mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 18:07:31 +09:00
Sync libwebp sources with https://chromium.googlesource.com/webm/libwebp/+/v1.0.0
This commit is contained in:
parent
96f65ed0eb
commit
57e9b57974
86 changed files with 3796 additions and 2250 deletions
|
|
@ -35,4 +35,5 @@ Contributors:
|
||||||
- Urvang Joshi (urvang at google dot com)
|
- Urvang Joshi (urvang at google dot com)
|
||||||
- Vikas Arora (vikasa at google dot com)
|
- Vikas Arora (vikasa at google dot com)
|
||||||
- Vincent Rabaud (vrabaud at google dot com)
|
- Vincent Rabaud (vrabaud at google dot com)
|
||||||
|
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
|
||||||
- Yang Zhang (yang dot zhang at arm dot com)
|
- Yang Zhang (yang dot zhang at arm dot com)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,26 @@
|
||||||
|
- 4/2/2018: version 1.0.0
|
||||||
|
This is a binary compatible release.
|
||||||
|
* lossy encoder improvements to avoid chroma shifts in various circumstances
|
||||||
|
(issues #308, #340)
|
||||||
|
* big-endian fixes for decode, RGBA import and WebPPictureDistortion
|
||||||
|
Tool updates:
|
||||||
|
gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
|
||||||
|
web browsers, transcoding tools (issue #379)
|
||||||
|
img2webp, webpmux - allow options to be passed in via a file (issue #355)
|
||||||
|
|
||||||
|
- 11/24/2017: version 0.6.1
|
||||||
|
This is a binary compatible release.
|
||||||
|
* lossless performance and compression improvements + a new 'cruncher' mode
|
||||||
|
(-m 6 -q 100)
|
||||||
|
* ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
|
||||||
|
* webp-js: emscripten/webassembly based javascript decoder
|
||||||
|
* miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
|
||||||
|
#363)
|
||||||
|
Tool updates / additions:
|
||||||
|
added webpinfo - prints file format information (issue #330)
|
||||||
|
gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
|
||||||
|
'-loop_compatibility' can be used for the old behavior
|
||||||
|
|
||||||
- 1/26/2017: version 0.6.0
|
- 1/26/2017: version 0.6.0
|
||||||
* lossless performance and compression improvements
|
* lossless performance and compression improvements
|
||||||
* miscellaneous performance improvements (SSE2, NEON, MSA)
|
* miscellaneous performance improvements (SSE2, NEON, MSA)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
\__\__/\____/\_____/__/ ____ ___
|
\__\__/\____/\_____/__/ ____ ___
|
||||||
/ _/ / \ \ / _ \/ _/
|
/ _/ / \ \ / _ \/ _/
|
||||||
/ \_/ / / \ \ __/ \__
|
/ \_/ / / \ \ __/ \__
|
||||||
\____/____/\_____/_____/____/v0.6.0
|
\____/____/\_____/_____/____/v1.0.0
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
============
|
============
|
||||||
|
|
@ -113,8 +113,8 @@ make install
|
||||||
|
|
||||||
CMake:
|
CMake:
|
||||||
------
|
------
|
||||||
The support for CMake is minimal: it only helps you compile libwebp, cwebp and
|
With CMake, you can compile libwebp, cwebp, dwebp, gif2web, img2webp, webpinfo
|
||||||
dwebp.
|
and the JS bindings.
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
A compiler (e.g., gcc with autotools) and CMake.
|
A compiler (e.g., gcc with autotools) and CMake.
|
||||||
|
|
@ -123,18 +123,25 @@ minimal build:
|
||||||
$ sudo apt-get install build-essential cmake
|
$ sudo apt-get install build-essential cmake
|
||||||
|
|
||||||
When building from git sources, you will need to run cmake to generate the
|
When building from git sources, you will need to run cmake to generate the
|
||||||
configure script.
|
makefiles.
|
||||||
|
|
||||||
mkdir build && cd build && cmake ../
|
mkdir build && cd build && cmake ../
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
||||||
If you also want cwebp or dwebp, you will need to enable them through CMake:
|
If you also want any of the executables, you will need to enable them through
|
||||||
|
CMake, e.g.:
|
||||||
|
|
||||||
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
|
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
|
||||||
|
|
||||||
or through your favorite interface (like ccmake or cmake-qt-gui).
|
or through your favorite interface (like ccmake or cmake-qt-gui).
|
||||||
|
|
||||||
|
Finally, once installed, you can also use WebP in your CMake project by doing:
|
||||||
|
|
||||||
|
find_package(WebP)
|
||||||
|
|
||||||
|
which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
|
||||||
|
|
||||||
Gradle:
|
Gradle:
|
||||||
-------
|
-------
|
||||||
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
|
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
|
||||||
|
|
@ -360,6 +367,23 @@ Use following options to convert into alternate image formats:
|
||||||
-quiet ....... quiet mode, don't print anything
|
-quiet ....... quiet mode, don't print anything
|
||||||
-noasm ....... disable all assembly optimizations
|
-noasm ....... disable all assembly optimizations
|
||||||
|
|
||||||
|
WebP file analysis tool:
|
||||||
|
========================
|
||||||
|
|
||||||
|
'webpinfo' can be used to print out the chunk level structure and bitstream
|
||||||
|
header information of WebP files. It can also check if the files are of valid
|
||||||
|
WebP format.
|
||||||
|
|
||||||
|
Usage: webpinfo [options] in_files
|
||||||
|
Note: there could be multiple input files;
|
||||||
|
options must come before input files.
|
||||||
|
Options:
|
||||||
|
-version ........... Print version number and exit.
|
||||||
|
-quiet ............. Do not show chunk parsing information.
|
||||||
|
-diag .............. Show parsing error diagnosis.
|
||||||
|
-summary ........... Show chunk stats summary.
|
||||||
|
-bitstream_info .... Parse bitstream header.
|
||||||
|
|
||||||
Visualization tool:
|
Visualization tool:
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
@ -434,6 +458,7 @@ File-level options (only used at the start of compression):
|
||||||
-mixed ............... use mixed lossy/lossless automatic mode
|
-mixed ............... use mixed lossy/lossless automatic mode
|
||||||
-v ................... verbose mode
|
-v ................... verbose mode
|
||||||
-h ................... this help
|
-h ................... this help
|
||||||
|
-version ............. print version number and exit
|
||||||
|
|
||||||
Per-frame options (only used for subsequent images input):
|
Per-frame options (only used for subsequent images input):
|
||||||
-d <int> ............. frame duration in ms (default: 100)
|
-d <int> ............. frame duration in ms (default: 100)
|
||||||
|
|
@ -470,6 +495,8 @@ Options:
|
||||||
-metadata <string> ..... comma separated list of metadata to
|
-metadata <string> ..... comma separated list of metadata to
|
||||||
copy from the input to the output if present
|
copy from the input to the output if present
|
||||||
Valid values: all, none, icc, xmp (default)
|
Valid values: all, none, icc, xmp (default)
|
||||||
|
-loop_compatibility .... use compatibility mode for Chrome
|
||||||
|
version prior to M62 (inclusive)
|
||||||
-mt .................... use multi-threading if available
|
-mt .................... use multi-threading if available
|
||||||
|
|
||||||
-version ............... print version number and exit
|
-version ............... print version number and exit
|
||||||
|
|
@ -498,6 +525,11 @@ Options:
|
||||||
-min_psnr <float> ... minimum per-frame PSNR
|
-min_psnr <float> ... minimum per-frame PSNR
|
||||||
-raw_comparison ..... if this flag is not used, RGB is
|
-raw_comparison ..... if this flag is not used, RGB is
|
||||||
premultiplied before comparison
|
premultiplied before comparison
|
||||||
|
-max_diff <int> ..... maximum allowed difference per channel
|
||||||
|
between corresponding pixels in subsequent
|
||||||
|
frames
|
||||||
|
-h .................. this help
|
||||||
|
-version ............ print version number and exit
|
||||||
|
|
||||||
Building:
|
Building:
|
||||||
---------
|
---------
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
__ __ ____ ____ ____ __ __ _ __ __
|
__ __ ____ ____ ____ __ __ _ __ __
|
||||||
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
|
||||||
\ / __/ _ \ __/ / / (_/ /__
|
\ / __/ _ \ __/ / / (_/ /__
|
||||||
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.4.0
|
\__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.0
|
||||||
|
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
|
|
@ -33,6 +33,7 @@ Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
|
||||||
webpmux -info INPUT
|
webpmux -info INPUT
|
||||||
webpmux [-h|-help]
|
webpmux [-h|-help]
|
||||||
webpmux -version
|
webpmux -version
|
||||||
|
webpmux argument_file_name
|
||||||
|
|
||||||
GET_OPTIONS:
|
GET_OPTIONS:
|
||||||
Extract relevant data:
|
Extract relevant data:
|
||||||
|
|
@ -92,6 +93,9 @@ INPUT & OUTPUT are in WebP format.
|
||||||
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
|
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
|
||||||
valid.
|
valid.
|
||||||
|
|
||||||
|
Note: if a single file name is passed as the argument, the arguments will be
|
||||||
|
tokenized from this file. The file name must not start with the character '-'.
|
||||||
|
|
||||||
Visualization tool:
|
Visualization tool:
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "./alphai_dec.h"
|
#include "../dec/alphai_dec.h"
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../utils/quant_levels_dec_utils.h"
|
#include "../utils/quant_levels_dec_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@
|
||||||
//
|
//
|
||||||
// Author: Urvang (urvang@google.com)
|
// Author: Urvang (urvang@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_DEC_ALPHAI_H_
|
#ifndef WEBP_DEC_ALPHAI_DEC_H_
|
||||||
#define WEBP_DEC_ALPHAI_H_
|
#define WEBP_DEC_ALPHAI_DEC_H_
|
||||||
|
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../utils/filters_utils.h"
|
#include "../utils/filters_utils.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_DEC_ALPHAI_H_ */
|
#endif /* WEBP_DEC_ALPHAI_DEC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// WebPDecBuffer
|
// WebPDecBuffer
|
||||||
|
|
||||||
// Number of bytes per pixel for the different color-spaces.
|
// Number of bytes per pixel for the different color-spaces.
|
||||||
static const int kModeBpp[MODE_LAST] = {
|
static const uint8_t kModeBpp[MODE_LAST] = {
|
||||||
3, 4, 3, 4, 4, 2, 2,
|
3, 4, 3, 4, 4, 2, 2,
|
||||||
4, 4, 4, 2, // pre-multiplied modes
|
4, 4, 4, 2, // pre-multiplied modes
|
||||||
1, 1 };
|
1, 1 };
|
||||||
|
|
@ -36,7 +36,7 @@ static int IsValidColorspace(int webp_csp_mode) {
|
||||||
// strictly speaking, the very last (or first, if flipped) row
|
// strictly speaking, the very last (or first, if flipped) row
|
||||||
// doesn't require padding.
|
// doesn't require padding.
|
||||||
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
|
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
|
||||||
(uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
|
((uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH))
|
||||||
|
|
||||||
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
|
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
@ -98,9 +98,14 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||||
uint64_t uv_size = 0, a_size = 0, total_size;
|
uint64_t uv_size = 0, a_size = 0, total_size;
|
||||||
// We need memory and it hasn't been allocated yet.
|
// We need memory and it hasn't been allocated yet.
|
||||||
// => initialize output buffer, now that dimensions are known.
|
// => initialize output buffer, now that dimensions are known.
|
||||||
const int stride = w * kModeBpp[mode];
|
int stride;
|
||||||
const uint64_t size = (uint64_t)stride * h;
|
uint64_t size;
|
||||||
|
|
||||||
|
if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
|
||||||
|
return VP8_STATUS_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
stride = w * kModeBpp[mode];
|
||||||
|
size = (uint64_t)stride * h;
|
||||||
if (!WebPIsRGBMode(mode)) {
|
if (!WebPIsRGBMode(mode)) {
|
||||||
uv_stride = (w + 1) / 2;
|
uv_stride = (w + 1) / 2;
|
||||||
uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
|
uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
|
||||||
|
|
@ -169,11 +174,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
|
||||||
return VP8_STATUS_OK;
|
return VP8_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
VP8StatusCode WebPAllocateDecBuffer(int w, int h,
|
VP8StatusCode WebPAllocateDecBuffer(int width, int height,
|
||||||
const WebPDecoderOptions* const options,
|
const WebPDecoderOptions* const options,
|
||||||
WebPDecBuffer* const out) {
|
WebPDecBuffer* const buffer) {
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
if (out == NULL || w <= 0 || h <= 0) {
|
if (buffer == NULL || width <= 0 || height <= 0) {
|
||||||
return VP8_STATUS_INVALID_PARAM;
|
return VP8_STATUS_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
if (options != NULL) { // First, apply options if there is any.
|
if (options != NULL) { // First, apply options if there is any.
|
||||||
|
|
@ -182,33 +187,39 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
|
||||||
const int ch = options->crop_height;
|
const int ch = options->crop_height;
|
||||||
const int x = options->crop_left & ~1;
|
const int x = options->crop_left & ~1;
|
||||||
const int y = options->crop_top & ~1;
|
const int y = options->crop_top & ~1;
|
||||||
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
|
if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
|
||||||
|
x + cw > width || y + ch > height) {
|
||||||
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
|
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
|
||||||
}
|
}
|
||||||
w = cw;
|
width = cw;
|
||||||
h = ch;
|
height = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->use_scaling) {
|
if (options->use_scaling) {
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
int scaled_width = options->scaled_width;
|
int scaled_width = options->scaled_width;
|
||||||
int scaled_height = options->scaled_height;
|
int scaled_height = options->scaled_height;
|
||||||
if (!WebPRescalerGetScaledDimensions(
|
if (!WebPRescalerGetScaledDimensions(
|
||||||
w, h, &scaled_width, &scaled_height)) {
|
width, height, &scaled_width, &scaled_height)) {
|
||||||
return VP8_STATUS_INVALID_PARAM;
|
return VP8_STATUS_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
w = scaled_width;
|
width = scaled_width;
|
||||||
h = scaled_height;
|
height = scaled_height;
|
||||||
|
#else
|
||||||
|
return VP8_STATUS_INVALID_PARAM; // rescaling not supported
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out->width = w;
|
buffer->width = width;
|
||||||
out->height = h;
|
buffer->height = height;
|
||||||
|
|
||||||
// Then, allocate buffer for real.
|
// Then, allocate buffer for real.
|
||||||
status = AllocateBuffer(out);
|
status = AllocateBuffer(buffer);
|
||||||
if (status != VP8_STATUS_OK) return status;
|
if (status != VP8_STATUS_OK) return status;
|
||||||
|
|
||||||
// Use the stride trick if vertical flip is needed.
|
// Use the stride trick if vertical flip is needed.
|
||||||
if (options != NULL && options->flip) {
|
if (options != NULL && options->flip) {
|
||||||
status = WebPFlipBuffer(out);
|
status = WebPFlipBuffer(buffer);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_DEC_COMMON_H_
|
#ifndef WEBP_DEC_COMMON_DEC_H_
|
||||||
#define WEBP_DEC_COMMON_H_
|
#define WEBP_DEC_COMMON_DEC_H_
|
||||||
|
|
||||||
// intra prediction modes
|
// intra prediction modes
|
||||||
enum { B_DC_PRED = 0, // 4x4 modes
|
enum { B_DC_PRED = 0, // 4x4 modes
|
||||||
|
|
@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3,
|
||||||
NUM_PROBAS = 11
|
NUM_PROBAS = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WEBP_DEC_COMMON_H_
|
#endif // WEBP_DEC_COMMON_DEC_H_
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Main reconstruction function.
|
// Main reconstruction function.
|
||||||
|
|
||||||
static const int kScan[16] = {
|
static const uint16_t kScan[16] = {
|
||||||
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
|
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
|
||||||
0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
|
0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
|
||||||
0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
|
0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
|
||||||
|
|
@ -320,7 +320,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
|
||||||
#define MIN_DITHER_AMP 4
|
#define MIN_DITHER_AMP 4
|
||||||
|
|
||||||
#define DITHER_AMP_TAB_SIZE 12
|
#define DITHER_AMP_TAB_SIZE 12
|
||||||
static const int kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
|
static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
|
||||||
// roughly, it's dqm->uv_mat_[1]
|
// roughly, it's dqm->uv_mat_[1]
|
||||||
8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
|
8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
|
||||||
};
|
};
|
||||||
|
|
@ -400,7 +400,9 @@ static void DitherRow(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.
|
||||||
static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
|
static int FinishRow(void* arg1, void* arg2) {
|
||||||
|
VP8Decoder* const dec = (VP8Decoder*)arg1;
|
||||||
|
VP8Io* const io = (VP8Io*)arg2;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
|
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
|
||||||
const int cache_id = ctx->id_;
|
const int cache_id = ctx->id_;
|
||||||
|
|
@ -448,10 +450,9 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
|
||||||
if (y_end > io->crop_bottom) {
|
if (y_end > io->crop_bottom) {
|
||||||
y_end = io->crop_bottom; // make sure we don't overflow on last row.
|
y_end = io->crop_bottom; // make sure we don't overflow on last row.
|
||||||
}
|
}
|
||||||
|
// If dec->alpha_data_ is not NULL, we have some alpha plane present.
|
||||||
io->a = NULL;
|
io->a = NULL;
|
||||||
if (dec->alpha_data_ != NULL && y_start < y_end) {
|
if (dec->alpha_data_ != NULL && y_start < y_end) {
|
||||||
// TODO(skal): testing presence of alpha with dec->alpha_data_ is not a
|
|
||||||
// good idea.
|
|
||||||
io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
|
io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
|
||||||
if (io->a == NULL) {
|
if (io->a == NULL) {
|
||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
|
|
@ -558,7 +559,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
|
||||||
if (io->bypass_filtering) {
|
if (io->bypass_filtering) {
|
||||||
dec->filter_type_ = 0;
|
dec->filter_type_ = 0;
|
||||||
}
|
}
|
||||||
// TODO(skal): filter type / strength / sharpness forcing
|
|
||||||
|
|
||||||
// Define the area where we can skip in-loop filtering, in case of cropping.
|
// Define the area where we can skip in-loop filtering, in case of cropping.
|
||||||
//
|
//
|
||||||
|
|
@ -569,8 +569,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
|
||||||
// Means: there's a dependency chain that goes all the way up to the
|
// Means: there's a dependency chain that goes all the way up to the
|
||||||
// top-left corner of the picture (MB #0). We must filter all the previous
|
// top-left corner of the picture (MB #0). We must filter all the previous
|
||||||
// macroblocks.
|
// macroblocks.
|
||||||
// TODO(skal): add an 'approximate_decoding' option, that won't produce
|
|
||||||
// a 1:1 bit-exactness for complex filtering?
|
|
||||||
{
|
{
|
||||||
const int extra_pixels = kFilterExtraRows[dec->filter_type_];
|
const int extra_pixels = kFilterExtraRows[dec->filter_type_];
|
||||||
if (dec->filter_type_ == 2) {
|
if (dec->filter_type_ == 2) {
|
||||||
|
|
@ -651,7 +649,7 @@ static int InitThreadContext(VP8Decoder* const dec) {
|
||||||
}
|
}
|
||||||
worker->data1 = dec;
|
worker->data1 = dec;
|
||||||
worker->data2 = (void*)&dec->thread_ctx_.io_;
|
worker->data2 = (void*)&dec->thread_ctx_.io_;
|
||||||
worker->hook = (WebPWorkerHook)FinishRow;
|
worker->hook = FinishRow;
|
||||||
dec->num_caches_ =
|
dec->num_caches_ =
|
||||||
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
|
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -728,7 +726,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem = (uint8_t*)dec->mem_;
|
mem = (uint8_t*)dec->mem_;
|
||||||
dec->intra_t_ = (uint8_t*)mem;
|
dec->intra_t_ = mem;
|
||||||
mem += intra_pred_mode_size;
|
mem += intra_pred_mode_size;
|
||||||
|
|
||||||
dec->yuv_t_ = (VP8TopSamples*)mem;
|
dec->yuv_t_ = (VP8TopSamples*)mem;
|
||||||
|
|
@ -750,7 +748,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
||||||
|
|
||||||
mem = (uint8_t*)WEBP_ALIGN(mem);
|
mem = (uint8_t*)WEBP_ALIGN(mem);
|
||||||
assert((yuv_size & WEBP_ALIGN_CST) == 0);
|
assert((yuv_size & WEBP_ALIGN_CST) == 0);
|
||||||
dec->yuv_b_ = (uint8_t*)mem;
|
dec->yuv_b_ = mem;
|
||||||
mem += yuv_size;
|
mem += yuv_size;
|
||||||
|
|
||||||
dec->mb_data_ = (VP8MBData*)mem;
|
dec->mb_data_ = (VP8MBData*)mem;
|
||||||
|
|
@ -766,7 +764,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
||||||
const int extra_rows = kFilterExtraRows[dec->filter_type_];
|
const int extra_rows = kFilterExtraRows[dec->filter_type_];
|
||||||
const int extra_y = extra_rows * dec->cache_y_stride_;
|
const int extra_y = extra_rows * dec->cache_y_stride_;
|
||||||
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
|
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
|
||||||
dec->cache_y_ = ((uint8_t*)mem) + extra_y;
|
dec->cache_y_ = mem + extra_y;
|
||||||
dec->cache_u_ = dec->cache_y_
|
dec->cache_u_ = dec->cache_y_
|
||||||
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
|
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
|
||||||
dec->cache_v_ = dec->cache_u_
|
dec->cache_v_ = dec->cache_u_
|
||||||
|
|
@ -776,7 +774,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
|
||||||
mem += cache_size;
|
mem += cache_size;
|
||||||
|
|
||||||
// alpha plane
|
// alpha plane
|
||||||
dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
|
dec->alpha_plane_ = alpha_size ? mem : NULL;
|
||||||
mem += alpha_size;
|
mem += alpha_size;
|
||||||
assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
|
assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai_dec.h"
|
#include "../dec/alphai_dec.h"
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
// In append mode, buffer allocations increase as multiples of this value.
|
// In append mode, buffer allocations increase as multiples of this value.
|
||||||
|
|
@ -673,12 +673,12 @@ void WebPIDelete(WebPIDecoder* idec) {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Wrapper toward WebPINewDecoder
|
// Wrapper toward WebPINewDecoder
|
||||||
|
|
||||||
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
|
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
|
||||||
size_t output_buffer_size, int output_stride) {
|
size_t output_buffer_size, int output_stride) {
|
||||||
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
|
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
|
||||||
WebPIDecoder* idec;
|
WebPIDecoder* idec;
|
||||||
|
|
||||||
if (mode >= MODE_YUV) return NULL;
|
if (csp >= MODE_YUV) return NULL;
|
||||||
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
||||||
output_buffer_size = 0;
|
output_buffer_size = 0;
|
||||||
output_stride = 0;
|
output_stride = 0;
|
||||||
|
|
@ -689,7 +689,7 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
|
||||||
}
|
}
|
||||||
idec = WebPINewDecoder(NULL);
|
idec = WebPINewDecoder(NULL);
|
||||||
if (idec == NULL) return NULL;
|
if (idec == NULL) return NULL;
|
||||||
idec->output_.colorspace = mode;
|
idec->output_.colorspace = csp;
|
||||||
idec->output_.is_external_memory = is_external_memory;
|
idec->output_.is_external_memory = is_external_memory;
|
||||||
idec->output_.u.RGBA.rgba = output_buffer;
|
idec->output_.u.RGBA.rgba = output_buffer;
|
||||||
idec->output_.u.RGBA.stride = output_stride;
|
idec->output_.u.RGBA.stride = output_stride;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../dec/vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../dsp/yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
@ -212,7 +212,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
|
||||||
int num_rows;
|
int num_rows;
|
||||||
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
|
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
|
||||||
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
|
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
uint8_t* alpha_dst = base_rgba;
|
uint8_t* alpha_dst = base_rgba;
|
||||||
#else
|
#else
|
||||||
uint8_t* alpha_dst = base_rgba + 1;
|
uint8_t* alpha_dst = base_rgba + 1;
|
||||||
|
|
@ -241,6 +241,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// YUV rescaling (no final RGB conversion needed)
|
// YUV rescaling (no final RGB conversion needed)
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
static int Rescale(const uint8_t* src, int src_stride,
|
static int Rescale(const uint8_t* src, int src_stride,
|
||||||
int new_lines, WebPRescaler* const wrk) {
|
int new_lines, WebPRescaler* const wrk) {
|
||||||
int num_lines_out = 0;
|
int num_lines_out = 0;
|
||||||
|
|
@ -431,7 +432,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
|
||||||
int max_lines_out) {
|
int max_lines_out) {
|
||||||
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
|
||||||
uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
|
uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
uint8_t* alpha_dst = base_rgba;
|
uint8_t* alpha_dst = base_rgba;
|
||||||
#else
|
#else
|
||||||
uint8_t* alpha_dst = base_rgba + 1;
|
uint8_t* alpha_dst = base_rgba + 1;
|
||||||
|
|
@ -541,6 +542,8 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_REDUCE_SIZE
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Default custom functions
|
// Default custom functions
|
||||||
|
|
||||||
|
|
@ -561,10 +564,14 @@ static int CustomSetup(VP8Io* io) {
|
||||||
WebPInitUpsamplers();
|
WebPInitUpsamplers();
|
||||||
}
|
}
|
||||||
if (io->use_scaling) {
|
if (io->use_scaling) {
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
|
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return 0; // memory error
|
return 0; // memory error
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
return 0; // rescaling support not compiled
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (is_rgb) {
|
if (is_rgb) {
|
||||||
WebPInitSamplers();
|
WebPInitSamplers();
|
||||||
|
|
@ -598,9 +605,6 @@ static int CustomSetup(VP8Io* io) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_rgb) {
|
|
||||||
VP8YUVInit();
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
|
|
||||||
static WEBP_INLINE int clip(int v, int M) {
|
static WEBP_INLINE int clip(int v, int M) {
|
||||||
return v < 0 ? 0 : v > M ? M : v;
|
return v < 0 ? 0 : v > M ? M : v;
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,19 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/bit_reader_inl_utils.h"
|
#include "../utils/bit_reader_inl_utils.h"
|
||||||
|
|
||||||
|
#if !defined(USE_GENERIC_TREE)
|
||||||
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
|
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
|
||||||
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
|
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
|
||||||
#define USE_GENERIC_TREE
|
#define USE_GENERIC_TREE 1 // ALTERNATE_CODE
|
||||||
|
#else
|
||||||
|
#define USE_GENERIC_TREE 0
|
||||||
#endif
|
#endif
|
||||||
|
#endif // USE_GENERIC_TREE
|
||||||
|
|
||||||
#ifdef USE_GENERIC_TREE
|
#if (USE_GENERIC_TREE == 1)
|
||||||
static const int8_t kYModesIntra4[18] = {
|
static const int8_t kYModesIntra4[18] = {
|
||||||
-B_DC_PRED, 1,
|
-B_DC_PRED, 1,
|
||||||
-B_TM_PRED, 2,
|
-B_TM_PRED, 2,
|
||||||
|
|
@ -317,7 +321,7 @@ static void ParseIntraMode(VP8BitReader* const br,
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < 4; ++x) {
|
for (x = 0; x < 4; ++x) {
|
||||||
const uint8_t* const prob = kBModesProba[top[x]][ymode];
|
const uint8_t* const prob = kBModesProba[top[x]][ymode];
|
||||||
#ifdef USE_GENERIC_TREE
|
#if (USE_GENERIC_TREE == 1)
|
||||||
// Generic tree-parsing
|
// Generic tree-parsing
|
||||||
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
|
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
|
|
@ -335,7 +339,7 @@ static void ParseIntraMode(VP8BitReader* const br,
|
||||||
(!VP8GetBit(br, prob[6]) ? B_LD_PRED :
|
(!VP8GetBit(br, prob[6]) ? B_LD_PRED :
|
||||||
(!VP8GetBit(br, prob[7]) ? B_VL_PRED :
|
(!VP8GetBit(br, prob[7]) ? B_VL_PRED :
|
||||||
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
|
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
|
||||||
#endif // USE_GENERIC_TREE
|
#endif // USE_GENERIC_TREE
|
||||||
top[x] = ymode;
|
top[x] = ymode;
|
||||||
}
|
}
|
||||||
memcpy(modes, top, 4 * sizeof(*top));
|
memcpy(modes, top, 4 * sizeof(*top));
|
||||||
|
|
@ -498,7 +502,7 @@ static const uint8_t
|
||||||
|
|
||||||
// Paragraph 9.9
|
// Paragraph 9.9
|
||||||
|
|
||||||
static const int kBands[16 + 1] = {
|
static const uint8_t kBands[16 + 1] = {
|
||||||
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
||||||
0 // extra entry as sentinel
|
0 // extra entry as sentinel
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai_dec.h"
|
#include "../dec/alphai_dec.h"
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../utils/bit_reader_inl_utils.h"
|
#include "../utils/bit_reader_inl_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
|
|
@ -491,7 +491,7 @@ static int GetCoeffsAlt(VP8BitReader* const br,
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) {
|
static WEBP_TSAN_IGNORE_FUNCTION void InitGetCoeffs(void) {
|
||||||
if (GetCoeffs == NULL) {
|
if (GetCoeffs == NULL) {
|
||||||
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
|
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
|
||||||
GetCoeffs = GetCoeffsAlt;
|
GetCoeffs = GetCoeffsAlt;
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_WEBP_DECODE_VP8_H_
|
#ifndef WEBP_DEC_VP8_DEC_H_
|
||||||
#define WEBP_WEBP_DECODE_VP8_H_
|
#define WEBP_DEC_VP8_DEC_H_
|
||||||
|
|
||||||
#include "../webp/decode.h"
|
#include "../webp/decode.h"
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ extern "C" {
|
||||||
// /* customize io's functions (setup()/put()/teardown()) if needed. */
|
// /* customize io's functions (setup()/put()/teardown()) if needed. */
|
||||||
//
|
//
|
||||||
// VP8Decoder* dec = VP8New();
|
// VP8Decoder* dec = VP8New();
|
||||||
// bool ok = VP8Decode(dec);
|
// int ok = VP8Decode(dec, &io);
|
||||||
// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
|
// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
|
||||||
// VP8Delete(dec);
|
// VP8Delete(dec);
|
||||||
// return ok;
|
// return ok;
|
||||||
|
|
@ -157,24 +157,24 @@ void VP8Delete(VP8Decoder* const dec);
|
||||||
// Miscellaneous VP8/VP8L bitstream probing functions.
|
// Miscellaneous VP8/VP8L bitstream probing functions.
|
||||||
|
|
||||||
// Returns true if the next 3 bytes in data contain the VP8 signature.
|
// Returns true if the next 3 bytes in data contain the VP8 signature.
|
||||||
WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
|
WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size);
|
||||||
|
|
||||||
// Validates the VP8 data-header and retrieves basic header information viz
|
// Validates the VP8 data-header and retrieves basic header information viz
|
||||||
// width and height. Returns 0 in case of formatting error. *width/*height
|
// width and height. Returns 0 in case of formatting error. *width/*height
|
||||||
// can be passed NULL.
|
// can be passed NULL.
|
||||||
WEBP_EXTERN(int) VP8GetInfo(
|
WEBP_EXTERN int VP8GetInfo(
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
size_t data_size, // data available so far
|
size_t data_size, // data available so far
|
||||||
size_t chunk_size, // total data size expected in the chunk
|
size_t chunk_size, // total data size expected in the chunk
|
||||||
int* const width, int* const height);
|
int* const width, int* const height);
|
||||||
|
|
||||||
// Returns true if the next byte(s) in data is a VP8L signature.
|
// Returns true if the next byte(s) in data is a VP8L signature.
|
||||||
WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
|
WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size);
|
||||||
|
|
||||||
// Validates the VP8L data-header and retrieves basic header information viz
|
// Validates the VP8L data-header and retrieves basic header information viz
|
||||||
// width, height and alpha. Returns 0 in case of formatting error.
|
// width, height and alpha. Returns 0 in case of formatting error.
|
||||||
// width/height/has_alpha can be passed NULL.
|
// width/height/has_alpha can be passed NULL.
|
||||||
WEBP_EXTERN(int) VP8LGetInfo(
|
WEBP_EXTERN int VP8LGetInfo(
|
||||||
const uint8_t* data, size_t data_size, // data available so far
|
const uint8_t* data, size_t data_size, // data available so far
|
||||||
int* const width, int* const height, int* const has_alpha);
|
int* const width, int* const height, int* const has_alpha);
|
||||||
|
|
||||||
|
|
@ -182,4 +182,4 @@ WEBP_EXTERN(int) VP8LGetInfo(
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_WEBP_DECODE_VP8_H_ */
|
#endif /* WEBP_DEC_VP8_DEC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_DEC_VP8I_H_
|
#ifndef WEBP_DEC_VP8I_DEC_H_
|
||||||
#define WEBP_DEC_VP8I_H_
|
#define WEBP_DEC_VP8I_DEC_H_
|
||||||
|
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include "./common_dec.h"
|
#include "../dec/common_dec.h"
|
||||||
#include "./vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "../utils/bit_reader_utils.h"
|
#include "../utils/bit_reader_utils.h"
|
||||||
#include "../utils/random_utils.h"
|
#include "../utils/random_utils.h"
|
||||||
#include "../utils/thread_utils.h"
|
#include "../utils/thread_utils.h"
|
||||||
|
|
@ -30,8 +30,8 @@ extern "C" {
|
||||||
// Various defines and enums
|
// Various defines and enums
|
||||||
|
|
||||||
// version numbers
|
// version numbers
|
||||||
#define DEC_MAJ_VERSION 0
|
#define DEC_MAJ_VERSION 1
|
||||||
#define DEC_MIN_VERSION 6
|
#define DEC_MIN_VERSION 0
|
||||||
#define DEC_REV_VERSION 0
|
#define DEC_REV_VERSION 0
|
||||||
|
|
||||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||||
|
|
@ -57,7 +57,6 @@ extern "C" {
|
||||||
// '|' = left sample, '-' = top sample, '+' = top-left sample
|
// '|' = left sample, '-' = top sample, '+' = top-left sample
|
||||||
// 't' = extra top-right sample for 4x4 modes
|
// 't' = extra top-right sample for 4x4 modes
|
||||||
#define YUV_SIZE (BPS * 17 + BPS * 9)
|
#define YUV_SIZE (BPS * 17 + BPS * 9)
|
||||||
#define Y_SIZE (BPS * 17)
|
|
||||||
#define Y_OFF (BPS * 1 + 8)
|
#define Y_OFF (BPS * 1 + 8)
|
||||||
#define U_OFF (Y_OFF + BPS * 16 + BPS)
|
#define U_OFF (Y_OFF + BPS * 16 + BPS)
|
||||||
#define V_OFF (U_OFF + 16)
|
#define V_OFF (U_OFF + 16)
|
||||||
|
|
@ -317,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_DEC_VP8I_H_ */
|
#endif /* WEBP_DEC_VP8I_DEC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./alphai_dec.h"
|
#include "../dec/alphai_dec.h"
|
||||||
#include "./vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../dsp/lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
#include "../dsp/lossless_common.h"
|
#include "../dsp/lossless_common.h"
|
||||||
|
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
static const int kCodeLengthLiterals = 16;
|
static const int kCodeLengthLiterals = 16;
|
||||||
static const int kCodeLengthRepeatCode = 16;
|
static const int kCodeLengthRepeatCode = 16;
|
||||||
static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
|
static const uint8_t kCodeLengthExtraBits[3] = { 2, 3, 7 };
|
||||||
static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
|
static const uint8_t kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Five Huffman codes are used at each meta code:
|
// Five Huffman codes are used at each meta code:
|
||||||
|
|
@ -86,7 +86,7 @@ static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
|
||||||
// All values computed for 8-bit first level lookup with Mark Adler's tool:
|
// All values computed for 8-bit first level lookup with Mark Adler's tool:
|
||||||
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
|
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
|
||||||
#define FIXED_TABLE_SIZE (630 * 3 + 410)
|
#define FIXED_TABLE_SIZE (630 * 3 + 410)
|
||||||
static const int kTableSize[12] = {
|
static const uint16_t kTableSize[12] = {
|
||||||
FIXED_TABLE_SIZE + 654,
|
FIXED_TABLE_SIZE + 654,
|
||||||
FIXED_TABLE_SIZE + 656,
|
FIXED_TABLE_SIZE + 656,
|
||||||
FIXED_TABLE_SIZE + 658,
|
FIXED_TABLE_SIZE + 658,
|
||||||
|
|
@ -485,6 +485,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Scaling.
|
// Scaling.
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
||||||
const int num_channels = 4;
|
const int num_channels = 4;
|
||||||
const int in_width = io->mb_w;
|
const int in_width = io->mb_w;
|
||||||
|
|
@ -516,10 +517,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
||||||
out_width, out_height, 0, num_channels, work);
|
out_width, out_height, 0, num_channels, work);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif // WEBP_REDUCE_SIZE
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Export to ARGB
|
// Export to ARGB
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
|
|
||||||
// We have special "export" function since we need to convert from BGRA
|
// We have special "export" function since we need to convert from BGRA
|
||||||
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
|
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
|
||||||
int rgba_stride, uint8_t* const rgba) {
|
int rgba_stride, uint8_t* const rgba) {
|
||||||
|
|
@ -561,6 +565,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
|
||||||
return num_lines_out;
|
return num_lines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_REDUCE_SIZE
|
||||||
|
|
||||||
// Emit rows without any scaling.
|
// Emit rows without any scaling.
|
||||||
static int EmitRows(WEBP_CSP_MODE colorspace,
|
static int EmitRows(WEBP_CSP_MODE colorspace,
|
||||||
const uint8_t* row_in, int in_stride,
|
const uint8_t* row_in, int in_stride,
|
||||||
|
|
@ -746,9 +752,12 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
|
||||||
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
|
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
|
||||||
const WebPRGBABuffer* const buf = &output->u.RGBA;
|
const WebPRGBABuffer* const buf = &output->u.RGBA;
|
||||||
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
|
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
|
||||||
const int num_rows_out = io->use_scaling ?
|
const int num_rows_out =
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
|
io->use_scaling ?
|
||||||
EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
|
EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
|
||||||
rgba, buf->stride) :
|
rgba, buf->stride) :
|
||||||
|
#endif // WEBP_REDUCE_SIZE
|
||||||
EmitRows(output->colorspace, rows_data, in_stride,
|
EmitRows(output->colorspace, rows_data, in_stride,
|
||||||
io->mb_w, io->mb_h, rgba, buf->stride);
|
io->mb_w, io->mb_h, rgba, buf->stride);
|
||||||
// Update 'last_out_row_'.
|
// Update 'last_out_row_'.
|
||||||
|
|
@ -1012,12 +1021,13 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
||||||
ok = 0;
|
ok = 0;
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
assert(br->eos_ == VP8LIsEndOfStream(br));
|
br->eos_ = VP8LIsEndOfStream(br);
|
||||||
}
|
}
|
||||||
// Process the remaining rows corresponding to last row-block.
|
// Process the remaining rows corresponding to last row-block.
|
||||||
ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
|
ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
|
||||||
|
|
||||||
End:
|
End:
|
||||||
|
br->eos_ = VP8LIsEndOfStream(br);
|
||||||
if (!ok || (br->eos_ && pos < end)) {
|
if (!ok || (br->eos_ && pos < end)) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
|
dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
|
||||||
|
|
@ -1090,11 +1100,12 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||||
VP8LFillBitWindow(br);
|
VP8LFillBitWindow(br);
|
||||||
if (htree_group->use_packed_table) {
|
if (htree_group->use_packed_table) {
|
||||||
code = ReadPackedSymbols(htree_group, br, src);
|
code = ReadPackedSymbols(htree_group, br, src);
|
||||||
|
if (VP8LIsEndOfStream(br)) break;
|
||||||
if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
|
if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
|
||||||
} else {
|
} else {
|
||||||
code = ReadSymbol(htree_group->htrees[GREEN], br);
|
code = ReadSymbol(htree_group->htrees[GREEN], br);
|
||||||
}
|
}
|
||||||
if (br->eos_) break; // early out
|
if (VP8LIsEndOfStream(br)) break;
|
||||||
if (code < NUM_LITERAL_CODES) { // Literal
|
if (code < NUM_LITERAL_CODES) { // Literal
|
||||||
if (htree_group->is_trivial_literal) {
|
if (htree_group->is_trivial_literal) {
|
||||||
*src = htree_group->literal_arb | (code << 8);
|
*src = htree_group->literal_arb | (code << 8);
|
||||||
|
|
@ -1104,7 +1115,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||||
VP8LFillBitWindow(br);
|
VP8LFillBitWindow(br);
|
||||||
blue = ReadSymbol(htree_group->htrees[BLUE], br);
|
blue = ReadSymbol(htree_group->htrees[BLUE], br);
|
||||||
alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
|
alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
|
||||||
if (br->eos_) break;
|
if (VP8LIsEndOfStream(br)) break;
|
||||||
*src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
|
*src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
|
||||||
}
|
}
|
||||||
AdvanceByOne:
|
AdvanceByOne:
|
||||||
|
|
@ -1132,7 +1143,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||||
VP8LFillBitWindow(br);
|
VP8LFillBitWindow(br);
|
||||||
dist_code = GetCopyDistance(dist_symbol, br);
|
dist_code = GetCopyDistance(dist_symbol, br);
|
||||||
dist = PlaneCodeToDistance(width, dist_code);
|
dist = PlaneCodeToDistance(width, dist_code);
|
||||||
if (br->eos_) break;
|
if (VP8LIsEndOfStream(br)) break;
|
||||||
if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
|
if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
|
||||||
goto Error;
|
goto Error;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1169,9 +1180,9 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||||
} else { // Not reached
|
} else { // Not reached
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
assert(br->eos_ == VP8LIsEndOfStream(br));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
br->eos_ = VP8LIsEndOfStream(br);
|
||||||
if (dec->incremental_ && br->eos_ && src < src_end) {
|
if (dec->incremental_ && br->eos_ && src < src_end) {
|
||||||
RestoreState(dec);
|
RestoreState(dec);
|
||||||
} else if (!br->eos_) {
|
} else if (!br->eos_) {
|
||||||
|
|
@ -1630,12 +1641,19 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
|
||||||
|
|
||||||
if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
|
if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
|
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
|
||||||
|
#else
|
||||||
|
if (io->use_scaling) {
|
||||||
|
dec->status_ = VP8_STATUS_INVALID_PARAM;
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
|
if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
|
||||||
// need the alpha-multiply functions for premultiplied output or rescaling
|
// need the alpha-multiply functions for premultiplied output or rescaling
|
||||||
WebPInitAlphaProcessing();
|
WebPInitAlphaProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WebPIsRGBMode(dec->output_->colorspace)) {
|
if (!WebPIsRGBMode(dec->output_->colorspace)) {
|
||||||
WebPInitConvertARGBToYUV();
|
WebPInitConvertARGBToYUV();
|
||||||
if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
|
if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
// Vikas Arora(vikaas.arora@gmail.com)
|
// Vikas Arora(vikaas.arora@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_DEC_VP8LI_H_
|
#ifndef WEBP_DEC_VP8LI_DEC_H_
|
||||||
#define WEBP_DEC_VP8LI_H_
|
#define WEBP_DEC_VP8LI_DEC_H_
|
||||||
|
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../utils/bit_reader_utils.h"
|
#include "../utils/bit_reader_utils.h"
|
||||||
#include "../utils/color_cache_utils.h"
|
#include "../utils/color_cache_utils.h"
|
||||||
#include "../utils/huffman_utils.h"
|
#include "../utils/huffman_utils.h"
|
||||||
|
|
@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_DEC_VP8LI_H_ */
|
#endif /* WEBP_DEC_VP8LI_DEC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "./vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "./vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "./webpi_dec.h"
|
#include "../dec/webpi_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../webp/mux_types.h" // ALPHA_FLAG
|
#include "../webp/mux_types.h" // ALPHA_FLAG
|
||||||
|
|
||||||
|
|
@ -421,7 +421,9 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
|
||||||
NULL, NULL, NULL, &has_animation,
|
NULL, NULL, NULL, &has_animation,
|
||||||
NULL, headers);
|
NULL, headers);
|
||||||
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||||
// TODO(jzern): full support of animation frames will require API additions.
|
// The WebPDemux API + libwebp can be used to decode individual
|
||||||
|
// uncomposited frames or the WebPAnimDecoder can be used to fully
|
||||||
|
// reconstruct them (see webp/demux.h).
|
||||||
if (has_animation) {
|
if (has_animation) {
|
||||||
status = VP8_STATUS_UNSUPPORTED_FEATURE;
|
status = VP8_STATUS_UNSUPPORTED_FEATURE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@
|
||||||
//
|
//
|
||||||
// Author: somnath@google.com (Somnath Banerjee)
|
// Author: somnath@google.com (Somnath Banerjee)
|
||||||
|
|
||||||
#ifndef WEBP_DEC_WEBPI_H_
|
#ifndef WEBP_DEC_WEBPI_DEC_H_
|
||||||
#define WEBP_DEC_WEBPI_H_
|
#define WEBP_DEC_WEBPI_DEC_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../utils/rescaler_utils.h"
|
#include "../utils/rescaler_utils.h"
|
||||||
#include "./vp8_dec.h"
|
#include "../dec/vp8_dec.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// WebPDecParams: Decoding output parameters. Transient internal object.
|
// WebPDecParams: Decoding output parameters. Transient internal object.
|
||||||
|
|
@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_DEC_WEBPI_H_ */
|
#endif /* WEBP_DEC_WEBPI_DEC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
#include "../webp/demux.h"
|
#include "../webp/demux.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
||||||
#define DMUX_MAJ_VERSION 0
|
#define DMUX_MAJ_VERSION 1
|
||||||
#define DMUX_MIN_VERSION 3
|
#define DMUX_MIN_VERSION 0
|
||||||
#define DMUX_REV_VERSION 2
|
#define DMUX_REV_VERSION 0
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t start_; // start location of the data
|
size_t start_; // start location of the data
|
||||||
|
|
@ -205,12 +205,14 @@ static void SetFrameInfo(size_t start_offset, size_t size,
|
||||||
frame->complete_ = complete;
|
frame->complete_ = complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store image bearing chunks to 'frame'.
|
// Store image bearing chunks to 'frame'. 'min_size' is an optional size
|
||||||
|
// requirement, it may be zero.
|
||||||
static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
|
||||||
MemBuffer* const mem, Frame* const frame) {
|
MemBuffer* const mem, Frame* const frame) {
|
||||||
int alpha_chunks = 0;
|
int alpha_chunks = 0;
|
||||||
int image_chunks = 0;
|
int image_chunks = 0;
|
||||||
int done = (MemDataSize(mem) < min_size);
|
int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE ||
|
||||||
|
MemDataSize(mem) < min_size);
|
||||||
ParseStatus status = PARSE_OK;
|
ParseStatus status = PARSE_OK;
|
||||||
|
|
||||||
if (done) return PARSE_NEED_MORE_DATA;
|
if (done) return PARSE_NEED_MORE_DATA;
|
||||||
|
|
@ -401,9 +403,9 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
|
||||||
frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
|
frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
|
||||||
if (frame == NULL) return PARSE_ERROR;
|
if (frame == NULL) return PARSE_ERROR;
|
||||||
|
|
||||||
// For the single image case we allow parsing of a partial frame, but we need
|
// For the single image case we allow parsing of a partial frame, so no
|
||||||
// at least CHUNK_HEADER_SIZE for parsing.
|
// minimum size is imposed here.
|
||||||
status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
|
status = StoreFrame(1, 0, &dmux->mem_, frame);
|
||||||
if (status != PARSE_ERROR) {
|
if (status != PARSE_ERROR) {
|
||||||
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
|
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
|
||||||
// Clear any alpha when the alpha flag is missing.
|
// Clear any alpha when the alpha flag is missing.
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,13 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
// Tables can be faster on some platform but incur some extra binary size (~2k).
|
// Tables can be faster on some platform but incur some extra binary size (~2k).
|
||||||
// #define USE_TABLES_FOR_ALPHA_MULT
|
#if !defined(USE_TABLES_FOR_ALPHA_MULT)
|
||||||
|
#define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -29,7 +32,7 @@ static uint32_t Mult(uint8_t x, uint32_t mult) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TABLES_FOR_ALPHA_MULT
|
#if (USE_TABLES_FOR_ALPHA_MULT == 1)
|
||||||
|
|
||||||
static const uint32_t kMultTables[2][256] = {
|
static const uint32_t kMultTables[2][256] = {
|
||||||
{ // (255u << MFIX) / alpha
|
{ // (255u << MFIX) / alpha
|
||||||
|
|
@ -132,9 +135,9 @@ static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
|
||||||
return inverse ? (255u << MFIX) / a : a * KINV_255;
|
return inverse ? (255u << MFIX) / a : a * KINV_255;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_TABLES_FOR_ALPHA_MULT
|
#endif // USE_TABLES_FOR_ALPHA_MULT
|
||||||
|
|
||||||
void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
|
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
const uint32_t argb = ptr[x];
|
const uint32_t argb = ptr[x];
|
||||||
|
|
@ -154,8 +157,8 @@ void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
|
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
int width, int inverse) {
|
int width, int inverse) {
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
const uint32_t a = alpha[x];
|
const uint32_t a = alpha[x];
|
||||||
|
|
@ -217,8 +220,9 @@ void WebPMultRows(uint8_t* ptr, int stride,
|
||||||
#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
|
#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
int w, int h, int stride) {
|
static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first,
|
||||||
|
int w, int h, int stride) {
|
||||||
while (h-- > 0) {
|
while (h-- > 0) {
|
||||||
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
|
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
|
||||||
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
|
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
|
||||||
|
|
@ -235,6 +239,7 @@ static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
|
||||||
rgba += stride;
|
rgba += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
#undef MULTIPLIER
|
#undef MULTIPLIER
|
||||||
#undef PREMULTIPLY
|
#undef PREMULTIPLY
|
||||||
|
|
||||||
|
|
@ -254,9 +259,9 @@ static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
|
||||||
return (x * m) >> 16;
|
return (x * m) >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444,
|
||||||
int w, int h, int stride,
|
int w, int h, int stride,
|
||||||
int rg_byte_pos /* 0 or 1 */) {
|
int rg_byte_pos /* 0 or 1 */) {
|
||||||
while (h-- > 0) {
|
while (h-- > 0) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < w; ++i) {
|
for (i = 0; i < w; ++i) {
|
||||||
|
|
@ -275,15 +280,16 @@ static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
|
||||||
}
|
}
|
||||||
#undef MULTIPLIER
|
#undef MULTIPLIER
|
||||||
|
|
||||||
static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
|
static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
|
||||||
int w, int h, int stride) {
|
int w, int h, int stride) {
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
|
ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 1);
|
||||||
#else
|
#else
|
||||||
ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
|
ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* dst, int dst_stride) {
|
||||||
|
|
@ -338,6 +344,46 @@ static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int HasAlpha8b_C(const uint8_t* src, int length) {
|
||||||
|
while (length-- > 0) if (*src++ != 0xff) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HasAlpha32b_C(const uint8_t* src, int length) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; length-- > 0; x += 4) if (src[x] != 0xff) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Simple channel manipulations.
|
||||||
|
|
||||||
|
static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
|
||||||
|
return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
||||||
|
const uint8_t* b, int len, uint32_t* out) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||||
|
int len, int step, uint32_t* out) {
|
||||||
|
int i, offset = 0;
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
|
||||||
|
offset += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
|
||||||
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
|
||||||
|
|
@ -345,6 +391,15 @@ int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||||
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
|
||||||
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
|
||||||
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
|
||||||
|
const uint8_t* b, int, uint32_t*);
|
||||||
|
#endif
|
||||||
|
void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||||
|
int len, int step, uint32_t* out);
|
||||||
|
|
||||||
|
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
||||||
|
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Init function
|
// Init function
|
||||||
|
|
@ -354,21 +409,25 @@ extern void WebPInitAlphaProcessingSSE2(void);
|
||||||
extern void WebPInitAlphaProcessingSSE41(void);
|
extern void WebPInitAlphaProcessingSSE41(void);
|
||||||
extern void WebPInitAlphaProcessingNEON(void);
|
extern void WebPInitAlphaProcessingNEON(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
|
WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
|
||||||
(VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
|
WebPMultARGBRow = WebPMultARGBRow_C;
|
||||||
|
WebPMultRow = WebPMultRow_C;
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
|
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C;
|
||||||
if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
WebPMultARGBRow = WebPMultARGBRowC;
|
|
||||||
WebPMultRow = WebPMultRowC;
|
|
||||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
|
|
||||||
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
|
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
WebPPackARGB = PackARGB_C;
|
||||||
|
#endif
|
||||||
|
WebPPackRGB = PackRGB_C;
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply_C;
|
||||||
WebPDispatchAlpha = DispatchAlpha_C;
|
WebPDispatchAlpha = DispatchAlpha_C;
|
||||||
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
|
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
|
||||||
WebPExtractAlpha = ExtractAlpha_C;
|
WebPExtractAlpha = ExtractAlpha_C;
|
||||||
WebPExtractGreen = ExtractGreen_C;
|
WebPExtractGreen = ExtractGreen_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WebPHasAlpha8b = HasAlpha8b_C;
|
||||||
|
WebPHasAlpha32b = HasAlpha32b_C;
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
|
|
@ -382,16 +441,32 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
WebPInitAlphaProcessingNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
||||||
WebPInitAlphaProcessingMIPSdspR2();
|
WebPInitAlphaProcessingMIPSdspR2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
WebPInitAlphaProcessingNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(WebPMultARGBRow != NULL);
|
||||||
|
assert(WebPMultRow != NULL);
|
||||||
|
assert(WebPApplyAlphaMultiply != NULL);
|
||||||
|
assert(WebPApplyAlphaMultiply4444 != NULL);
|
||||||
|
assert(WebPDispatchAlpha != NULL);
|
||||||
|
assert(WebPDispatchAlphaToGreen != NULL);
|
||||||
|
assert(WebPExtractAlpha != NULL);
|
||||||
|
assert(WebPExtractGreen != NULL);
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
assert(WebPPackARGB != NULL);
|
||||||
|
#endif
|
||||||
|
assert(WebPPackRGB != NULL);
|
||||||
|
assert(WebPHasAlpha8b != NULL);
|
||||||
|
assert(WebPHasAlpha32b != NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,16 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
|
static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* dst, int dst_stride) {
|
uint8_t* dst, int dst_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
|
|
@ -72,9 +72,9 @@ static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
|
||||||
return (alpha_and != 0xff);
|
return (alpha_and != 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
|
static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint32_t* dst, int dst_stride) {
|
uint32_t* dst, int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const int limit = width & ~15;
|
const int limit = width & ~15;
|
||||||
|
|
@ -98,9 +98,9 @@ static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* alpha, int alpha_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
|
|
@ -210,6 +210,61 @@ static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
|
||||||
#undef MULTIPLIER
|
#undef MULTIPLIER
|
||||||
#undef PREMULTIPLY
|
#undef PREMULTIPLY
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Alpha detection
|
||||||
|
|
||||||
|
static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
|
||||||
|
const __m128i all_0xff = _mm_set1_epi8(0xff);
|
||||||
|
int i = 0;
|
||||||
|
for (; i + 16 <= length; i += 16) {
|
||||||
|
const __m128i v = _mm_loadu_si128((const __m128i*)(src + i));
|
||||||
|
const __m128i bits = _mm_cmpeq_epi8(v, all_0xff);
|
||||||
|
const int mask = _mm_movemask_epi8(bits);
|
||||||
|
if (mask != 0xffff) return 1;
|
||||||
|
}
|
||||||
|
for (; i < length; ++i) if (src[i] != 0xff) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HasAlpha32b_SSE2(const uint8_t* src, int length) {
|
||||||
|
const __m128i alpha_mask = _mm_set1_epi32(0xff);
|
||||||
|
const __m128i all_0xff = _mm_set1_epi8(0xff);
|
||||||
|
int i = 0;
|
||||||
|
// We don't know if we can access the last 3 bytes after the last alpha
|
||||||
|
// value 'src[4 * length - 4]' (because we don't know if alpha is the first
|
||||||
|
// or the last byte of the quadruplet). Hence the '-3' protection below.
|
||||||
|
length = length * 4 - 3; // size in bytes
|
||||||
|
for (; i + 64 <= length; i += 64) {
|
||||||
|
const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0));
|
||||||
|
const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16));
|
||||||
|
const __m128i a2 = _mm_loadu_si128((const __m128i*)(src + i + 32));
|
||||||
|
const __m128i a3 = _mm_loadu_si128((const __m128i*)(src + i + 48));
|
||||||
|
const __m128i b0 = _mm_and_si128(a0, alpha_mask);
|
||||||
|
const __m128i b1 = _mm_and_si128(a1, alpha_mask);
|
||||||
|
const __m128i b2 = _mm_and_si128(a2, alpha_mask);
|
||||||
|
const __m128i b3 = _mm_and_si128(a3, alpha_mask);
|
||||||
|
const __m128i c0 = _mm_packs_epi32(b0, b1);
|
||||||
|
const __m128i c1 = _mm_packs_epi32(b2, b3);
|
||||||
|
const __m128i d = _mm_packus_epi16(c0, c1);
|
||||||
|
const __m128i bits = _mm_cmpeq_epi8(d, all_0xff);
|
||||||
|
const int mask = _mm_movemask_epi8(bits);
|
||||||
|
if (mask != 0xffff) return 1;
|
||||||
|
}
|
||||||
|
for (; i + 32 <= length; i += 32) {
|
||||||
|
const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0));
|
||||||
|
const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16));
|
||||||
|
const __m128i b0 = _mm_and_si128(a0, alpha_mask);
|
||||||
|
const __m128i b1 = _mm_and_si128(a1, alpha_mask);
|
||||||
|
const __m128i c = _mm_packs_epi32(b0, b1);
|
||||||
|
const __m128i d = _mm_packus_epi16(c, c);
|
||||||
|
const __m128i bits = _mm_cmpeq_epi8(d, all_0xff);
|
||||||
|
const int mask = _mm_movemask_epi8(bits);
|
||||||
|
if (mask != 0xffff) return 1;
|
||||||
|
}
|
||||||
|
for (; i <= length; i += 4) if (src[i] != 0xff) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Apply alpha value to rows
|
// Apply alpha value to rows
|
||||||
|
|
||||||
|
|
@ -238,7 +293,7 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width -= x;
|
width -= x;
|
||||||
if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse);
|
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
|
|
@ -261,7 +316,7 @@ static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width -= x;
|
width -= x;
|
||||||
if (width > 0) WebPMultRowC(ptr + x, alpha + x, width, inverse);
|
if (width > 0) WebPMultRow_C(ptr + x, alpha + x, width, inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -273,9 +328,12 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
|
||||||
WebPMultARGBRow = MultARGBRow_SSE2;
|
WebPMultARGBRow = MultARGBRow_SSE2;
|
||||||
WebPMultRow = MultRow_SSE2;
|
WebPMultRow = MultRow_SSE2;
|
||||||
WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2;
|
WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2;
|
||||||
WebPDispatchAlpha = DispatchAlpha;
|
WebPDispatchAlpha = DispatchAlpha_SSE2;
|
||||||
WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
|
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_SSE2;
|
||||||
WebPExtractAlpha = ExtractAlpha;
|
WebPExtractAlpha = ExtractAlpha_SSE2;
|
||||||
|
|
||||||
|
WebPHasAlpha8b = HasAlpha8b_SSE2;
|
||||||
|
WebPHasAlpha32b = HasAlpha32b_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE2
|
#else // !WEBP_USE_SSE2
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE41)
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
|
||||||
|
|
@ -19,9 +19,9 @@
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
uint8_t* alpha, int alpha_stride) {
|
uint8_t* alpha, int alpha_stride) {
|
||||||
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
// alpha_and stores an 'and' operation of all the alpha[] values. The final
|
||||||
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
// value is not 0xff if any of the alpha[] is not equal to 0xff.
|
||||||
uint32_t alpha_and = 0xff;
|
uint32_t alpha_and = 0xff;
|
||||||
|
|
@ -82,7 +82,7 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride,
|
||||||
extern void WebPInitAlphaProcessingSSE41(void);
|
extern void WebPInitAlphaProcessingSSE41(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE41(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE41(void) {
|
||||||
WebPExtractAlpha = ExtractAlpha;
|
WebPExtractAlpha = ExtractAlpha_SSE41;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE41
|
#else // !WEBP_USE_SSE41
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,9 @@ static WEBP_INLINE void VP8Transpose_2_4x4_16b(
|
||||||
// Pack the planar buffers
|
// Pack the planar buffers
|
||||||
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
||||||
static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
static WEBP_INLINE void VP8PlanarTo24b_SSE2(
|
||||||
__m128i* const in2, __m128i* const in3,
|
__m128i* const in0, __m128i* const in1, __m128i* const in2,
|
||||||
__m128i* const in4, __m128i* const in5) {
|
__m128i* const in3, __m128i* const in4, __m128i* const in5) {
|
||||||
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
||||||
// let's take 6 registers of four 8b values.
|
// let's take 6 registers of four 8b values.
|
||||||
// To pack, we will keep taking one every two 8b integer and move it
|
// To pack, we will keep taking one every two 8b integer and move it
|
||||||
|
|
@ -159,10 +159,10 @@ static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
||||||
|
|
||||||
// Convert four packed four-channel buffers like argbargbargbargb... into the
|
// Convert four packed four-channel buffers like argbargbargbargb... into the
|
||||||
// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
|
// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
|
||||||
static WEBP_INLINE void VP8L32bToPlanar(__m128i* const in0,
|
static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0,
|
||||||
__m128i* const in1,
|
__m128i* const in1,
|
||||||
__m128i* const in2,
|
__m128i* const in2,
|
||||||
__m128i* const in3) {
|
__m128i* const in3) {
|
||||||
// Column-wise transpose.
|
// Column-wise transpose.
|
||||||
const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
|
const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
|
||||||
const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
|
const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
|
||||||
|
|
|
||||||
132
media/libwebp/dsp/common_sse41.h
Normal file
132
media/libwebp/dsp/common_sse41.h
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SSE4 code common to several files.
|
||||||
|
//
|
||||||
|
// Author: Vincent Rabaud (vrabaud@google.com)
|
||||||
|
|
||||||
|
#ifndef WEBP_DSP_COMMON_SSE41_H_
|
||||||
|
#define WEBP_DSP_COMMON_SSE41_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
#include <smmintrin.h>
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Channel mixing.
|
||||||
|
// Shuffles the input buffer as A0 0 0 A1 0 0 A2 ...
|
||||||
|
#define WEBP_SSE41_SHUFF(OUT, IN0, IN1) \
|
||||||
|
OUT##0 = _mm_shuffle_epi8(*IN0, shuff0); \
|
||||||
|
OUT##1 = _mm_shuffle_epi8(*IN0, shuff1); \
|
||||||
|
OUT##2 = _mm_shuffle_epi8(*IN0, shuff2); \
|
||||||
|
OUT##3 = _mm_shuffle_epi8(*IN1, shuff0); \
|
||||||
|
OUT##4 = _mm_shuffle_epi8(*IN1, shuff1); \
|
||||||
|
OUT##5 = _mm_shuffle_epi8(*IN1, shuff2);
|
||||||
|
|
||||||
|
// Pack the planar buffers
|
||||||
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
|
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
||||||
|
static WEBP_INLINE void VP8PlanarTo24b_SSE41(
|
||||||
|
__m128i* const in0, __m128i* const in1, __m128i* const in2,
|
||||||
|
__m128i* const in3, __m128i* const in4, __m128i* const in5) {
|
||||||
|
__m128i R0, R1, R2, R3, R4, R5;
|
||||||
|
__m128i G0, G1, G2, G3, G4, G5;
|
||||||
|
__m128i B0, B1, B2, B3, B4, B5;
|
||||||
|
|
||||||
|
// Process R.
|
||||||
|
{
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
5, -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
-1, 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
-1, -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1);
|
||||||
|
WEBP_SSE41_SHUFF(R, in0, in1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process G.
|
||||||
|
{
|
||||||
|
// Same as before, just shifted to the left by one and including the right
|
||||||
|
// padding.
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
-1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
-1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1);
|
||||||
|
WEBP_SSE41_SHUFF(G, in2, in3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process B.
|
||||||
|
{
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
-1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1, -1);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
-1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5, -1);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1, 10);
|
||||||
|
WEBP_SSE41_SHUFF(B, in4, in5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OR the different channels.
|
||||||
|
{
|
||||||
|
const __m128i RG0 = _mm_or_si128(R0, G0);
|
||||||
|
const __m128i RG1 = _mm_or_si128(R1, G1);
|
||||||
|
const __m128i RG2 = _mm_or_si128(R2, G2);
|
||||||
|
const __m128i RG3 = _mm_or_si128(R3, G3);
|
||||||
|
const __m128i RG4 = _mm_or_si128(R4, G4);
|
||||||
|
const __m128i RG5 = _mm_or_si128(R5, G5);
|
||||||
|
*in0 = _mm_or_si128(RG0, B0);
|
||||||
|
*in1 = _mm_or_si128(RG1, B1);
|
||||||
|
*in2 = _mm_or_si128(RG2, B2);
|
||||||
|
*in3 = _mm_or_si128(RG3, B3);
|
||||||
|
*in4 = _mm_or_si128(RG4, B4);
|
||||||
|
*in5 = _mm_or_si128(RG5, B5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef WEBP_SSE41_SHUFF
|
||||||
|
|
||||||
|
// Convert four packed four-channel buffers like argbargbargbargb... into the
|
||||||
|
// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
|
||||||
|
static WEBP_INLINE void VP8L32bToPlanar_SSE41(__m128i* const in0,
|
||||||
|
__m128i* const in1,
|
||||||
|
__m128i* const in2,
|
||||||
|
__m128i* const in3) {
|
||||||
|
// aaaarrrrggggbbbb
|
||||||
|
const __m128i shuff0 =
|
||||||
|
_mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0);
|
||||||
|
const __m128i A0 = _mm_shuffle_epi8(*in0, shuff0);
|
||||||
|
const __m128i A1 = _mm_shuffle_epi8(*in1, shuff0);
|
||||||
|
const __m128i A2 = _mm_shuffle_epi8(*in2, shuff0);
|
||||||
|
const __m128i A3 = _mm_shuffle_epi8(*in3, shuff0);
|
||||||
|
// A0A1R0R1
|
||||||
|
// G0G1B0B1
|
||||||
|
// A2A3R2R3
|
||||||
|
// G0G1B0B1
|
||||||
|
const __m128i B0 = _mm_unpacklo_epi32(A0, A1);
|
||||||
|
const __m128i B1 = _mm_unpackhi_epi32(A0, A1);
|
||||||
|
const __m128i B2 = _mm_unpacklo_epi32(A2, A3);
|
||||||
|
const __m128i B3 = _mm_unpackhi_epi32(A2, A3);
|
||||||
|
*in3 = _mm_unpacklo_epi64(B0, B2);
|
||||||
|
*in2 = _mm_unpackhi_epi64(B0, B2);
|
||||||
|
*in1 = _mm_unpacklo_epi64(B1, B3);
|
||||||
|
*in0 = _mm_unpackhi_epi64(B1, B3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_DSP_COMMON_SSE41_H_
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "../dsp/dsp.h"
|
||||||
#include "../dec/vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
|
|
@ -25,7 +27,7 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
|
||||||
// Transforms (Paragraph 14.4)
|
// Transforms (Paragraph 14.4)
|
||||||
|
|
||||||
#define STORE(x, y, v) \
|
#define STORE(x, y, v) \
|
||||||
dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
|
dst[(x) + (y) * BPS] = clip_8b(dst[(x) + (y) * BPS] + ((v) >> 3))
|
||||||
|
|
||||||
#define STORE2(y, dc, d, c) do { \
|
#define STORE2(y, dc, d, c) do { \
|
||||||
const int DC = (dc); \
|
const int DC = (dc); \
|
||||||
|
|
@ -38,7 +40,8 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
|
||||||
#define MUL1(a) ((((a) * 20091) >> 16) + (a))
|
#define MUL1(a) ((((a) * 20091) >> 16) + (a))
|
||||||
#define MUL2(a) (((a) * 35468) >> 16)
|
#define MUL2(a) (((a) * 35468) >> 16)
|
||||||
|
|
||||||
static void TransformOne(const int16_t* in, uint8_t* dst) {
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void TransformOne_C(const int16_t* in, uint8_t* dst) {
|
||||||
int C[4 * 4], *tmp;
|
int C[4 * 4], *tmp;
|
||||||
int i;
|
int i;
|
||||||
tmp = C;
|
tmp = C;
|
||||||
|
|
@ -78,7 +81,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simplified transform when only in[0], in[1] and in[4] are non-zero
|
// Simplified transform when only in[0], in[1] and in[4] are non-zero
|
||||||
static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
static void TransformAC3_C(const int16_t* in, uint8_t* dst) {
|
||||||
const int a = in[0] + 4;
|
const int a = in[0] + 4;
|
||||||
const int c4 = MUL2(in[4]);
|
const int c4 = MUL2(in[4]);
|
||||||
const int d4 = MUL1(in[4]);
|
const int d4 = MUL1(in[4]);
|
||||||
|
|
@ -93,19 +96,21 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
||||||
#undef MUL2
|
#undef MUL2
|
||||||
#undef STORE2
|
#undef STORE2
|
||||||
|
|
||||||
static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
|
static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) {
|
||||||
TransformOne(in, dst);
|
TransformOne_C(in, dst);
|
||||||
if (do_two) {
|
if (do_two) {
|
||||||
TransformOne(in + 16, dst + 4);
|
TransformOne_C(in + 16, dst + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void TransformUV(const int16_t* in, uint8_t* dst) {
|
static void TransformUV_C(const int16_t* in, uint8_t* dst) {
|
||||||
VP8Transform(in + 0 * 16, dst, 1);
|
VP8Transform(in + 0 * 16, dst, 1);
|
||||||
VP8Transform(in + 2 * 16, dst + 4 * BPS, 1);
|
VP8Transform(in + 2 * 16, dst + 4 * BPS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TransformDC(const int16_t* in, uint8_t* dst) {
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void TransformDC_C(const int16_t* in, uint8_t* dst) {
|
||||||
const int DC = in[0] + 4;
|
const int DC = in[0] + 4;
|
||||||
int i, j;
|
int i, j;
|
||||||
for (j = 0; j < 4; ++j) {
|
for (j = 0; j < 4; ++j) {
|
||||||
|
|
@ -114,8 +119,9 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void TransformDCUV(const int16_t* in, uint8_t* dst) {
|
static void TransformDCUV_C(const int16_t* in, uint8_t* dst) {
|
||||||
if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst);
|
if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst);
|
||||||
if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4);
|
if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4);
|
||||||
if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS);
|
if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS);
|
||||||
|
|
@ -127,7 +133,8 @@ static void TransformDCUV(const int16_t* in, uint8_t* dst) {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Paragraph 14.3
|
// Paragraph 14.3
|
||||||
|
|
||||||
static void TransformWHT(const int16_t* in, int16_t* out) {
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void TransformWHT_C(const int16_t* in, int16_t* out) {
|
||||||
int tmp[16];
|
int tmp[16];
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 4; ++i) {
|
for (i = 0; i < 4; ++i) {
|
||||||
|
|
@ -153,6 +160,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
|
||||||
out += 64;
|
out += 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
|
void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
|
||||||
|
|
||||||
|
|
@ -161,6 +169,7 @@ void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
|
||||||
|
|
||||||
#define DST(x, y) dst[(x) + (y) * BPS]
|
#define DST(x, y) dst[(x) + (y) * BPS]
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
|
static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
|
||||||
const uint8_t* top = dst - BPS;
|
const uint8_t* top = dst - BPS;
|
||||||
const uint8_t* const clip0 = VP8kclip1 - top[-1];
|
const uint8_t* const clip0 = VP8kclip1 - top[-1];
|
||||||
|
|
@ -174,21 +183,21 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
|
||||||
dst += BPS;
|
dst += BPS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
|
static void TM4_C(uint8_t* dst) { TrueMotion(dst, 4); }
|
||||||
static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
|
static void TM8uv_C(uint8_t* dst) { TrueMotion(dst, 8); }
|
||||||
static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
|
static void TM16_C(uint8_t* dst) { TrueMotion(dst, 16); }
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// 16x16
|
// 16x16
|
||||||
|
|
||||||
static void VE16(uint8_t* dst) { // vertical
|
static void VE16_C(uint8_t* dst) { // vertical
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
memcpy(dst + j * BPS, dst - BPS, 16);
|
memcpy(dst + j * BPS, dst - BPS, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HE16(uint8_t* dst) { // horizontal
|
static void HE16_C(uint8_t* dst) { // horizontal
|
||||||
int j;
|
int j;
|
||||||
for (j = 16; j > 0; --j) {
|
for (j = 16; j > 0; --j) {
|
||||||
memset(dst, dst[-1], 16);
|
memset(dst, dst[-1], 16);
|
||||||
|
|
@ -203,7 +212,7 @@ static WEBP_INLINE void Put16(int v, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16(uint8_t* dst) { // DC
|
static void DC16_C(uint8_t* dst) { // DC
|
||||||
int DC = 16;
|
int DC = 16;
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
|
|
@ -212,7 +221,7 @@ static void DC16(uint8_t* dst) { // DC
|
||||||
Put16(DC >> 5, dst);
|
Put16(DC >> 5, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
|
static void DC16NoTop_C(uint8_t* dst) { // DC with top samples not available
|
||||||
int DC = 8;
|
int DC = 8;
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
|
|
@ -221,7 +230,7 @@ static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
|
||||||
Put16(DC >> 4, dst);
|
Put16(DC >> 4, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
|
static void DC16NoLeft_C(uint8_t* dst) { // DC with left samples not available
|
||||||
int DC = 8;
|
int DC = 8;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
|
|
@ -230,9 +239,10 @@ static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
|
||||||
Put16(DC >> 4, dst);
|
Put16(DC >> 4, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
|
static void DC16NoTopLeft_C(uint8_t* dst) { // DC with no top and left samples
|
||||||
Put16(0x80, dst);
|
Put16(0x80, dst);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
|
VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
|
||||||
|
|
||||||
|
|
@ -242,7 +252,8 @@ VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
|
||||||
#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2))
|
#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2))
|
||||||
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
|
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
|
||||||
|
|
||||||
static void VE4(uint8_t* dst) { // vertical
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void VE4_C(uint8_t* dst) { // vertical
|
||||||
const uint8_t* top = dst - BPS;
|
const uint8_t* top = dst - BPS;
|
||||||
const uint8_t vals[4] = {
|
const uint8_t vals[4] = {
|
||||||
AVG3(top[-1], top[0], top[1]),
|
AVG3(top[-1], top[0], top[1]),
|
||||||
|
|
@ -255,8 +266,9 @@ static void VE4(uint8_t* dst) { // vertical
|
||||||
memcpy(dst + i * BPS, vals, sizeof(vals));
|
memcpy(dst + i * BPS, vals, sizeof(vals));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void HE4(uint8_t* dst) { // horizontal
|
static void HE4_C(uint8_t* dst) { // horizontal
|
||||||
const int A = dst[-1 - BPS];
|
const int A = dst[-1 - BPS];
|
||||||
const int B = dst[-1];
|
const int B = dst[-1];
|
||||||
const int C = dst[-1 + BPS];
|
const int C = dst[-1 + BPS];
|
||||||
|
|
@ -268,7 +280,8 @@ static void HE4(uint8_t* dst) { // horizontal
|
||||||
WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(D, E, E));
|
WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(D, E, E));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC4(uint8_t* dst) { // DC
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void DC4_C(uint8_t* dst) { // DC
|
||||||
uint32_t dc = 4;
|
uint32_t dc = 4;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
|
for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
|
||||||
|
|
@ -276,7 +289,7 @@ static void DC4(uint8_t* dst) { // DC
|
||||||
for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
|
for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RD4(uint8_t* dst) { // Down-right
|
static void RD4_C(uint8_t* dst) { // Down-right
|
||||||
const int I = dst[-1 + 0 * BPS];
|
const int I = dst[-1 + 0 * BPS];
|
||||||
const int J = dst[-1 + 1 * BPS];
|
const int J = dst[-1 + 1 * BPS];
|
||||||
const int K = dst[-1 + 2 * BPS];
|
const int K = dst[-1 + 2 * BPS];
|
||||||
|
|
@ -295,7 +308,7 @@ static void RD4(uint8_t* dst) { // Down-right
|
||||||
DST(3, 0) = AVG3(D, C, B);
|
DST(3, 0) = AVG3(D, C, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LD4(uint8_t* dst) { // Down-Left
|
static void LD4_C(uint8_t* dst) { // Down-Left
|
||||||
const int A = dst[0 - BPS];
|
const int A = dst[0 - BPS];
|
||||||
const int B = dst[1 - BPS];
|
const int B = dst[1 - BPS];
|
||||||
const int C = dst[2 - BPS];
|
const int C = dst[2 - BPS];
|
||||||
|
|
@ -312,8 +325,9 @@ static void LD4(uint8_t* dst) { // Down-Left
|
||||||
DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
|
DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
|
||||||
DST(3, 3) = AVG3(G, H, H);
|
DST(3, 3) = AVG3(G, H, H);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void VR4(uint8_t* dst) { // Vertical-Right
|
static void VR4_C(uint8_t* dst) { // Vertical-Right
|
||||||
const int I = dst[-1 + 0 * BPS];
|
const int I = dst[-1 + 0 * BPS];
|
||||||
const int J = dst[-1 + 1 * BPS];
|
const int J = dst[-1 + 1 * BPS];
|
||||||
const int K = dst[-1 + 2 * BPS];
|
const int K = dst[-1 + 2 * BPS];
|
||||||
|
|
@ -335,7 +349,7 @@ static void VR4(uint8_t* dst) { // Vertical-Right
|
||||||
DST(3, 1) = AVG3(B, C, D);
|
DST(3, 1) = AVG3(B, C, D);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VL4(uint8_t* dst) { // Vertical-Left
|
static void VL4_C(uint8_t* dst) { // Vertical-Left
|
||||||
const int A = dst[0 - BPS];
|
const int A = dst[0 - BPS];
|
||||||
const int B = dst[1 - BPS];
|
const int B = dst[1 - BPS];
|
||||||
const int C = dst[2 - BPS];
|
const int C = dst[2 - BPS];
|
||||||
|
|
@ -357,7 +371,7 @@ static void VL4(uint8_t* dst) { // Vertical-Left
|
||||||
DST(3, 3) = AVG3(F, G, H);
|
DST(3, 3) = AVG3(F, G, H);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HU4(uint8_t* dst) { // Horizontal-Up
|
static void HU4_C(uint8_t* dst) { // Horizontal-Up
|
||||||
const int I = dst[-1 + 0 * BPS];
|
const int I = dst[-1 + 0 * BPS];
|
||||||
const int J = dst[-1 + 1 * BPS];
|
const int J = dst[-1 + 1 * BPS];
|
||||||
const int K = dst[-1 + 2 * BPS];
|
const int K = dst[-1 + 2 * BPS];
|
||||||
|
|
@ -372,7 +386,7 @@ static void HU4(uint8_t* dst) { // Horizontal-Up
|
||||||
DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
|
DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HD4(uint8_t* dst) { // Horizontal-Down
|
static void HD4_C(uint8_t* dst) { // Horizontal-Down
|
||||||
const int I = dst[-1 + 0 * BPS];
|
const int I = dst[-1 + 0 * BPS];
|
||||||
const int J = dst[-1 + 1 * BPS];
|
const int J = dst[-1 + 1 * BPS];
|
||||||
const int K = dst[-1 + 2 * BPS];
|
const int K = dst[-1 + 2 * BPS];
|
||||||
|
|
@ -404,14 +418,15 @@ VP8PredFunc VP8PredLuma4[NUM_BMODES];
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Chroma
|
// Chroma
|
||||||
|
|
||||||
static void VE8uv(uint8_t* dst) { // vertical
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void VE8uv_C(uint8_t* dst) { // vertical
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 8; ++j) {
|
for (j = 0; j < 8; ++j) {
|
||||||
memcpy(dst + j * BPS, dst - BPS, 8);
|
memcpy(dst + j * BPS, dst - BPS, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HE8uv(uint8_t* dst) { // horizontal
|
static void HE8uv_C(uint8_t* dst) { // horizontal
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 8; ++j) {
|
for (j = 0; j < 8; ++j) {
|
||||||
memset(dst, dst[-1], 8);
|
memset(dst, dst[-1], 8);
|
||||||
|
|
@ -427,7 +442,7 @@ static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uv(uint8_t* dst) { // DC
|
static void DC8uv_C(uint8_t* dst) { // DC
|
||||||
int dc0 = 8;
|
int dc0 = 8;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
|
|
@ -436,7 +451,7 @@ static void DC8uv(uint8_t* dst) { // DC
|
||||||
Put8x8uv(dc0 >> 4, dst);
|
Put8x8uv(dc0 >> 4, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
|
static void DC8uvNoLeft_C(uint8_t* dst) { // DC with no left samples
|
||||||
int dc0 = 4;
|
int dc0 = 4;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
|
|
@ -445,7 +460,7 @@ static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
|
||||||
Put8x8uv(dc0 >> 3, dst);
|
Put8x8uv(dc0 >> 3, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
|
static void DC8uvNoTop_C(uint8_t* dst) { // DC with no top samples
|
||||||
int dc0 = 4;
|
int dc0 = 4;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
|
|
@ -454,17 +469,19 @@ static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
|
||||||
Put8x8uv(dc0 >> 3, dst);
|
Put8x8uv(dc0 >> 3, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
|
static void DC8uvNoTopLeft_C(uint8_t* dst) { // DC with nothing
|
||||||
Put8x8uv(0x80, dst);
|
Put8x8uv(0x80, dst);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
|
VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Edge filtering functions
|
// Edge filtering functions
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
// 4 pixels in, 2 pixels out
|
// 4 pixels in, 2 pixels out
|
||||||
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
|
static WEBP_INLINE void DoFilter2_C(uint8_t* p, int step) {
|
||||||
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
||||||
const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
|
const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
|
||||||
const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
|
const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
|
||||||
|
|
@ -474,7 +491,7 @@ static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4 pixels in, 4 pixels out
|
// 4 pixels in, 4 pixels out
|
||||||
static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
|
static WEBP_INLINE void DoFilter4_C(uint8_t* p, int step) {
|
||||||
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
||||||
const int a = 3 * (q0 - p0);
|
const int a = 3 * (q0 - p0);
|
||||||
const int a1 = VP8ksclip2[(a + 4) >> 3];
|
const int a1 = VP8ksclip2[(a + 4) >> 3];
|
||||||
|
|
@ -487,7 +504,7 @@ static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6 pixels in, 6 pixels out
|
// 6 pixels in, 6 pixels out
|
||||||
static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
|
static WEBP_INLINE void DoFilter6_C(uint8_t* p, int step) {
|
||||||
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
|
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
|
||||||
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
|
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
|
||||||
const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
|
const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
|
||||||
|
|
@ -503,18 +520,22 @@ static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
|
||||||
p[ 2*step] = VP8kclip1[q2 - a3];
|
p[ 2*step] = VP8kclip1[q2 - a3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
|
static WEBP_INLINE int Hev(const uint8_t* p, int step, int thresh) {
|
||||||
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
||||||
return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh);
|
return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) {
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static WEBP_INLINE int NeedsFilter_C(const uint8_t* p, int step, int t) {
|
||||||
const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
|
||||||
return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t);
|
return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static WEBP_INLINE int needs_filter2(const uint8_t* p,
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
int step, int t, int it) {
|
static WEBP_INLINE int NeedsFilter2_C(const uint8_t* p,
|
||||||
|
int step, int t, int it) {
|
||||||
const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step];
|
const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step];
|
||||||
const int p0 = p[-step], q0 = p[0];
|
const int p0 = p[-step], q0 = p[0];
|
||||||
const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
|
const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
|
||||||
|
|
@ -523,140 +544,159 @@ static WEBP_INLINE int needs_filter2(const uint8_t* p,
|
||||||
VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it &&
|
VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it &&
|
||||||
VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it;
|
VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it;
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Simple In-loop filtering (Paragraph 15.2)
|
// Simple In-loop filtering (Paragraph 15.2)
|
||||||
|
|
||||||
static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void SimpleVFilter16_C(uint8_t* p, int stride, int thresh) {
|
||||||
int i;
|
int i;
|
||||||
const int thresh2 = 2 * thresh + 1;
|
const int thresh2 = 2 * thresh + 1;
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
if (needs_filter(p + i, stride, thresh2)) {
|
if (NeedsFilter_C(p + i, stride, thresh2)) {
|
||||||
do_filter2(p + i, stride);
|
DoFilter2_C(p + i, stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
|
static void SimpleHFilter16_C(uint8_t* p, int stride, int thresh) {
|
||||||
int i;
|
int i;
|
||||||
const int thresh2 = 2 * thresh + 1;
|
const int thresh2 = 2 * thresh + 1;
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
if (needs_filter(p + i * stride, 1, thresh2)) {
|
if (NeedsFilter_C(p + i * stride, 1, thresh2)) {
|
||||||
do_filter2(p + i * stride, 1);
|
DoFilter2_C(p + i * stride, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
|
static void SimpleVFilter16i_C(uint8_t* p, int stride, int thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4 * stride;
|
p += 4 * stride;
|
||||||
SimpleVFilter16(p, stride, thresh);
|
SimpleVFilter16_C(p, stride, thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
|
static void SimpleHFilter16i_C(uint8_t* p, int stride, int thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4;
|
p += 4;
|
||||||
SimpleHFilter16(p, stride, thresh);
|
SimpleHFilter16_C(p, stride, thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Complex In-loop filtering (Paragraph 15.3)
|
// Complex In-loop filtering (Paragraph 15.3)
|
||||||
|
|
||||||
static WEBP_INLINE void FilterLoop26(uint8_t* p,
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
int hstride, int vstride, int size,
|
static WEBP_INLINE void FilterLoop26_C(uint8_t* p,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int hstride, int vstride, int size,
|
||||||
|
int thresh, int ithresh,
|
||||||
|
int hev_thresh) {
|
||||||
const int thresh2 = 2 * thresh + 1;
|
const int thresh2 = 2 * thresh + 1;
|
||||||
while (size-- > 0) {
|
while (size-- > 0) {
|
||||||
if (needs_filter2(p, hstride, thresh2, ithresh)) {
|
if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) {
|
||||||
if (hev(p, hstride, hev_thresh)) {
|
if (Hev(p, hstride, hev_thresh)) {
|
||||||
do_filter2(p, hstride);
|
DoFilter2_C(p, hstride);
|
||||||
} else {
|
} else {
|
||||||
do_filter6(p, hstride);
|
DoFilter6_C(p, hstride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p += vstride;
|
p += vstride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void FilterLoop24(uint8_t* p,
|
static WEBP_INLINE void FilterLoop24_C(uint8_t* p,
|
||||||
int hstride, int vstride, int size,
|
int hstride, int vstride, int size,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh,
|
||||||
|
int hev_thresh) {
|
||||||
const int thresh2 = 2 * thresh + 1;
|
const int thresh2 = 2 * thresh + 1;
|
||||||
while (size-- > 0) {
|
while (size-- > 0) {
|
||||||
if (needs_filter2(p, hstride, thresh2, ithresh)) {
|
if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) {
|
||||||
if (hev(p, hstride, hev_thresh)) {
|
if (Hev(p, hstride, hev_thresh)) {
|
||||||
do_filter2(p, hstride);
|
DoFilter2_C(p, hstride);
|
||||||
} else {
|
} else {
|
||||||
do_filter4(p, hstride);
|
DoFilter4_C(p, hstride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p += vstride;
|
p += vstride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
// on macroblock edges
|
// on macroblock edges
|
||||||
static void VFilter16(uint8_t* p, int stride,
|
static void VFilter16_C(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
FilterLoop26_C(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter16(uint8_t* p, int stride,
|
static void HFilter16_C(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
FilterLoop26_C(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on three inner edges
|
// on three inner edges
|
||||||
static void VFilter16i(uint8_t* p, int stride,
|
static void VFilter16i_C(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4 * stride;
|
p += 4 * stride;
|
||||||
FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
FilterLoop24_C(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void HFilter16i(uint8_t* p, int stride,
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
static void HFilter16i_C(uint8_t* p, int stride,
|
||||||
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4;
|
p += 4;
|
||||||
FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
FilterLoop24_C(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
// 8-pixels wide variant, for chroma filtering
|
// 8-pixels wide variant, for chroma filtering
|
||||||
static void VFilter8(uint8_t* u, uint8_t* v, int stride,
|
static void VFilter8_C(uint8_t* u, uint8_t* v, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
|
FilterLoop26_C(u, stride, 1, 8, thresh, ithresh, hev_thresh);
|
||||||
FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
|
FilterLoop26_C(v, stride, 1, 8, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void HFilter8(uint8_t* u, uint8_t* v, int stride,
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
static void HFilter8_C(uint8_t* u, uint8_t* v, int stride,
|
||||||
FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
|
FilterLoop26_C(u, 1, stride, 8, thresh, ithresh, hev_thresh);
|
||||||
|
FilterLoop26_C(v, 1, stride, 8, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
static void VFilter8i_C(uint8_t* u, uint8_t* v, int stride,
|
||||||
FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
FilterLoop24_C(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
||||||
|
FilterLoop24_C(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
static void HFilter8i_C(uint8_t* u, uint8_t* v, int stride,
|
||||||
FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
FilterLoop24_C(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
||||||
|
FilterLoop24_C(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void DitherCombine8x8(const uint8_t* dither, uint8_t* dst,
|
static void DitherCombine8x8_C(const uint8_t* dither, uint8_t* dst,
|
||||||
int dst_stride) {
|
int dst_stride) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (j = 0; j < 8; ++j) {
|
for (j = 0; j < 8; ++j) {
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
|
|
@ -701,62 +741,69 @@ extern void VP8DspInitMIPS32(void);
|
||||||
extern void VP8DspInitMIPSdspR2(void);
|
extern void VP8DspInitMIPSdspR2(void);
|
||||||
extern void VP8DspInitMSA(void);
|
extern void VP8DspInitMSA(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo dec_last_cpuinfo_used =
|
WEBP_DSP_INIT_FUNC(VP8DspInit) {
|
||||||
(VP8CPUInfo)&dec_last_cpuinfo_used;
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
|
|
||||||
if (dec_last_cpuinfo_used == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
VP8InitClipTables();
|
VP8InitClipTables();
|
||||||
|
|
||||||
VP8TransformWHT = TransformWHT;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
VP8Transform = TransformTwo;
|
VP8TransformWHT = TransformWHT_C;
|
||||||
VP8TransformUV = TransformUV;
|
VP8Transform = TransformTwo_C;
|
||||||
VP8TransformDC = TransformDC;
|
VP8TransformDC = TransformDC_C;
|
||||||
VP8TransformDCUV = TransformDCUV;
|
VP8TransformAC3 = TransformAC3_C;
|
||||||
VP8TransformAC3 = TransformAC3;
|
#endif
|
||||||
|
VP8TransformUV = TransformUV_C;
|
||||||
|
VP8TransformDCUV = TransformDCUV_C;
|
||||||
|
|
||||||
VP8VFilter16 = VFilter16;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
VP8HFilter16 = HFilter16;
|
VP8VFilter16 = VFilter16_C;
|
||||||
VP8VFilter8 = VFilter8;
|
VP8VFilter16i = VFilter16i_C;
|
||||||
VP8HFilter8 = HFilter8;
|
VP8HFilter16 = HFilter16_C;
|
||||||
VP8VFilter16i = VFilter16i;
|
VP8VFilter8 = VFilter8_C;
|
||||||
VP8HFilter16i = HFilter16i;
|
VP8VFilter8i = VFilter8i_C;
|
||||||
VP8VFilter8i = VFilter8i;
|
VP8SimpleVFilter16 = SimpleVFilter16_C;
|
||||||
VP8HFilter8i = HFilter8i;
|
VP8SimpleHFilter16 = SimpleHFilter16_C;
|
||||||
VP8SimpleVFilter16 = SimpleVFilter16;
|
VP8SimpleVFilter16i = SimpleVFilter16i_C;
|
||||||
VP8SimpleHFilter16 = SimpleHFilter16;
|
VP8SimpleHFilter16i = SimpleHFilter16i_C;
|
||||||
VP8SimpleVFilter16i = SimpleVFilter16i;
|
#endif
|
||||||
VP8SimpleHFilter16i = SimpleHFilter16i;
|
|
||||||
|
|
||||||
VP8PredLuma4[0] = DC4;
|
#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
|
||||||
VP8PredLuma4[1] = TM4;
|
VP8HFilter16i = HFilter16i_C;
|
||||||
VP8PredLuma4[2] = VE4;
|
VP8HFilter8 = HFilter8_C;
|
||||||
VP8PredLuma4[3] = HE4;
|
VP8HFilter8i = HFilter8i_C;
|
||||||
VP8PredLuma4[4] = RD4;
|
#endif
|
||||||
VP8PredLuma4[5] = VR4;
|
|
||||||
VP8PredLuma4[6] = LD4;
|
|
||||||
VP8PredLuma4[7] = VL4;
|
|
||||||
VP8PredLuma4[8] = HD4;
|
|
||||||
VP8PredLuma4[9] = HU4;
|
|
||||||
|
|
||||||
VP8PredLuma16[0] = DC16;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
VP8PredLuma16[1] = TM16;
|
VP8PredLuma4[0] = DC4_C;
|
||||||
VP8PredLuma16[2] = VE16;
|
VP8PredLuma4[1] = TM4_C;
|
||||||
VP8PredLuma16[3] = HE16;
|
VP8PredLuma4[2] = VE4_C;
|
||||||
VP8PredLuma16[4] = DC16NoTop;
|
VP8PredLuma4[4] = RD4_C;
|
||||||
VP8PredLuma16[5] = DC16NoLeft;
|
VP8PredLuma4[6] = LD4_C;
|
||||||
VP8PredLuma16[6] = DC16NoTopLeft;
|
#endif
|
||||||
|
|
||||||
VP8PredChroma8[0] = DC8uv;
|
VP8PredLuma4[3] = HE4_C;
|
||||||
VP8PredChroma8[1] = TM8uv;
|
VP8PredLuma4[5] = VR4_C;
|
||||||
VP8PredChroma8[2] = VE8uv;
|
VP8PredLuma4[7] = VL4_C;
|
||||||
VP8PredChroma8[3] = HE8uv;
|
VP8PredLuma4[8] = HD4_C;
|
||||||
VP8PredChroma8[4] = DC8uvNoTop;
|
VP8PredLuma4[9] = HU4_C;
|
||||||
VP8PredChroma8[5] = DC8uvNoLeft;
|
|
||||||
VP8PredChroma8[6] = DC8uvNoTopLeft;
|
|
||||||
|
|
||||||
VP8DitherCombine8x8 = DitherCombine8x8;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
VP8PredLuma16[0] = DC16_C;
|
||||||
|
VP8PredLuma16[1] = TM16_C;
|
||||||
|
VP8PredLuma16[2] = VE16_C;
|
||||||
|
VP8PredLuma16[3] = HE16_C;
|
||||||
|
VP8PredLuma16[4] = DC16NoTop_C;
|
||||||
|
VP8PredLuma16[5] = DC16NoLeft_C;
|
||||||
|
VP8PredLuma16[6] = DC16NoTopLeft_C;
|
||||||
|
|
||||||
|
VP8PredChroma8[0] = DC8uv_C;
|
||||||
|
VP8PredChroma8[1] = TM8uv_C;
|
||||||
|
VP8PredChroma8[2] = VE8uv_C;
|
||||||
|
VP8PredChroma8[3] = HE8uv_C;
|
||||||
|
VP8PredChroma8[4] = DC8uvNoTop_C;
|
||||||
|
VP8PredChroma8[5] = DC8uvNoLeft_C;
|
||||||
|
VP8PredChroma8[6] = DC8uvNoTopLeft_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VP8DitherCombine8x8 = DitherCombine8x8_C;
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
|
|
@ -770,11 +817,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
VP8DspInitNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_MIPS32)
|
#if defined(WEBP_USE_MIPS32)
|
||||||
if (VP8GetCPUInfo(kMIPS32)) {
|
if (VP8GetCPUInfo(kMIPS32)) {
|
||||||
VP8DspInitMIPS32();
|
VP8DspInitMIPS32();
|
||||||
|
|
@ -791,5 +833,55 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
dec_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
VP8DspInitNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(VP8TransformWHT != NULL);
|
||||||
|
assert(VP8Transform != NULL);
|
||||||
|
assert(VP8TransformDC != NULL);
|
||||||
|
assert(VP8TransformAC3 != NULL);
|
||||||
|
assert(VP8TransformUV != NULL);
|
||||||
|
assert(VP8TransformDCUV != NULL);
|
||||||
|
assert(VP8VFilter16 != NULL);
|
||||||
|
assert(VP8HFilter16 != NULL);
|
||||||
|
assert(VP8VFilter8 != NULL);
|
||||||
|
assert(VP8HFilter8 != NULL);
|
||||||
|
assert(VP8VFilter16i != NULL);
|
||||||
|
assert(VP8HFilter16i != NULL);
|
||||||
|
assert(VP8VFilter8i != NULL);
|
||||||
|
assert(VP8HFilter8i != NULL);
|
||||||
|
assert(VP8SimpleVFilter16 != NULL);
|
||||||
|
assert(VP8SimpleHFilter16 != NULL);
|
||||||
|
assert(VP8SimpleVFilter16i != NULL);
|
||||||
|
assert(VP8SimpleHFilter16i != NULL);
|
||||||
|
assert(VP8PredLuma4[0] != NULL);
|
||||||
|
assert(VP8PredLuma4[1] != NULL);
|
||||||
|
assert(VP8PredLuma4[2] != NULL);
|
||||||
|
assert(VP8PredLuma4[3] != NULL);
|
||||||
|
assert(VP8PredLuma4[4] != NULL);
|
||||||
|
assert(VP8PredLuma4[5] != NULL);
|
||||||
|
assert(VP8PredLuma4[6] != NULL);
|
||||||
|
assert(VP8PredLuma4[7] != NULL);
|
||||||
|
assert(VP8PredLuma4[8] != NULL);
|
||||||
|
assert(VP8PredLuma4[9] != NULL);
|
||||||
|
assert(VP8PredLuma16[0] != NULL);
|
||||||
|
assert(VP8PredLuma16[1] != NULL);
|
||||||
|
assert(VP8PredLuma16[2] != NULL);
|
||||||
|
assert(VP8PredLuma16[3] != NULL);
|
||||||
|
assert(VP8PredLuma16[4] != NULL);
|
||||||
|
assert(VP8PredLuma16[5] != NULL);
|
||||||
|
assert(VP8PredLuma16[6] != NULL);
|
||||||
|
assert(VP8PredChroma8[0] != NULL);
|
||||||
|
assert(VP8PredChroma8[1] != NULL);
|
||||||
|
assert(VP8PredChroma8[2] != NULL);
|
||||||
|
assert(VP8PredChroma8[3] != NULL);
|
||||||
|
assert(VP8PredChroma8[4] != NULL);
|
||||||
|
assert(VP8PredChroma8[5] != NULL);
|
||||||
|
assert(VP8PredChroma8[6] != NULL);
|
||||||
|
assert(VP8DitherCombine8x8 != NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,14 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#define USE_STATIC_TABLES // undefine to have run-time table initialization
|
// define to 0 to have run-time table initialization
|
||||||
|
#if !defined(USE_STATIC_TABLES)
|
||||||
|
#define USE_STATIC_TABLES 1 // ALTERNATE_CODE
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_STATIC_TABLES
|
#if (USE_STATIC_TABLES == 1)
|
||||||
|
|
||||||
static const uint8_t abs0[255 + 255 + 1] = {
|
static const uint8_t abs0[255 + 255 + 1] = {
|
||||||
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
|
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
|
||||||
|
|
@ -337,7 +340,7 @@ static uint8_t clip1[255 + 511 + 1];
|
||||||
// and make sure it's set to true _last_ (so as to be thread-safe)
|
// and make sure it's set to true _last_ (so as to be thread-safe)
|
||||||
static volatile int tables_ok = 0;
|
static volatile int tables_ok = 0;
|
||||||
|
|
||||||
#endif
|
#endif // USE_STATIC_TABLES
|
||||||
|
|
||||||
const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020];
|
const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020];
|
||||||
const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112];
|
const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112];
|
||||||
|
|
@ -345,7 +348,7 @@ const uint8_t* const VP8kclip1 = &clip1[255];
|
||||||
const uint8_t* const VP8kabs0 = &abs0[255];
|
const uint8_t* const VP8kabs0 = &abs0[255];
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8InitClipTables(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void VP8InitClipTables(void) {
|
||||||
#if !defined(USE_STATIC_TABLES)
|
#if (USE_STATIC_TABLES == 0)
|
||||||
int i;
|
int i;
|
||||||
if (!tables_ok) {
|
if (!tables_ok) {
|
||||||
for (i = -255; i <= 255; ++i) {
|
for (i = -255; i <= 255; ++i) {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -12,23 +12,25 @@
|
||||||
// Author: somnath@google.com (Somnath Banerjee)
|
// Author: somnath@google.com (Somnath Banerjee)
|
||||||
// cduvivier@google.com (Christian Duvivier)
|
// cduvivier@google.com (Christian Duvivier)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C
|
// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C
|
||||||
// one it seems => disable it by default. Uncomment the following to enable:
|
// one it seems => disable it by default. Uncomment the following to enable:
|
||||||
// #define USE_TRANSFORM_AC3
|
#if !defined(USE_TRANSFORM_AC3)
|
||||||
|
#define USE_TRANSFORM_AC3 0 // ALTERNATE_CODE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
#include "./common_sse2.h"
|
#include "../dsp/common_sse2.h"
|
||||||
#include "../dec/vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Transforms (Paragraph 14.4)
|
// Transforms (Paragraph 14.4)
|
||||||
|
|
||||||
static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
|
static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) {
|
||||||
// This implementation makes use of 16-bit fixed point versions of two
|
// This implementation makes use of 16-bit fixed point versions of two
|
||||||
// multiply constants:
|
// multiply constants:
|
||||||
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
|
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
|
||||||
|
|
@ -193,7 +195,7 @@ static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_TRANSFORM_AC3)
|
#if (USE_TRANSFORM_AC3 == 1)
|
||||||
#define MUL(a, b) (((a) * (b)) >> 16)
|
#define MUL(a, b) (((a) * (b)) >> 16)
|
||||||
static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
||||||
static const int kC1 = 20091 + (1 << 16);
|
static const int kC1 = 20091 + (1 << 16);
|
||||||
|
|
@ -248,7 +250,7 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
|
||||||
_mm_subs_epu8((p), (q)))
|
_mm_subs_epu8((p), (q)))
|
||||||
|
|
||||||
// Shift each byte of "x" by 3 bits while preserving by the sign bit.
|
// Shift each byte of "x" by 3 bits while preserving by the sign bit.
|
||||||
static WEBP_INLINE void SignedShift8b(__m128i* const x) {
|
static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i lo_0 = _mm_unpacklo_epi8(zero, *x);
|
const __m128i lo_0 = _mm_unpacklo_epi8(zero, *x);
|
||||||
const __m128i hi_0 = _mm_unpackhi_epi8(zero, *x);
|
const __m128i hi_0 = _mm_unpackhi_epi8(zero, *x);
|
||||||
|
|
@ -258,8 +260,8 @@ static WEBP_INLINE void SignedShift8b(__m128i* const x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FLIP_SIGN_BIT2(a, b) { \
|
#define FLIP_SIGN_BIT2(a, b) { \
|
||||||
a = _mm_xor_si128(a, sign_bit); \
|
(a) = _mm_xor_si128(a, sign_bit); \
|
||||||
b = _mm_xor_si128(b, sign_bit); \
|
(b) = _mm_xor_si128(b, sign_bit); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FLIP_SIGN_BIT4(a, b, c, d) { \
|
#define FLIP_SIGN_BIT4(a, b, c, d) { \
|
||||||
|
|
@ -268,11 +270,11 @@ static WEBP_INLINE void SignedShift8b(__m128i* const x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// input/output is uint8_t
|
// input/output is uint8_t
|
||||||
static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
|
static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1,
|
||||||
const __m128i* const p0,
|
const __m128i* const p0,
|
||||||
const __m128i* const q0,
|
const __m128i* const q0,
|
||||||
const __m128i* const q1,
|
const __m128i* const q1,
|
||||||
int hev_thresh, __m128i* const not_hev) {
|
int hev_thresh, __m128i* const not_hev) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i t_1 = MM_ABS(*p1, *p0);
|
const __m128i t_1 = MM_ABS(*p1, *p0);
|
||||||
const __m128i t_2 = MM_ABS(*q1, *q0);
|
const __m128i t_2 = MM_ABS(*q1, *q0);
|
||||||
|
|
@ -285,11 +287,11 @@ static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// input pixels are int8_t
|
// input pixels are int8_t
|
||||||
static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
|
static WEBP_INLINE void GetBaseDelta_SSE2(const __m128i* const p1,
|
||||||
const __m128i* const p0,
|
const __m128i* const p0,
|
||||||
const __m128i* const q0,
|
const __m128i* const q0,
|
||||||
const __m128i* const q1,
|
const __m128i* const q1,
|
||||||
__m128i* const delta) {
|
__m128i* const delta) {
|
||||||
// beware of addition order, for saturation!
|
// beware of addition order, for saturation!
|
||||||
const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
|
const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
|
||||||
const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
|
const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
|
||||||
|
|
@ -300,15 +302,16 @@ static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// input and output are int8_t
|
// input and output are int8_t
|
||||||
static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
|
static WEBP_INLINE void DoSimpleFilter_SSE2(__m128i* const p0,
|
||||||
const __m128i* const fl) {
|
__m128i* const q0,
|
||||||
|
const __m128i* const fl) {
|
||||||
const __m128i k3 = _mm_set1_epi8(3);
|
const __m128i k3 = _mm_set1_epi8(3);
|
||||||
const __m128i k4 = _mm_set1_epi8(4);
|
const __m128i k4 = _mm_set1_epi8(4);
|
||||||
__m128i v3 = _mm_adds_epi8(*fl, k3);
|
__m128i v3 = _mm_adds_epi8(*fl, k3);
|
||||||
__m128i v4 = _mm_adds_epi8(*fl, k4);
|
__m128i v4 = _mm_adds_epi8(*fl, k4);
|
||||||
|
|
||||||
SignedShift8b(&v4); // v4 >> 3
|
SignedShift8b_SSE2(&v4); // v4 >> 3
|
||||||
SignedShift8b(&v3); // v3 >> 3
|
SignedShift8b_SSE2(&v3); // v3 >> 3
|
||||||
*q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
|
*q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
|
||||||
*p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
|
*p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
|
||||||
}
|
}
|
||||||
|
|
@ -317,9 +320,9 @@ static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
|
||||||
// Update operations:
|
// Update operations:
|
||||||
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
|
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
|
||||||
// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
|
// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
|
||||||
static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
|
static WEBP_INLINE void Update2Pixels_SSE2(__m128i* const pi, __m128i* const qi,
|
||||||
const __m128i* const a0_lo,
|
const __m128i* const a0_lo,
|
||||||
const __m128i* const a0_hi) {
|
const __m128i* const a0_hi) {
|
||||||
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
|
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
|
||||||
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
|
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
|
||||||
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
|
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
|
||||||
|
|
@ -330,11 +333,11 @@ static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
|
||||||
}
|
}
|
||||||
|
|
||||||
// input pixels are uint8_t
|
// input pixels are uint8_t
|
||||||
static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
|
static WEBP_INLINE void NeedsFilter_SSE2(const __m128i* const p1,
|
||||||
const __m128i* const p0,
|
const __m128i* const p0,
|
||||||
const __m128i* const q0,
|
const __m128i* const q0,
|
||||||
const __m128i* const q1,
|
const __m128i* const q1,
|
||||||
int thresh, __m128i* const mask) {
|
int thresh, __m128i* const mask) {
|
||||||
const __m128i m_thresh = _mm_set1_epi8(thresh);
|
const __m128i m_thresh = _mm_set1_epi8(thresh);
|
||||||
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
|
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
|
||||||
const __m128i kFE = _mm_set1_epi8(0xFE);
|
const __m128i kFE = _mm_set1_epi8(0xFE);
|
||||||
|
|
@ -353,28 +356,29 @@ static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
|
||||||
// Edge filtering functions
|
// Edge filtering functions
|
||||||
|
|
||||||
// Applies filter on 2 pixels (p0 and q0)
|
// Applies filter on 2 pixels (p0 and q0)
|
||||||
static WEBP_INLINE void DoFilter2(__m128i* const p1, __m128i* const p0,
|
static WEBP_INLINE void DoFilter2_SSE2(__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* const q0, __m128i* const q1,
|
__m128i* const q0, __m128i* const q1,
|
||||||
int thresh) {
|
int thresh) {
|
||||||
__m128i a, mask;
|
__m128i a, mask;
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
// convert p1/q1 to int8_t (for GetBaseDelta)
|
// convert p1/q1 to int8_t (for GetBaseDelta_SSE2)
|
||||||
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
|
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
|
||||||
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
|
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
|
||||||
|
|
||||||
NeedsFilter(p1, p0, q0, q1, thresh, &mask);
|
NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &mask);
|
||||||
|
|
||||||
FLIP_SIGN_BIT2(*p0, *q0);
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
GetBaseDelta(&p1s, p0, q0, &q1s, &a);
|
GetBaseDelta_SSE2(&p1s, p0, q0, &q1s, &a);
|
||||||
a = _mm_and_si128(a, mask); // mask filter values we don't care about
|
a = _mm_and_si128(a, mask); // mask filter values we don't care about
|
||||||
DoSimpleFilter(p0, q0, &a);
|
DoSimpleFilter_SSE2(p0, q0, &a);
|
||||||
FLIP_SIGN_BIT2(*p0, *q0);
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies filter on 4 pixels (p1, p0, q0 and q1)
|
// Applies filter on 4 pixels (p1, p0, q0 and q1)
|
||||||
static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
|
static WEBP_INLINE void DoFilter4_SSE2(__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* const q0, __m128i* const q1,
|
__m128i* const q0, __m128i* const q1,
|
||||||
const __m128i* const mask, int hev_thresh) {
|
const __m128i* const mask,
|
||||||
|
int hev_thresh) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
const __m128i k64 = _mm_set1_epi8(64);
|
const __m128i k64 = _mm_set1_epi8(64);
|
||||||
|
|
@ -384,7 +388,7 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
|
||||||
__m128i t1, t2, t3;
|
__m128i t1, t2, t3;
|
||||||
|
|
||||||
// compute hev mask
|
// compute hev mask
|
||||||
GetNotHEV(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
||||||
|
|
||||||
// convert to signed values
|
// convert to signed values
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
||||||
|
|
@ -399,8 +403,8 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
|
||||||
|
|
||||||
t2 = _mm_adds_epi8(t1, k3); // 3 * (q0 - p0) + hev(p1 - q1) + 3
|
t2 = _mm_adds_epi8(t1, k3); // 3 * (q0 - p0) + hev(p1 - q1) + 3
|
||||||
t3 = _mm_adds_epi8(t1, k4); // 3 * (q0 - p0) + hev(p1 - q1) + 4
|
t3 = _mm_adds_epi8(t1, k4); // 3 * (q0 - p0) + hev(p1 - q1) + 4
|
||||||
SignedShift8b(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
|
SignedShift8b_SSE2(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
|
||||||
SignedShift8b(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
|
SignedShift8b_SSE2(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
|
||||||
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
|
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
|
||||||
*q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
|
*q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
|
||||||
FLIP_SIGN_BIT2(*p0, *q0);
|
FLIP_SIGN_BIT2(*p0, *q0);
|
||||||
|
|
@ -417,25 +421,26 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
|
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
|
||||||
static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
|
static WEBP_INLINE void DoFilter6_SSE2(__m128i* const p2, __m128i* const p1,
|
||||||
__m128i* const p0, __m128i* const q0,
|
__m128i* const p0, __m128i* const q0,
|
||||||
__m128i* const q1, __m128i* const q2,
|
__m128i* const q1, __m128i* const q2,
|
||||||
const __m128i* const mask, int hev_thresh) {
|
const __m128i* const mask,
|
||||||
|
int hev_thresh) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||||
__m128i a, not_hev;
|
__m128i a, not_hev;
|
||||||
|
|
||||||
// compute hev mask
|
// compute hev mask
|
||||||
GetNotHEV(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_hev);
|
||||||
|
|
||||||
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
|
||||||
FLIP_SIGN_BIT2(*p2, *q2);
|
FLIP_SIGN_BIT2(*p2, *q2);
|
||||||
GetBaseDelta(p1, p0, q0, q1, &a);
|
GetBaseDelta_SSE2(p1, p0, q0, q1, &a);
|
||||||
|
|
||||||
{ // do simple filter on pixels with hev
|
{ // do simple filter on pixels with hev
|
||||||
const __m128i m = _mm_andnot_si128(not_hev, *mask);
|
const __m128i m = _mm_andnot_si128(not_hev, *mask);
|
||||||
const __m128i f = _mm_and_si128(a, m);
|
const __m128i f = _mm_and_si128(a, m);
|
||||||
DoSimpleFilter(p0, q0, &f);
|
DoSimpleFilter_SSE2(p0, q0, &f);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // do strong filter on pixels with not hev
|
{ // do strong filter on pixels with not hev
|
||||||
|
|
@ -460,15 +465,15 @@ static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
|
||||||
const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
|
const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
|
||||||
const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
|
const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
|
||||||
|
|
||||||
Update2Pixels(p2, q2, &a2_lo, &a2_hi);
|
Update2Pixels_SSE2(p2, q2, &a2_lo, &a2_hi);
|
||||||
Update2Pixels(p1, q1, &a1_lo, &a1_hi);
|
Update2Pixels_SSE2(p1, q1, &a1_lo, &a1_hi);
|
||||||
Update2Pixels(p0, q0, &a0_lo, &a0_hi);
|
Update2Pixels_SSE2(p0, q0, &a0_lo, &a0_hi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads 8 rows across a vertical edge.
|
// reads 8 rows across a vertical edge.
|
||||||
static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
|
static WEBP_INLINE void Load8x4_SSE2(const uint8_t* const b, int stride,
|
||||||
__m128i* const p, __m128i* const q) {
|
__m128i* const p, __m128i* const q) {
|
||||||
// A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00
|
// A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00
|
||||||
// A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10
|
// A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10
|
||||||
const __m128i A0 = _mm_set_epi32(
|
const __m128i A0 = _mm_set_epi32(
|
||||||
|
|
@ -494,11 +499,11 @@ static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
|
||||||
*q = _mm_unpackhi_epi32(C0, C1);
|
*q = _mm_unpackhi_epi32(C0, C1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Load16x4(const uint8_t* const r0,
|
static WEBP_INLINE void Load16x4_SSE2(const uint8_t* const r0,
|
||||||
const uint8_t* const r8,
|
const uint8_t* const r8,
|
||||||
int stride,
|
int stride,
|
||||||
__m128i* const p1, __m128i* const p0,
|
__m128i* const p1, __m128i* const p0,
|
||||||
__m128i* const q0, __m128i* const q1) {
|
__m128i* const q0, __m128i* const q1) {
|
||||||
// Assume the pixels around the edge (|) are numbered as follows
|
// Assume the pixels around the edge (|) are numbered as follows
|
||||||
// 00 01 | 02 03
|
// 00 01 | 02 03
|
||||||
// 10 11 | 12 13
|
// 10 11 | 12 13
|
||||||
|
|
@ -514,8 +519,8 @@ static WEBP_INLINE void Load16x4(const uint8_t* const r0,
|
||||||
// q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
|
// q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
|
||||||
// p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80
|
// p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80
|
||||||
// q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
|
// q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
|
||||||
Load8x4(r0, stride, p1, q0);
|
Load8x4_SSE2(r0, stride, p1, q0);
|
||||||
Load8x4(r8, stride, p0, q1);
|
Load8x4_SSE2(r8, stride, p0, q1);
|
||||||
|
|
||||||
{
|
{
|
||||||
// p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
|
// p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
|
||||||
|
|
@ -531,7 +536,8 @@ static WEBP_INLINE void Load16x4(const uint8_t* const r0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
|
static WEBP_INLINE void Store4x4_SSE2(__m128i* const x,
|
||||||
|
uint8_t* dst, int stride) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 4; ++i, dst += stride) {
|
for (i = 0; i < 4; ++i, dst += stride) {
|
||||||
WebPUint32ToMem(dst, _mm_cvtsi128_si32(*x));
|
WebPUint32ToMem(dst, _mm_cvtsi128_si32(*x));
|
||||||
|
|
@ -540,12 +546,12 @@ static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transpose back and store
|
// Transpose back and store
|
||||||
static WEBP_INLINE void Store16x4(const __m128i* const p1,
|
static WEBP_INLINE void Store16x4_SSE2(const __m128i* const p1,
|
||||||
const __m128i* const p0,
|
const __m128i* const p0,
|
||||||
const __m128i* const q0,
|
const __m128i* const q0,
|
||||||
const __m128i* const q1,
|
const __m128i* const q1,
|
||||||
uint8_t* r0, uint8_t* r8,
|
uint8_t* r0, uint8_t* r8,
|
||||||
int stride) {
|
int stride) {
|
||||||
__m128i t1, p1_s, p0_s, q0_s, q1_s;
|
__m128i t1, p1_s, p0_s, q0_s, q1_s;
|
||||||
|
|
||||||
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
|
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
|
||||||
|
|
@ -572,55 +578,55 @@ static WEBP_INLINE void Store16x4(const __m128i* const p1,
|
||||||
p1_s = _mm_unpacklo_epi16(t1, q1_s);
|
p1_s = _mm_unpacklo_epi16(t1, q1_s);
|
||||||
q1_s = _mm_unpackhi_epi16(t1, q1_s);
|
q1_s = _mm_unpackhi_epi16(t1, q1_s);
|
||||||
|
|
||||||
Store4x4(&p0_s, r0, stride);
|
Store4x4_SSE2(&p0_s, r0, stride);
|
||||||
r0 += 4 * stride;
|
r0 += 4 * stride;
|
||||||
Store4x4(&q0_s, r0, stride);
|
Store4x4_SSE2(&q0_s, r0, stride);
|
||||||
|
|
||||||
Store4x4(&p1_s, r8, stride);
|
Store4x4_SSE2(&p1_s, r8, stride);
|
||||||
r8 += 4 * stride;
|
r8 += 4 * stride;
|
||||||
Store4x4(&q1_s, r8, stride);
|
Store4x4_SSE2(&q1_s, r8, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Simple In-loop filtering (Paragraph 15.2)
|
// Simple In-loop filtering (Paragraph 15.2)
|
||||||
|
|
||||||
static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
|
static void SimpleVFilter16_SSE2(uint8_t* p, int stride, int thresh) {
|
||||||
// Load
|
// Load
|
||||||
__m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
|
__m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
|
||||||
__m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
|
__m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
|
||||||
__m128i q0 = _mm_loadu_si128((__m128i*)&p[0]);
|
__m128i q0 = _mm_loadu_si128((__m128i*)&p[0]);
|
||||||
__m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]);
|
__m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]);
|
||||||
|
|
||||||
DoFilter2(&p1, &p0, &q0, &q1, thresh);
|
DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
_mm_storeu_si128((__m128i*)&p[-stride], p0);
|
_mm_storeu_si128((__m128i*)&p[-stride], p0);
|
||||||
_mm_storeu_si128((__m128i*)&p[0], q0);
|
_mm_storeu_si128((__m128i*)&p[0], q0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
|
static void SimpleHFilter16_SSE2(uint8_t* p, int stride, int thresh) {
|
||||||
__m128i p1, p0, q0, q1;
|
__m128i p1, p0, q0, q1;
|
||||||
|
|
||||||
p -= 2; // beginning of p1
|
p -= 2; // beginning of p1
|
||||||
|
|
||||||
Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
Load16x4_SSE2(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
|
||||||
DoFilter2(&p1, &p0, &q0, &q1, thresh);
|
DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh);
|
||||||
Store16x4(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
|
Store16x4_SSE2(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
|
static void SimpleVFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4 * stride;
|
p += 4 * stride;
|
||||||
SimpleVFilter16(p, stride, thresh);
|
SimpleVFilter16_SSE2(p, stride, thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
|
static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
|
||||||
int k;
|
int k;
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
p += 4;
|
p += 4;
|
||||||
SimpleHFilter16(p, stride, thresh);
|
SimpleHFilter16_SSE2(p, stride, thresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -628,60 +634,60 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
|
||||||
// Complex In-loop filtering (Paragraph 15.3)
|
// Complex In-loop filtering (Paragraph 15.3)
|
||||||
|
|
||||||
#define MAX_DIFF1(p3, p2, p1, p0, m) do { \
|
#define MAX_DIFF1(p3, p2, p1, p0, m) do { \
|
||||||
m = MM_ABS(p1, p0); \
|
(m) = MM_ABS(p1, p0); \
|
||||||
m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
|
(m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \
|
||||||
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
|
(m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MAX_DIFF2(p3, p2, p1, p0, m) do { \
|
#define MAX_DIFF2(p3, p2, p1, p0, m) do { \
|
||||||
m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
|
(m) = _mm_max_epu8(m, MM_ABS(p1, p0)); \
|
||||||
m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
|
(m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \
|
||||||
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
|
(m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
|
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
|
||||||
e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \
|
(e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \
|
||||||
e2 = _mm_loadu_si128((__m128i*)&(p)[1 * stride]); \
|
(e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \
|
||||||
e3 = _mm_loadu_si128((__m128i*)&(p)[2 * stride]); \
|
(e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \
|
||||||
e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \
|
(e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOADUV_H_EDGE(p, u, v, stride) do { \
|
#define LOADUV_H_EDGE(p, u, v, stride) do { \
|
||||||
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
|
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
|
||||||
const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \
|
const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \
|
||||||
p = _mm_unpacklo_epi64(U, V); \
|
(p) = _mm_unpacklo_epi64(U, V); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
|
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
|
||||||
LOADUV_H_EDGE(e1, u, v, 0 * stride); \
|
LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \
|
||||||
LOADUV_H_EDGE(e2, u, v, 1 * stride); \
|
LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \
|
||||||
LOADUV_H_EDGE(e3, u, v, 2 * stride); \
|
LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \
|
||||||
LOADUV_H_EDGE(e4, u, v, 3 * stride); \
|
LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STOREUV(p, u, v, stride) { \
|
#define STOREUV(p, u, v, stride) { \
|
||||||
_mm_storel_epi64((__m128i*)&u[(stride)], p); \
|
_mm_storel_epi64((__m128i*)&(u)[(stride)], p); \
|
||||||
p = _mm_srli_si128(p, 8); \
|
(p) = _mm_srli_si128(p, 8); \
|
||||||
_mm_storel_epi64((__m128i*)&v[(stride)], p); \
|
_mm_storel_epi64((__m128i*)&(v)[(stride)], p); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void ComplexMask(const __m128i* const p1,
|
static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1,
|
||||||
const __m128i* const p0,
|
const __m128i* const p0,
|
||||||
const __m128i* const q0,
|
const __m128i* const q0,
|
||||||
const __m128i* const q1,
|
const __m128i* const q1,
|
||||||
int thresh, int ithresh,
|
int thresh, int ithresh,
|
||||||
__m128i* const mask) {
|
__m128i* const mask) {
|
||||||
const __m128i it = _mm_set1_epi8(ithresh);
|
const __m128i it = _mm_set1_epi8(ithresh);
|
||||||
const __m128i diff = _mm_subs_epu8(*mask, it);
|
const __m128i diff = _mm_subs_epu8(*mask, it);
|
||||||
const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
|
const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
|
||||||
__m128i filter_mask;
|
__m128i filter_mask;
|
||||||
NeedsFilter(p1, p0, q0, q1, thresh, &filter_mask);
|
NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &filter_mask);
|
||||||
*mask = _mm_and_si128(thresh_mask, filter_mask);
|
*mask = _mm_and_si128(thresh_mask, filter_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on macroblock edges
|
// on macroblock edges
|
||||||
static void VFilter16(uint8_t* p, int stride,
|
static void VFilter16_SSE2(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i t1;
|
__m128i t1;
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i p2, p1, p0, q0, q1, q2;
|
__m128i p2, p1, p0, q0, q1, q2;
|
||||||
|
|
@ -694,8 +700,8 @@ static void VFilter16(uint8_t* p, int stride,
|
||||||
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
|
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
|
||||||
MAX_DIFF2(t1, q2, q1, q0, mask);
|
MAX_DIFF2(t1, q2, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
|
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
|
||||||
|
|
@ -706,28 +712,28 @@ static void VFilter16(uint8_t* p, int stride,
|
||||||
_mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
|
_mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter16(uint8_t* p, int stride,
|
static void HFilter16_SSE2(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
|
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
|
||||||
|
|
||||||
uint8_t* const b = p - 4;
|
uint8_t* const b = p - 4;
|
||||||
Load16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
|
Load16x4_SSE2(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
|
||||||
MAX_DIFF1(p3, p2, p1, p0, mask);
|
MAX_DIFF1(p3, p2, p1, p0, mask);
|
||||||
|
|
||||||
Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
Load16x4_SSE2(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
|
||||||
MAX_DIFF2(q3, q2, q1, q0, mask);
|
MAX_DIFF2(q3, q2, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
Store16x4(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
|
Store16x4_SSE2(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
|
||||||
Store16x4(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
|
Store16x4_SSE2(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
// on three inner edges
|
// on three inner edges
|
||||||
static void VFilter16i(uint8_t* p, int stride,
|
static void VFilter16i_SSE2(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
int k;
|
int k;
|
||||||
__m128i p3, p2, p1, p0; // loop invariants
|
__m128i p3, p2, p1, p0; // loop invariants
|
||||||
|
|
||||||
|
|
@ -744,8 +750,8 @@ static void VFilter16i(uint8_t* p, int stride,
|
||||||
|
|
||||||
// p3 and p2 are not just temporary variables here: they will be
|
// p3 and p2 are not just temporary variables here: they will be
|
||||||
// re-used for next span. And q2/q3 will become p1/p0 accordingly.
|
// re-used for next span. And q2/q3 will become p1/p0 accordingly.
|
||||||
ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
|
DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
_mm_storeu_si128((__m128i*)&b[0 * stride], p1);
|
_mm_storeu_si128((__m128i*)&b[0 * stride], p1);
|
||||||
|
|
@ -759,12 +765,12 @@ static void VFilter16i(uint8_t* p, int stride,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter16i(uint8_t* p, int stride,
|
static void HFilter16i_SSE2(uint8_t* p, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
int k;
|
int k;
|
||||||
__m128i p3, p2, p1, p0; // loop invariants
|
__m128i p3, p2, p1, p0; // loop invariants
|
||||||
|
|
||||||
Load16x4(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
|
Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
|
||||||
|
|
||||||
for (k = 3; k > 0; --k) {
|
for (k = 3; k > 0; --k) {
|
||||||
__m128i mask, tmp1, tmp2;
|
__m128i mask, tmp1, tmp2;
|
||||||
|
|
@ -773,13 +779,13 @@ static void HFilter16i(uint8_t* p, int stride,
|
||||||
p += 4; // beginning of q0 (and next span)
|
p += 4; // beginning of q0 (and next span)
|
||||||
|
|
||||||
MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
|
MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
|
||||||
Load16x4(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
|
Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
|
||||||
MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
|
MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
|
DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh);
|
||||||
|
|
||||||
Store16x4(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
|
Store16x4_SSE2(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
|
||||||
|
|
||||||
// rotate samples
|
// rotate samples
|
||||||
p1 = tmp1;
|
p1 = tmp1;
|
||||||
|
|
@ -788,8 +794,8 @@ static void HFilter16i(uint8_t* p, int stride,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-pixels wide variant, for chroma filtering
|
// 8-pixels wide variant, for chroma filtering
|
||||||
static void VFilter8(uint8_t* u, uint8_t* v, int stride,
|
static void VFilter8_SSE2(uint8_t* u, uint8_t* v, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i t1, p2, p1, p0, q0, q1, q2;
|
__m128i t1, p2, p1, p0, q0, q1, q2;
|
||||||
|
|
||||||
|
|
@ -801,8 +807,8 @@ static void VFilter8(uint8_t* u, uint8_t* v, int stride,
|
||||||
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
|
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
|
||||||
MAX_DIFF2(t1, q2, q1, q0, mask);
|
MAX_DIFF2(t1, q2, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
STOREUV(p2, u, v, -3 * stride);
|
STOREUV(p2, u, v, -3 * stride);
|
||||||
|
|
@ -813,28 +819,28 @@ static void VFilter8(uint8_t* u, uint8_t* v, int stride,
|
||||||
STOREUV(q2, u, v, 2 * stride);
|
STOREUV(q2, u, v, 2 * stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter8(uint8_t* u, uint8_t* v, int stride,
|
static void HFilter8_SSE2(uint8_t* u, uint8_t* v, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
|
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
|
||||||
|
|
||||||
uint8_t* const tu = u - 4;
|
uint8_t* const tu = u - 4;
|
||||||
uint8_t* const tv = v - 4;
|
uint8_t* const tv = v - 4;
|
||||||
Load16x4(tu, tv, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
|
Load16x4_SSE2(tu, tv, stride, &p3, &p2, &p1, &p0);
|
||||||
MAX_DIFF1(p3, p2, p1, p0, mask);
|
MAX_DIFF1(p3, p2, p1, p0, mask);
|
||||||
|
|
||||||
Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
|
Load16x4_SSE2(u, v, stride, &q0, &q1, &q2, &q3);
|
||||||
MAX_DIFF2(q3, q2, q1, q0, mask);
|
MAX_DIFF2(q3, q2, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
|
||||||
|
|
||||||
Store16x4(&p3, &p2, &p1, &p0, tu, tv, stride);
|
Store16x4_SSE2(&p3, &p2, &p1, &p0, tu, tv, stride);
|
||||||
Store16x4(&q0, &q1, &q2, &q3, u, v, stride);
|
Store16x4_SSE2(&q0, &q1, &q2, &q3, u, v, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
static void VFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i t1, t2, p1, p0, q0, q1;
|
__m128i t1, t2, p1, p0, q0, q1;
|
||||||
|
|
||||||
|
|
@ -849,8 +855,8 @@ static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
||||||
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
|
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
STOREUV(p1, u, v, -2 * stride);
|
STOREUV(p1, u, v, -2 * stride);
|
||||||
|
|
@ -859,24 +865,24 @@ static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
|
||||||
STOREUV(q1, u, v, 1 * stride);
|
STOREUV(q1, u, v, 1 * stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
|
static void HFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride,
|
||||||
int thresh, int ithresh, int hev_thresh) {
|
int thresh, int ithresh, int hev_thresh) {
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
__m128i t1, t2, p1, p0, q0, q1;
|
__m128i t1, t2, p1, p0, q0, q1;
|
||||||
Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
|
Load16x4_SSE2(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
|
||||||
MAX_DIFF1(t2, t1, p1, p0, mask);
|
MAX_DIFF1(t2, t1, p1, p0, mask);
|
||||||
|
|
||||||
u += 4; // beginning of q0
|
u += 4; // beginning of q0
|
||||||
v += 4;
|
v += 4;
|
||||||
Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
Load16x4_SSE2(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
|
||||||
MAX_DIFF2(t2, t1, q1, q0, mask);
|
MAX_DIFF2(t2, t1, q1, q0, mask);
|
||||||
|
|
||||||
ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
|
||||||
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh);
|
||||||
|
|
||||||
u -= 2; // beginning of p1
|
u -= 2; // beginning of p1
|
||||||
v -= 2;
|
v -= 2;
|
||||||
Store16x4(&p1, &p0, &q0, &q1, u, v, stride);
|
Store16x4_SSE2(&p1, &p0, &q0, &q1, u, v, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -893,7 +899,7 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
|
||||||
// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
|
// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
|
||||||
// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
|
// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
|
||||||
|
|
||||||
static void VE4(uint8_t* dst) { // vertical
|
static void VE4_SSE2(uint8_t* dst) { // vertical
|
||||||
const __m128i one = _mm_set1_epi8(1);
|
const __m128i one = _mm_set1_epi8(1);
|
||||||
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
|
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
|
||||||
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
|
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
|
||||||
|
|
@ -909,7 +915,7 @@ static void VE4(uint8_t* dst) { // vertical
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LD4(uint8_t* dst) { // Down-Left
|
static void LD4_SSE2(uint8_t* dst) { // Down-Left
|
||||||
const __m128i one = _mm_set1_epi8(1);
|
const __m128i one = _mm_set1_epi8(1);
|
||||||
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
|
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
|
||||||
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
|
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
|
||||||
|
|
@ -925,7 +931,7 @@ static void LD4(uint8_t* dst) { // Down-Left
|
||||||
WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
|
WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VR4(uint8_t* dst) { // Vertical-Right
|
static void VR4_SSE2(uint8_t* dst) { // Vertical-Right
|
||||||
const __m128i one = _mm_set1_epi8(1);
|
const __m128i one = _mm_set1_epi8(1);
|
||||||
const int I = dst[-1 + 0 * BPS];
|
const int I = dst[-1 + 0 * BPS];
|
||||||
const int J = dst[-1 + 1 * BPS];
|
const int J = dst[-1 + 1 * BPS];
|
||||||
|
|
@ -950,7 +956,7 @@ static void VR4(uint8_t* dst) { // Vertical-Right
|
||||||
DST(0, 3) = AVG3(K, J, I);
|
DST(0, 3) = AVG3(K, J, I);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VL4(uint8_t* dst) { // Vertical-Left
|
static void VL4_SSE2(uint8_t* dst) { // Vertical-Left
|
||||||
const __m128i one = _mm_set1_epi8(1);
|
const __m128i one = _mm_set1_epi8(1);
|
||||||
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
|
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
|
||||||
const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
|
const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
|
||||||
|
|
@ -975,7 +981,7 @@ static void VL4(uint8_t* dst) { // Vertical-Left
|
||||||
DST(3, 3) = (extra_out >> 8) & 0xff;
|
DST(3, 3) = (extra_out >> 8) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RD4(uint8_t* dst) { // Down-right
|
static void RD4_SSE2(uint8_t* dst) { // Down-right
|
||||||
const __m128i one = _mm_set1_epi8(1);
|
const __m128i one = _mm_set1_epi8(1);
|
||||||
const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
|
const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
|
||||||
const __m128i ____XABCD = _mm_slli_si128(XABCD, 4);
|
const __m128i ____XABCD = _mm_slli_si128(XABCD, 4);
|
||||||
|
|
@ -1004,7 +1010,7 @@ static void RD4(uint8_t* dst) { // Down-right
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Luma 16x16
|
// Luma 16x16
|
||||||
|
|
||||||
static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
|
static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, int size) {
|
||||||
const uint8_t* top = dst - BPS;
|
const uint8_t* top = dst - BPS;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
int y;
|
int y;
|
||||||
|
|
@ -1041,11 +1047,11 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
|
static void TM4_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 4); }
|
||||||
static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
|
static void TM8uv_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 8); }
|
||||||
static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
|
static void TM16_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 16); }
|
||||||
|
|
||||||
static void VE16(uint8_t* dst) {
|
static void VE16_SSE2(uint8_t* dst) {
|
||||||
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
|
|
@ -1053,7 +1059,7 @@ static void VE16(uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HE16(uint8_t* dst) { // horizontal
|
static void HE16_SSE2(uint8_t* dst) { // horizontal
|
||||||
int j;
|
int j;
|
||||||
for (j = 16; j > 0; --j) {
|
for (j = 16; j > 0; --j) {
|
||||||
const __m128i values = _mm_set1_epi8(dst[-1]);
|
const __m128i values = _mm_set1_epi8(dst[-1]);
|
||||||
|
|
@ -1062,7 +1068,7 @@ static void HE16(uint8_t* dst) { // horizontal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
|
static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) {
|
||||||
int j;
|
int j;
|
||||||
const __m128i values = _mm_set1_epi8(v);
|
const __m128i values = _mm_set1_epi8(v);
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
|
|
@ -1070,7 +1076,7 @@ static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16(uint8_t* dst) { // DC
|
static void DC16_SSE2(uint8_t* dst) { // DC
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
||||||
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
|
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
|
||||||
|
|
@ -1083,37 +1089,37 @@ static void DC16(uint8_t* dst) { // DC
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const int DC = _mm_cvtsi128_si32(sum) + left + 16;
|
const int DC = _mm_cvtsi128_si32(sum) + left + 16;
|
||||||
Put16(DC >> 5, dst);
|
Put16_SSE2(DC >> 5, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
|
static void DC16NoTop_SSE2(uint8_t* dst) { // DC with top samples unavailable
|
||||||
int DC = 8;
|
int DC = 8;
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 16; ++j) {
|
for (j = 0; j < 16; ++j) {
|
||||||
DC += dst[-1 + j * BPS];
|
DC += dst[-1 + j * BPS];
|
||||||
}
|
}
|
||||||
Put16(DC >> 4, dst);
|
Put16_SSE2(DC >> 4, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
|
static void DC16NoLeft_SSE2(uint8_t* dst) { // DC with left samples unavailable
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
|
||||||
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
|
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
|
||||||
// sum the two sads: sad8x2[0:1] + sad8x2[8:9]
|
// sum the two sads: sad8x2[0:1] + sad8x2[8:9]
|
||||||
const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
|
const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
|
||||||
const int DC = _mm_cvtsi128_si32(sum) + 8;
|
const int DC = _mm_cvtsi128_si32(sum) + 8;
|
||||||
Put16(DC >> 4, dst);
|
Put16_SSE2(DC >> 4, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
|
static void DC16NoTopLeft_SSE2(uint8_t* dst) { // DC with no top & left samples
|
||||||
Put16(0x80, dst);
|
Put16_SSE2(0x80, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Chroma
|
// Chroma
|
||||||
|
|
||||||
static void VE8uv(uint8_t* dst) { // vertical
|
static void VE8uv_SSE2(uint8_t* dst) { // vertical
|
||||||
int j;
|
int j;
|
||||||
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
||||||
for (j = 0; j < 8; ++j) {
|
for (j = 0; j < 8; ++j) {
|
||||||
|
|
@ -1121,17 +1127,8 @@ static void VE8uv(uint8_t* dst) { // vertical
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HE8uv(uint8_t* dst) { // horizontal
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < 8; ++j) {
|
|
||||||
const __m128i values = _mm_set1_epi8(dst[-1]);
|
|
||||||
_mm_storel_epi64((__m128i*)dst, values);
|
|
||||||
dst += BPS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper for chroma-DC predictions
|
// helper for chroma-DC predictions
|
||||||
static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
|
static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) {
|
||||||
int j;
|
int j;
|
||||||
const __m128i values = _mm_set1_epi8(v);
|
const __m128i values = _mm_set1_epi8(v);
|
||||||
for (j = 0; j < 8; ++j) {
|
for (j = 0; j < 8; ++j) {
|
||||||
|
|
@ -1139,7 +1136,7 @@ static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uv(uint8_t* dst) { // DC
|
static void DC8uv_SSE2(uint8_t* dst) { // DC
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
||||||
const __m128i sum = _mm_sad_epu8(top, zero);
|
const __m128i sum = _mm_sad_epu8(top, zero);
|
||||||
|
|
@ -1150,29 +1147,29 @@ static void DC8uv(uint8_t* dst) { // DC
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const int DC = _mm_cvtsi128_si32(sum) + left + 8;
|
const int DC = _mm_cvtsi128_si32(sum) + left + 8;
|
||||||
Put8x8uv(DC >> 4, dst);
|
Put8x8uv_SSE2(DC >> 4, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
|
static void DC8uvNoLeft_SSE2(uint8_t* dst) { // DC with no left samples
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
|
||||||
const __m128i sum = _mm_sad_epu8(top, zero);
|
const __m128i sum = _mm_sad_epu8(top, zero);
|
||||||
const int DC = _mm_cvtsi128_si32(sum) + 4;
|
const int DC = _mm_cvtsi128_si32(sum) + 4;
|
||||||
Put8x8uv(DC >> 3, dst);
|
Put8x8uv_SSE2(DC >> 3, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
|
static void DC8uvNoTop_SSE2(uint8_t* dst) { // DC with no top samples
|
||||||
int dc0 = 4;
|
int dc0 = 4;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
dc0 += dst[-1 + i * BPS];
|
dc0 += dst[-1 + i * BPS];
|
||||||
}
|
}
|
||||||
Put8x8uv(dc0 >> 3, dst);
|
Put8x8uv_SSE2(dc0 >> 3, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
|
static void DC8uvNoTopLeft_SSE2(uint8_t* dst) { // DC with nothing
|
||||||
Put8x8uv(0x80, dst);
|
Put8x8uv_SSE2(0x80, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -1181,47 +1178,46 @@ static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
|
||||||
extern void VP8DspInitSSE2(void);
|
extern void VP8DspInitSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE2(void) {
|
||||||
VP8Transform = Transform;
|
VP8Transform = Transform_SSE2;
|
||||||
#if defined(USE_TRANSFORM_AC3)
|
#if (USE_TRANSFORM_AC3 == 1)
|
||||||
VP8TransformAC3 = TransformAC3;
|
VP8TransformAC3 = TransformAC3_SSE2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VP8VFilter16 = VFilter16;
|
VP8VFilter16 = VFilter16_SSE2;
|
||||||
VP8HFilter16 = HFilter16;
|
VP8HFilter16 = HFilter16_SSE2;
|
||||||
VP8VFilter8 = VFilter8;
|
VP8VFilter8 = VFilter8_SSE2;
|
||||||
VP8HFilter8 = HFilter8;
|
VP8HFilter8 = HFilter8_SSE2;
|
||||||
VP8VFilter16i = VFilter16i;
|
VP8VFilter16i = VFilter16i_SSE2;
|
||||||
VP8HFilter16i = HFilter16i;
|
VP8HFilter16i = HFilter16i_SSE2;
|
||||||
VP8VFilter8i = VFilter8i;
|
VP8VFilter8i = VFilter8i_SSE2;
|
||||||
VP8HFilter8i = HFilter8i;
|
VP8HFilter8i = HFilter8i_SSE2;
|
||||||
|
|
||||||
VP8SimpleVFilter16 = SimpleVFilter16;
|
VP8SimpleVFilter16 = SimpleVFilter16_SSE2;
|
||||||
VP8SimpleHFilter16 = SimpleHFilter16;
|
VP8SimpleHFilter16 = SimpleHFilter16_SSE2;
|
||||||
VP8SimpleVFilter16i = SimpleVFilter16i;
|
VP8SimpleVFilter16i = SimpleVFilter16i_SSE2;
|
||||||
VP8SimpleHFilter16i = SimpleHFilter16i;
|
VP8SimpleHFilter16i = SimpleHFilter16i_SSE2;
|
||||||
|
|
||||||
VP8PredLuma4[1] = TM4;
|
VP8PredLuma4[1] = TM4_SSE2;
|
||||||
VP8PredLuma4[2] = VE4;
|
VP8PredLuma4[2] = VE4_SSE2;
|
||||||
VP8PredLuma4[4] = RD4;
|
VP8PredLuma4[4] = RD4_SSE2;
|
||||||
VP8PredLuma4[5] = VR4;
|
VP8PredLuma4[5] = VR4_SSE2;
|
||||||
VP8PredLuma4[6] = LD4;
|
VP8PredLuma4[6] = LD4_SSE2;
|
||||||
VP8PredLuma4[7] = VL4;
|
VP8PredLuma4[7] = VL4_SSE2;
|
||||||
|
|
||||||
VP8PredLuma16[0] = DC16;
|
VP8PredLuma16[0] = DC16_SSE2;
|
||||||
VP8PredLuma16[1] = TM16;
|
VP8PredLuma16[1] = TM16_SSE2;
|
||||||
VP8PredLuma16[2] = VE16;
|
VP8PredLuma16[2] = VE16_SSE2;
|
||||||
VP8PredLuma16[3] = HE16;
|
VP8PredLuma16[3] = HE16_SSE2;
|
||||||
VP8PredLuma16[4] = DC16NoTop;
|
VP8PredLuma16[4] = DC16NoTop_SSE2;
|
||||||
VP8PredLuma16[5] = DC16NoLeft;
|
VP8PredLuma16[5] = DC16NoLeft_SSE2;
|
||||||
VP8PredLuma16[6] = DC16NoTopLeft;
|
VP8PredLuma16[6] = DC16NoTopLeft_SSE2;
|
||||||
|
|
||||||
VP8PredChroma8[0] = DC8uv;
|
VP8PredChroma8[0] = DC8uv_SSE2;
|
||||||
VP8PredChroma8[1] = TM8uv;
|
VP8PredChroma8[1] = TM8uv_SSE2;
|
||||||
VP8PredChroma8[2] = VE8uv;
|
VP8PredChroma8[2] = VE8uv_SSE2;
|
||||||
VP8PredChroma8[3] = HE8uv;
|
VP8PredChroma8[4] = DC8uvNoTop_SSE2;
|
||||||
VP8PredChroma8[4] = DC8uvNoTop;
|
VP8PredChroma8[5] = DC8uvNoLeft_SSE2;
|
||||||
VP8PredChroma8[5] = DC8uvNoLeft;
|
VP8PredChroma8[6] = DC8uvNoTopLeft_SSE2;
|
||||||
VP8PredChroma8[6] = DC8uvNoTopLeft;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE2
|
#else // !WEBP_USE_SSE2
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE41)
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
#include "../dec/vp8i_dec.h"
|
#include "../dec/vp8i_dec.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
static void HE16(uint8_t* dst) { // horizontal
|
static void HE16_SSE41(uint8_t* dst) { // horizontal
|
||||||
int j;
|
int j;
|
||||||
const __m128i kShuffle3 = _mm_set1_epi8(3);
|
const __m128i kShuffle3 = _mm_set1_epi8(3);
|
||||||
for (j = 16; j > 0; --j) {
|
for (j = 16; j > 0; --j) {
|
||||||
|
|
@ -36,7 +36,7 @@ static void HE16(uint8_t* dst) { // horizontal
|
||||||
extern void VP8DspInitSSE41(void);
|
extern void VP8DspInitSSE41(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE41(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE41(void) {
|
||||||
VP8PredLuma16[3] = HE16;
|
VP8PredLuma16[3] = HE16_SSE41;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE41
|
#else // !WEBP_USE_SSE41
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,22 @@ extern "C" {
|
||||||
# define LOCAL_GCC_PREREQ(maj, min) 0
|
# define LOCAL_GCC_PREREQ(maj, min) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
|
||||||
|
# define LOCAL_CLANG_PREREQ(maj, min) \
|
||||||
|
(LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
|
||||||
|
#else
|
||||||
|
# define LOCAL_CLANG_VERSION 0
|
||||||
|
# define LOCAL_CLANG_PREREQ(maj, min) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __has_builtin
|
#ifndef __has_builtin
|
||||||
# define __has_builtin(x) 0
|
# define __has_builtin(x) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// for now, none of the optimizations below are available in emscripten
|
||||||
|
#if !defined(EMSCRIPTEN)
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
|
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
|
||||||
(defined(_M_X64) || defined(_M_IX86))
|
(defined(_M_X64) || defined(_M_IX86))
|
||||||
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
|
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
|
||||||
|
|
@ -68,18 +80,20 @@ extern "C" {
|
||||||
#define WEBP_USE_AVX2
|
#define WEBP_USE_AVX2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
|
|
||||||
#define WEBP_ANDROID_NEON // Android targets that might support NEON
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
|
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
|
||||||
// inline assembly would need to be modified for use with Native Client.
|
// inline assembly would need to be modified for use with Native Client.
|
||||||
#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON) || \
|
#if (defined(__ARM_NEON__) || \
|
||||||
defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
|
defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
|
||||||
!defined(__native_client__)
|
!defined(__native_client__)
|
||||||
#define WEBP_USE_NEON
|
#define WEBP_USE_NEON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
|
||||||
|
defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
|
||||||
|
#define WEBP_ANDROID_NEON // Android targets that may have NEON
|
||||||
|
#define WEBP_USE_NEON
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
|
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
|
||||||
#define WEBP_USE_NEON
|
#define WEBP_USE_NEON
|
||||||
#define WEBP_USE_INTRINSICS
|
#define WEBP_USE_INTRINSICS
|
||||||
|
|
@ -90,7 +104,7 @@ extern "C" {
|
||||||
#define WEBP_USE_MIPS32
|
#define WEBP_USE_MIPS32
|
||||||
#if (__mips_isa_rev >= 2)
|
#if (__mips_isa_rev >= 2)
|
||||||
#define WEBP_USE_MIPS32_R2
|
#define WEBP_USE_MIPS32_R2
|
||||||
#if defined(__mips_dspr2) || (__mips_dsp_rev >= 2)
|
#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
|
||||||
#define WEBP_USE_MIPS_DSP_R2
|
#define WEBP_USE_MIPS_DSP_R2
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -100,6 +114,24 @@ extern "C" {
|
||||||
#define WEBP_USE_MSA
|
#define WEBP_USE_MSA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* EMSCRIPTEN */
|
||||||
|
|
||||||
|
#ifndef WEBP_DSP_OMIT_C_CODE
|
||||||
|
#define WEBP_DSP_OMIT_C_CODE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__aarch64__) || defined(__ARM_NEON__)) && WEBP_DSP_OMIT_C_CODE
|
||||||
|
#define WEBP_NEON_OMIT_C_CODE 1
|
||||||
|
#else
|
||||||
|
#define WEBP_NEON_OMIT_C_CODE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
|
||||||
|
#define WEBP_NEON_WORK_AROUND_GCC 1
|
||||||
|
#else
|
||||||
|
#define WEBP_NEON_WORK_AROUND_GCC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
// This macro prevents thread_sanitizer from reporting known concurrent writes.
|
// This macro prevents thread_sanitizer from reporting known concurrent writes.
|
||||||
#define WEBP_TSAN_IGNORE_FUNCTION
|
#define WEBP_TSAN_IGNORE_FUNCTION
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
|
|
@ -109,6 +141,42 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
|
||||||
|
#include <pthread.h> // NOLINT
|
||||||
|
|
||||||
|
#define WEBP_DSP_INIT(func) do { \
|
||||||
|
static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
|
||||||
|
(VP8CPUInfo)&func ## _last_cpuinfo_used; \
|
||||||
|
static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \
|
||||||
|
if (pthread_mutex_lock(&func ## _lock)) break; \
|
||||||
|
if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \
|
||||||
|
func ## _last_cpuinfo_used = VP8GetCPUInfo; \
|
||||||
|
(void)pthread_mutex_unlock(&func ## _lock); \
|
||||||
|
} while (0)
|
||||||
|
#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
|
||||||
|
#define WEBP_DSP_INIT(func) do { \
|
||||||
|
static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
|
||||||
|
(VP8CPUInfo)&func ## _last_cpuinfo_used; \
|
||||||
|
if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \
|
||||||
|
func(); \
|
||||||
|
func ## _last_cpuinfo_used = VP8GetCPUInfo; \
|
||||||
|
} while (0)
|
||||||
|
#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
|
||||||
|
|
||||||
|
// Defines an Init + helper function that control multiple initialization of
|
||||||
|
// function pointers / tables.
|
||||||
|
/* Usage:
|
||||||
|
WEBP_DSP_INIT_FUNC(InitFunc) {
|
||||||
|
...function body
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define WEBP_DSP_INIT_FUNC(name) \
|
||||||
|
static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void name(void) { \
|
||||||
|
WEBP_DSP_INIT(name ## _body); \
|
||||||
|
} \
|
||||||
|
static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void)
|
||||||
|
|
||||||
#define WEBP_UBSAN_IGNORE_UNDEF
|
#define WEBP_UBSAN_IGNORE_UNDEF
|
||||||
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
|
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
|
||||||
#if defined(__clang__) && defined(__has_attribute)
|
#if defined(__clang__) && defined(__has_attribute)
|
||||||
|
|
@ -129,6 +197,18 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
|
||||||
|
#if !defined(WEBP_SWAP_16BIT_CSP)
|
||||||
|
#define WEBP_SWAP_16BIT_CSP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
|
||||||
|
#if !defined(WORDS_BIGENDIAN) && \
|
||||||
|
(defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
|
||||||
|
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
|
||||||
|
#define WORDS_BIGENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kSSE2,
|
kSSE2,
|
||||||
kSSE3,
|
kSSE3,
|
||||||
|
|
@ -143,7 +223,7 @@ typedef enum {
|
||||||
} CPUFeature;
|
} CPUFeature;
|
||||||
// returns true if the CPU supports the feature.
|
// returns true if the CPU supports the feature.
|
||||||
typedef int (*VP8CPUInfo)(CPUFeature feature);
|
typedef int (*VP8CPUInfo)(CPUFeature feature);
|
||||||
WEBP_EXTERN(VP8CPUInfo) VP8GetCPUInfo;
|
WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Init stub generator
|
// Init stub generator
|
||||||
|
|
@ -152,7 +232,7 @@ WEBP_EXTERN(VP8CPUInfo) VP8GetCPUInfo;
|
||||||
// avoiding a compiler warning.
|
// avoiding a compiler warning.
|
||||||
#define WEBP_DSP_INIT_STUB(func) \
|
#define WEBP_DSP_INIT_STUB(func) \
|
||||||
extern void func(void); \
|
extern void func(void); \
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void func(void) {}
|
void func(void) {}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Encoding
|
// Encoding
|
||||||
|
|
@ -271,6 +351,7 @@ typedef double (*VP8SSIMGetClippedFunc)(const uint8_t* src1, int stride1,
|
||||||
int xo, int yo, // center position
|
int xo, int yo, // center position
|
||||||
int W, int H); // plane dimension
|
int W, int H); // plane dimension
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
// This version is called with the guarantee that you can load 8 bytes and
|
// This version is called with the guarantee that you can load 8 bytes and
|
||||||
// 8 rows at offset src1 and src2
|
// 8 rows at offset src1 and src2
|
||||||
typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1,
|
typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1,
|
||||||
|
|
@ -278,10 +359,13 @@ typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1,
|
||||||
|
|
||||||
extern VP8SSIMGetFunc VP8SSIMGet; // unclipped / unchecked
|
extern VP8SSIMGetFunc VP8SSIMGet; // unclipped / unchecked
|
||||||
extern VP8SSIMGetClippedFunc VP8SSIMGetClipped; // with clipping
|
extern VP8SSIMGetClippedFunc VP8SSIMGetClipped; // with clipping
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(WEBP_DISABLE_STATS)
|
||||||
typedef uint32_t (*VP8AccumulateSSEFunc)(const uint8_t* src1,
|
typedef uint32_t (*VP8AccumulateSSEFunc)(const uint8_t* src1,
|
||||||
const uint8_t* src2, int len);
|
const uint8_t* src2, int len);
|
||||||
extern VP8AccumulateSSEFunc VP8AccumulateSSE;
|
extern VP8AccumulateSSEFunc VP8AccumulateSSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
// must be called before using any of the above directly
|
// must be called before using any of the above directly
|
||||||
void VP8SSIMDspInit(void);
|
void VP8SSIMDspInit(void);
|
||||||
|
|
@ -462,12 +546,12 @@ extern WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
|
||||||
extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
|
extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
|
||||||
|
|
||||||
// Plain-C implementation, as fall-back.
|
// Plain-C implementation, as fall-back.
|
||||||
extern void WebPRescalerImportRowExpandC(struct WebPRescaler* const wrk,
|
extern void WebPRescalerImportRowExpand_C(struct WebPRescaler* const wrk,
|
||||||
const uint8_t* src);
|
const uint8_t* src);
|
||||||
extern void WebPRescalerImportRowShrinkC(struct WebPRescaler* const wrk,
|
extern void WebPRescalerImportRowShrink_C(struct WebPRescaler* const wrk,
|
||||||
const uint8_t* src);
|
const uint8_t* src);
|
||||||
extern void WebPRescalerExportRowExpandC(struct WebPRescaler* const wrk);
|
extern void WebPRescalerExportRowExpand_C(struct WebPRescaler* const wrk);
|
||||||
extern void WebPRescalerExportRowShrinkC(struct WebPRescaler* const wrk);
|
extern void WebPRescalerExportRowShrink_C(struct WebPRescaler* const wrk);
|
||||||
|
|
||||||
// Main entry calls:
|
// Main entry calls:
|
||||||
extern void WebPRescalerImportRow(struct WebPRescaler* const wrk,
|
extern void WebPRescalerImportRow(struct WebPRescaler* const wrk,
|
||||||
|
|
@ -533,25 +617,29 @@ void WebPMultRows(uint8_t* ptr, int stride,
|
||||||
int width, int num_rows, int inverse);
|
int width, int num_rows, int inverse);
|
||||||
|
|
||||||
// Plain-C versions, used as fallback by some implementations.
|
// Plain-C versions, used as fallback by some implementations.
|
||||||
void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
|
void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
|
||||||
int width, int inverse);
|
int width, int inverse);
|
||||||
void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse);
|
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse);
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
// ARGB packing function: a/r/g/b input is rgba or bgra order.
|
||||||
|
extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r,
|
||||||
|
const uint8_t* g, const uint8_t* b, int len,
|
||||||
|
uint32_t* out);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
|
||||||
|
extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
||||||
|
int len, int step, uint32_t* out);
|
||||||
|
|
||||||
|
// This function returns true if src[i] contains a value different from 0xff.
|
||||||
|
extern int (*WebPHasAlpha8b)(const uint8_t* src, int length);
|
||||||
|
// This function returns true if src[4*i] contains a value different from 0xff.
|
||||||
|
extern int (*WebPHasAlpha32b)(const uint8_t* src, int length);
|
||||||
|
|
||||||
// To be called first before using the above.
|
// To be called first before using the above.
|
||||||
void WebPInitAlphaProcessing(void);
|
void WebPInitAlphaProcessing(void);
|
||||||
|
|
||||||
// ARGB packing function: a/r/g/b input is rgba or bgra order.
|
|
||||||
extern void (*VP8PackARGB)(const uint8_t* a, const uint8_t* r,
|
|
||||||
const uint8_t* g, const uint8_t* b, int len,
|
|
||||||
uint32_t* out);
|
|
||||||
|
|
||||||
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
|
|
||||||
extern void (*VP8PackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
|
|
||||||
int len, int step, uint32_t* out);
|
|
||||||
|
|
||||||
// To be called first before using the above.
|
|
||||||
void VP8EncDspARGBInit(void);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Filter functions
|
// Filter functions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Urvang (urvang@google.com)
|
// Author: Urvang (urvang@google.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -20,16 +20,17 @@
|
||||||
// Helpful macro.
|
// Helpful macro.
|
||||||
|
|
||||||
# define SANITY_CHECK(in, out) \
|
# define SANITY_CHECK(in, out) \
|
||||||
assert(in != NULL); \
|
assert((in) != NULL); \
|
||||||
assert(out != NULL); \
|
assert((out) != NULL); \
|
||||||
assert(width > 0); \
|
assert(width > 0); \
|
||||||
assert(height > 0); \
|
assert(height > 0); \
|
||||||
assert(stride >= width); \
|
assert(stride >= width); \
|
||||||
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
|
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
|
||||||
(void)height; // Silence unused warning.
|
(void)height; // Silence unused warning.
|
||||||
|
|
||||||
static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
uint8_t* dst, int length, int inverse) {
|
static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
|
||||||
|
uint8_t* dst, int length, int inverse) {
|
||||||
int i;
|
int i;
|
||||||
if (inverse) {
|
if (inverse) {
|
||||||
for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
|
for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
|
||||||
|
|
@ -41,7 +42,44 @@ static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Horizontal filter.
|
// Horizontal filter.
|
||||||
|
|
||||||
static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
|
||||||
|
int width, int height, int stride,
|
||||||
|
int row, int num_rows,
|
||||||
|
int inverse, uint8_t* out) {
|
||||||
|
const uint8_t* preds;
|
||||||
|
const size_t start_offset = row * stride;
|
||||||
|
const int last_row = row + num_rows;
|
||||||
|
SANITY_CHECK(in, out);
|
||||||
|
in += start_offset;
|
||||||
|
out += start_offset;
|
||||||
|
preds = inverse ? out : in;
|
||||||
|
|
||||||
|
if (row == 0) {
|
||||||
|
// Leftmost pixel is the same as input for topmost scanline.
|
||||||
|
out[0] = in[0];
|
||||||
|
PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
|
||||||
|
row = 1;
|
||||||
|
preds += stride;
|
||||||
|
in += stride;
|
||||||
|
out += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter line-by-line.
|
||||||
|
while (row < last_row) {
|
||||||
|
// Leftmost pixel is predicted from above.
|
||||||
|
PredictLine_C(in, preds - stride, out, 1, inverse);
|
||||||
|
PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
|
||||||
|
++row;
|
||||||
|
preds += stride;
|
||||||
|
in += stride;
|
||||||
|
out += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Vertical filter.
|
||||||
|
|
||||||
|
static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
int row, int num_rows,
|
int row, int num_rows,
|
||||||
int inverse, uint8_t* out) {
|
int inverse, uint8_t* out) {
|
||||||
|
|
@ -53,48 +91,11 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
||||||
out += start_offset;
|
out += start_offset;
|
||||||
preds = inverse ? out : in;
|
preds = inverse ? out : in;
|
||||||
|
|
||||||
if (row == 0) {
|
|
||||||
// Leftmost pixel is the same as input for topmost scanline.
|
|
||||||
out[0] = in[0];
|
|
||||||
PredictLine(in + 1, preds, out + 1, width - 1, inverse);
|
|
||||||
row = 1;
|
|
||||||
preds += stride;
|
|
||||||
in += stride;
|
|
||||||
out += stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter line-by-line.
|
|
||||||
while (row < last_row) {
|
|
||||||
// Leftmost pixel is predicted from above.
|
|
||||||
PredictLine(in, preds - stride, out, 1, inverse);
|
|
||||||
PredictLine(in + 1, preds, out + 1, width - 1, inverse);
|
|
||||||
++row;
|
|
||||||
preds += stride;
|
|
||||||
in += stride;
|
|
||||||
out += stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Vertical filter.
|
|
||||||
|
|
||||||
static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
|
||||||
int width, int height, int stride,
|
|
||||||
int row, int num_rows,
|
|
||||||
int inverse, uint8_t* out) {
|
|
||||||
const uint8_t* preds;
|
|
||||||
const size_t start_offset = row * stride;
|
|
||||||
const int last_row = row + num_rows;
|
|
||||||
SANITY_CHECK(in, out);
|
|
||||||
in += start_offset;
|
|
||||||
out += start_offset;
|
|
||||||
preds = inverse ? out : in;
|
|
||||||
|
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
// Very first top-left pixel is copied.
|
// Very first top-left pixel is copied.
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
// Rest of top scan-line is left-predicted.
|
// Rest of top scan-line is left-predicted.
|
||||||
PredictLine(in + 1, preds, out + 1, width - 1, inverse);
|
PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
|
||||||
row = 1;
|
row = 1;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -105,26 +106,28 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
||||||
|
|
||||||
// Filter line-by-line.
|
// Filter line-by-line.
|
||||||
while (row < last_row) {
|
while (row < last_row) {
|
||||||
PredictLine(in, preds, out, width, inverse);
|
PredictLine_C(in, preds, out, width, inverse);
|
||||||
++row;
|
++row;
|
||||||
preds += stride;
|
preds += stride;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Gradient filter.
|
// Gradient filter.
|
||||||
|
|
||||||
static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
|
static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) {
|
||||||
const int g = a + b - c;
|
const int g = a + b - c;
|
||||||
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
|
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
int width, int height, int stride,
|
static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
|
||||||
int row, int num_rows,
|
int width, int height, int stride,
|
||||||
int inverse, uint8_t* out) {
|
int row, int num_rows,
|
||||||
|
int inverse, uint8_t* out) {
|
||||||
const uint8_t* preds;
|
const uint8_t* preds;
|
||||||
const size_t start_offset = row * stride;
|
const size_t start_offset = row * stride;
|
||||||
const int last_row = row + num_rows;
|
const int last_row = row + num_rows;
|
||||||
|
|
@ -136,7 +139,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
// left prediction for top scan-line
|
// left prediction for top scan-line
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
PredictLine(in + 1, preds, out + 1, width - 1, inverse);
|
PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
|
||||||
row = 1;
|
row = 1;
|
||||||
preds += stride;
|
preds += stride;
|
||||||
in += stride;
|
in += stride;
|
||||||
|
|
@ -147,11 +150,11 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
while (row < last_row) {
|
while (row < last_row) {
|
||||||
int w;
|
int w;
|
||||||
// leftmost pixel: predict from above.
|
// leftmost pixel: predict from above.
|
||||||
PredictLine(in, preds - stride, out, 1, inverse);
|
PredictLine_C(in, preds - stride, out, 1, inverse);
|
||||||
for (w = 1; w < width; ++w) {
|
for (w = 1; w < width; ++w) {
|
||||||
const int pred = GradientPredictor(preds[w - 1],
|
const int pred = GradientPredictor_C(preds[w - 1],
|
||||||
preds[w - stride],
|
preds[w - stride],
|
||||||
preds[w - stride - 1]);
|
preds[w - stride - 1]);
|
||||||
out[w] = in[w] + (inverse ? pred : -pred);
|
out[w] = in[w] + (inverse ? pred : -pred);
|
||||||
}
|
}
|
||||||
++row;
|
++row;
|
||||||
|
|
@ -160,32 +163,34 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
out += stride;
|
out += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
#undef SANITY_CHECK
|
#undef SANITY_CHECK
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void HorizontalFilter(const uint8_t* data, int width, int height,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
static void HorizontalFilter_C(const uint8_t* data, int width, int height,
|
||||||
|
int stride, uint8_t* filtered_data) {
|
||||||
|
DoHorizontalFilter_C(data, width, height, stride, 0, height, 0,
|
||||||
|
filtered_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VerticalFilter_C(const uint8_t* data, int width, int height,
|
||||||
int stride, uint8_t* filtered_data) {
|
int stride, uint8_t* filtered_data) {
|
||||||
DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
|
DoVerticalFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VerticalFilter(const uint8_t* data, int width, int height,
|
static void GradientFilter_C(const uint8_t* data, int width, int height,
|
||||||
int stride, uint8_t* filtered_data) {
|
int stride, uint8_t* filtered_data) {
|
||||||
DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
|
DoGradientFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void GradientFilter(const uint8_t* data, int width, int height,
|
|
||||||
int stride, uint8_t* filtered_data) {
|
|
||||||
DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
|
static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||||
uint8_t* out, int width) {
|
uint8_t* out, int width) {
|
||||||
uint8_t pred = (prev == NULL) ? 0 : prev[0];
|
uint8_t pred = (prev == NULL) ? 0 : prev[0];
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
|
|
@ -194,26 +199,28 @@ static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
uint8_t* out, int width) {
|
static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||||
|
uint8_t* out, int width) {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
HorizontalUnfilter(NULL, in, out, width);
|
HorizontalUnfilter_C(NULL, in, out, width);
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i) out[i] = prev[i] + in[i];
|
for (i = 0; i < width; ++i) out[i] = prev[i] + in[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
|
static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||||
uint8_t* out, int width) {
|
uint8_t* out, int width) {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
HorizontalUnfilter(NULL, in, out, width);
|
HorizontalUnfilter_C(NULL, in, out, width);
|
||||||
} else {
|
} else {
|
||||||
uint8_t top = prev[0], top_left = top, left = top;
|
uint8_t top = prev[0], top_left = top, left = top;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
top = prev[i]; // need to read this first, in case prev==out
|
top = prev[i]; // need to read this first, in case prev==out
|
||||||
left = in[i] + GradientPredictor(left, top, top_left);
|
left = in[i] + GradientPredictor_C(left, top, top_left);
|
||||||
top_left = top;
|
top_left = top;
|
||||||
out[i] = left;
|
out[i] = left;
|
||||||
}
|
}
|
||||||
|
|
@ -231,21 +238,20 @@ extern void VP8FiltersInitMSA(void);
|
||||||
extern void VP8FiltersInitNEON(void);
|
extern void VP8FiltersInitNEON(void);
|
||||||
extern void VP8FiltersInitSSE2(void);
|
extern void VP8FiltersInitSSE2(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo filters_last_cpuinfo_used =
|
WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
|
||||||
(VP8CPUInfo)&filters_last_cpuinfo_used;
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
|
|
||||||
if (filters_last_cpuinfo_used == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
WebPUnfilters[WEBP_FILTER_NONE] = NULL;
|
WebPUnfilters[WEBP_FILTER_NONE] = NULL;
|
||||||
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
|
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
|
||||||
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
|
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
|
||||||
|
#endif
|
||||||
|
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_C;
|
||||||
|
|
||||||
WebPFilters[WEBP_FILTER_NONE] = NULL;
|
WebPFilters[WEBP_FILTER_NONE] = NULL;
|
||||||
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
|
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_C;
|
||||||
WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
|
WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_C;
|
||||||
|
WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
@ -253,11 +259,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
|
||||||
VP8FiltersInitSSE2();
|
VP8FiltersInitSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
VP8FiltersInitNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
||||||
VP8FiltersInitMIPSdspR2();
|
VP8FiltersInitMIPSdspR2();
|
||||||
|
|
@ -269,5 +270,18 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
filters_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
VP8FiltersInitNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
|
||||||
|
assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
|
||||||
|
assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
|
||||||
|
assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL);
|
||||||
|
assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL);
|
||||||
|
assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
|
|
@ -24,16 +24,16 @@
|
||||||
// Helpful macro.
|
// Helpful macro.
|
||||||
|
|
||||||
# define SANITY_CHECK(in, out) \
|
# define SANITY_CHECK(in, out) \
|
||||||
assert(in != NULL); \
|
assert((in) != NULL); \
|
||||||
assert(out != NULL); \
|
assert((out) != NULL); \
|
||||||
assert(width > 0); \
|
assert(width > 0); \
|
||||||
assert(height > 0); \
|
assert(height > 0); \
|
||||||
assert(stride >= width); \
|
assert(stride >= width); \
|
||||||
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
|
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
|
||||||
(void)height; // Silence unused warning.
|
(void)height; // Silence unused warning.
|
||||||
|
|
||||||
static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
|
static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred,
|
||||||
uint8_t* dst, int length) {
|
uint8_t* dst, int length) {
|
||||||
int i;
|
int i;
|
||||||
const int max_pos = length & ~31;
|
const int max_pos = length & ~31;
|
||||||
assert(length >= 0);
|
assert(length >= 0);
|
||||||
|
|
@ -51,7 +51,7 @@ static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for left-based prediction (when preds==dst-1 or preds==src-1).
|
// Special case for left-based prediction (when preds==dst-1 or preds==src-1).
|
||||||
static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length) {
|
static void PredictLineLeft_SSE2(const uint8_t* src, uint8_t* dst, int length) {
|
||||||
int i;
|
int i;
|
||||||
const int max_pos = length & ~31;
|
const int max_pos = length & ~31;
|
||||||
assert(length >= 0);
|
assert(length >= 0);
|
||||||
|
|
@ -71,10 +71,11 @@ static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length) {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Horizontal filter.
|
// Horizontal filter.
|
||||||
|
|
||||||
static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in,
|
||||||
int width, int height, int stride,
|
int width, int height,
|
||||||
int row, int num_rows,
|
int stride,
|
||||||
uint8_t* out) {
|
int row, int num_rows,
|
||||||
|
uint8_t* out) {
|
||||||
const size_t start_offset = row * stride;
|
const size_t start_offset = row * stride;
|
||||||
const int last_row = row + num_rows;
|
const int last_row = row + num_rows;
|
||||||
SANITY_CHECK(in, out);
|
SANITY_CHECK(in, out);
|
||||||
|
|
@ -84,7 +85,7 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
// Leftmost pixel is the same as input for topmost scanline.
|
// Leftmost pixel is the same as input for topmost scanline.
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
PredictLineLeft(in + 1, out + 1, width - 1);
|
PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
|
||||||
row = 1;
|
row = 1;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -94,7 +95,7 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
||||||
while (row < last_row) {
|
while (row < last_row) {
|
||||||
// Leftmost pixel is predicted from above.
|
// Leftmost pixel is predicted from above.
|
||||||
out[0] = in[0] - in[-stride];
|
out[0] = in[0] - in[-stride];
|
||||||
PredictLineLeft(in + 1, out + 1, width - 1);
|
PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
|
||||||
++row;
|
++row;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -104,9 +105,10 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Vertical filter.
|
// Vertical filter.
|
||||||
|
|
||||||
static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
int row, int num_rows, uint8_t* out) {
|
int row, int num_rows,
|
||||||
|
uint8_t* out) {
|
||||||
const size_t start_offset = row * stride;
|
const size_t start_offset = row * stride;
|
||||||
const int last_row = row + num_rows;
|
const int last_row = row + num_rows;
|
||||||
SANITY_CHECK(in, out);
|
SANITY_CHECK(in, out);
|
||||||
|
|
@ -117,7 +119,7 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
||||||
// Very first top-left pixel is copied.
|
// Very first top-left pixel is copied.
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
// Rest of top scan-line is left-predicted.
|
// Rest of top scan-line is left-predicted.
|
||||||
PredictLineLeft(in + 1, out + 1, width - 1);
|
PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
|
||||||
row = 1;
|
row = 1;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -125,7 +127,7 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
||||||
|
|
||||||
// Filter line-by-line.
|
// Filter line-by-line.
|
||||||
while (row < last_row) {
|
while (row < last_row) {
|
||||||
PredictLineTop(in, in - stride, out, width);
|
PredictLineTop_SSE2(in, in - stride, out, width);
|
||||||
++row;
|
++row;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -135,14 +137,14 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Gradient filter.
|
// Gradient filter.
|
||||||
|
|
||||||
static WEBP_INLINE int GradientPredictorC(uint8_t a, uint8_t b, uint8_t c) {
|
static WEBP_INLINE int GradientPredictor_SSE2(uint8_t a, uint8_t b, uint8_t c) {
|
||||||
const int g = a + b - c;
|
const int g = a + b - c;
|
||||||
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
|
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GradientPredictDirect(const uint8_t* const row,
|
static void GradientPredictDirect_SSE2(const uint8_t* const row,
|
||||||
const uint8_t* const top,
|
const uint8_t* const top,
|
||||||
uint8_t* const out, int length) {
|
uint8_t* const out, int length) {
|
||||||
const int max_pos = length & ~7;
|
const int max_pos = length & ~7;
|
||||||
int i;
|
int i;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
|
@ -161,14 +163,14 @@ static void GradientPredictDirect(const uint8_t* const row,
|
||||||
_mm_storel_epi64((__m128i*)(out + i), H);
|
_mm_storel_epi64((__m128i*)(out + i), H);
|
||||||
}
|
}
|
||||||
for (; i < length; ++i) {
|
for (; i < length; ++i) {
|
||||||
out[i] = row[i] - GradientPredictorC(row[i - 1], top[i], top[i - 1]);
|
out[i] = row[i] - GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
int row, int num_rows,
|
int row, int num_rows,
|
||||||
uint8_t* out) {
|
uint8_t* out) {
|
||||||
const size_t start_offset = row * stride;
|
const size_t start_offset = row * stride;
|
||||||
const int last_row = row + num_rows;
|
const int last_row = row + num_rows;
|
||||||
SANITY_CHECK(in, out);
|
SANITY_CHECK(in, out);
|
||||||
|
|
@ -178,7 +180,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
// left prediction for top scan-line
|
// left prediction for top scan-line
|
||||||
if (row == 0) {
|
if (row == 0) {
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
PredictLineLeft(in + 1, out + 1, width - 1);
|
PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
|
||||||
row = 1;
|
row = 1;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -187,7 +189,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
// Filter line-by-line.
|
// Filter line-by-line.
|
||||||
while (row < last_row) {
|
while (row < last_row) {
|
||||||
out[0] = in[0] - in[-stride];
|
out[0] = in[0] - in[-stride];
|
||||||
GradientPredictDirect(in + 1, in + 1 - stride, out + 1, width - 1);
|
GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1);
|
||||||
++row;
|
++row;
|
||||||
in += stride;
|
in += stride;
|
||||||
out += stride;
|
out += stride;
|
||||||
|
|
@ -198,26 +200,27 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void HorizontalFilter(const uint8_t* data, int width, int height,
|
static void HorizontalFilter_SSE2(const uint8_t* data, int width, int height,
|
||||||
int stride, uint8_t* filtered_data) {
|
int stride, uint8_t* filtered_data) {
|
||||||
DoHorizontalFilter(data, width, height, stride, 0, height, filtered_data);
|
DoHorizontalFilter_SSE2(data, width, height, stride, 0, height,
|
||||||
|
filtered_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VerticalFilter(const uint8_t* data, int width, int height,
|
static void VerticalFilter_SSE2(const uint8_t* data, int width, int height,
|
||||||
int stride, uint8_t* filtered_data) {
|
int stride, uint8_t* filtered_data) {
|
||||||
DoVerticalFilter(data, width, height, stride, 0, height, filtered_data);
|
DoVerticalFilter_SSE2(data, width, height, stride, 0, height, filtered_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GradientFilter(const uint8_t* data, int width, int height,
|
static void GradientFilter_SSE2(const uint8_t* data, int width, int height,
|
||||||
int stride, uint8_t* filtered_data) {
|
int stride, uint8_t* filtered_data) {
|
||||||
DoGradientFilter(data, width, height, stride, 0, height, filtered_data);
|
DoGradientFilter_SSE2(data, width, height, stride, 0, height, filtered_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Inverse transforms
|
// Inverse transforms
|
||||||
|
|
||||||
static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
|
static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||||
uint8_t* out, int width) {
|
uint8_t* out, int width) {
|
||||||
int i;
|
int i;
|
||||||
__m128i last;
|
__m128i last;
|
||||||
out[0] = in[0] + (prev == NULL ? 0 : prev[0]);
|
out[0] = in[0] + (prev == NULL ? 0 : prev[0]);
|
||||||
|
|
@ -238,10 +241,10 @@ static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
|
||||||
for (; i < width; ++i) out[i] = in[i] + out[i - 1];
|
for (; i < width; ++i) out[i] = in[i] + out[i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
|
static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||||
uint8_t* out, int width) {
|
uint8_t* out, int width) {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
HorizontalUnfilter(NULL, in, out, width);
|
HorizontalUnfilter_SSE2(NULL, in, out, width);
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
const int max_pos = width & ~31;
|
const int max_pos = width & ~31;
|
||||||
|
|
@ -260,9 +263,9 @@ static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GradientPredictInverse(const uint8_t* const in,
|
static void GradientPredictInverse_SSE2(const uint8_t* const in,
|
||||||
const uint8_t* const top,
|
const uint8_t* const top,
|
||||||
uint8_t* const row, int length) {
|
uint8_t* const row, int length) {
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
int i;
|
int i;
|
||||||
const int max_pos = length & ~7;
|
const int max_pos = length & ~7;
|
||||||
|
|
@ -293,18 +296,18 @@ static void GradientPredictInverse(const uint8_t* const in,
|
||||||
_mm_storel_epi64((__m128i*)&row[i], out);
|
_mm_storel_epi64((__m128i*)&row[i], out);
|
||||||
}
|
}
|
||||||
for (; i < length; ++i) {
|
for (; i < length; ++i) {
|
||||||
row[i] = in[i] + GradientPredictorC(row[i - 1], top[i], top[i - 1]);
|
row[i] = in[i] + GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
|
static void GradientUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||||
uint8_t* out, int width) {
|
uint8_t* out, int width) {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
HorizontalUnfilter(NULL, in, out, width);
|
HorizontalUnfilter_SSE2(NULL, in, out, width);
|
||||||
} else {
|
} else {
|
||||||
out[0] = in[0] + prev[0]; // predict from above
|
out[0] = in[0] + prev[0]; // predict from above
|
||||||
GradientPredictInverse(in + 1, prev + 1, out + 1, width - 1);
|
GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,13 +317,13 @@ static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
|
||||||
extern void VP8FiltersInitSSE2(void);
|
extern void VP8FiltersInitSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
|
||||||
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
|
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2;
|
||||||
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
|
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2;
|
||||||
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
|
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2;
|
||||||
|
|
||||||
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
|
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2;
|
||||||
WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
|
WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_SSE2;
|
||||||
WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
|
WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE2
|
#else // !WEBP_USE_SSE2
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,15 @@
|
||||||
// Jyrki Alakuijala (jyrki@google.com)
|
// Jyrki Alakuijala (jyrki@google.com)
|
||||||
// Urvang Joshi (urvang@google.com)
|
// Urvang Joshi (urvang@google.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../dec/vp8li_dec.h"
|
#include "../dec/vp8li_dec.h"
|
||||||
#include "../utils/endian_inl_utils.h"
|
#include "../utils/endian_inl_utils.h"
|
||||||
#include "./lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
#include "./lossless_common.h"
|
#include "../dsp/lossless_common.h"
|
||||||
|
|
||||||
#define MAX_DIFF_COST (1e30f)
|
#define MAX_DIFF_COST (1e30f)
|
||||||
|
|
||||||
|
|
@ -80,8 +81,9 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
|
||||||
return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
|
return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined.
|
// gcc <= 4.9 on ARM generates incorrect code in Select() when Sub3() is
|
||||||
#if defined(__arm__) && LOCAL_GCC_VERSION == 0x409
|
// inlined.
|
||||||
|
#if defined(__arm__) && LOCAL_GCC_VERSION <= 0x409
|
||||||
# define LOCAL_INLINE __attribute__ ((noinline))
|
# define LOCAL_INLINE __attribute__ ((noinline))
|
||||||
#else
|
#else
|
||||||
# define LOCAL_INLINE WEBP_INLINE
|
# define LOCAL_INLINE WEBP_INLINE
|
||||||
|
|
@ -107,69 +109,69 @@ static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Predictors
|
// Predictors
|
||||||
|
|
||||||
static uint32_t Predictor0(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor0_C(uint32_t left, const uint32_t* const top) {
|
||||||
(void)top;
|
(void)top;
|
||||||
(void)left;
|
(void)left;
|
||||||
return ARGB_BLACK;
|
return ARGB_BLACK;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor1(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor1_C(uint32_t left, const uint32_t* const top) {
|
||||||
(void)top;
|
(void)top;
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor2_C(uint32_t left, const uint32_t* const top) {
|
||||||
(void)left;
|
(void)left;
|
||||||
return top[0];
|
return top[0];
|
||||||
}
|
}
|
||||||
static uint32_t Predictor3(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor3_C(uint32_t left, const uint32_t* const top) {
|
||||||
(void)left;
|
(void)left;
|
||||||
return top[1];
|
return top[1];
|
||||||
}
|
}
|
||||||
static uint32_t Predictor4(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor4_C(uint32_t left, const uint32_t* const top) {
|
||||||
(void)left;
|
(void)left;
|
||||||
return top[-1];
|
return top[-1];
|
||||||
}
|
}
|
||||||
static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor5_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average3(left, top[0], top[1]);
|
const uint32_t pred = Average3(left, top[0], top[1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor6_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(left, top[-1]);
|
const uint32_t pred = Average2(left, top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor7_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(left, top[0]);
|
const uint32_t pred = Average2(left, top[0]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor8_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(top[-1], top[0]);
|
const uint32_t pred = Average2(top[-1], top[0]);
|
||||||
(void)left;
|
(void)left;
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor9_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(top[0], top[1]);
|
const uint32_t pred = Average2(top[0], top[1]);
|
||||||
(void)left;
|
(void)left;
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor10_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
|
const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor11_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Select(top[0], left, top[-1]);
|
const uint32_t pred = Select(top[0], left, top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor12_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
|
const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor13_C(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
|
const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
|
|
||||||
GENERATE_PREDICTOR_ADD(Predictor0, PredictorAdd0)
|
GENERATE_PREDICTOR_ADD(Predictor0_C, PredictorAdd0_C)
|
||||||
static void PredictorAdd1(const uint32_t* in, const uint32_t* upper,
|
static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper,
|
||||||
int num_pixels, uint32_t* out) {
|
int num_pixels, uint32_t* out) {
|
||||||
int i;
|
int i;
|
||||||
uint32_t left = out[-1];
|
uint32_t left = out[-1];
|
||||||
for (i = 0; i < num_pixels; ++i) {
|
for (i = 0; i < num_pixels; ++i) {
|
||||||
|
|
@ -177,29 +179,29 @@ static void PredictorAdd1(const uint32_t* in, const uint32_t* upper,
|
||||||
}
|
}
|
||||||
(void)upper;
|
(void)upper;
|
||||||
}
|
}
|
||||||
GENERATE_PREDICTOR_ADD(Predictor2, PredictorAdd2)
|
GENERATE_PREDICTOR_ADD(Predictor2_C, PredictorAdd2_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor3, PredictorAdd3)
|
GENERATE_PREDICTOR_ADD(Predictor3_C, PredictorAdd3_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor4, PredictorAdd4)
|
GENERATE_PREDICTOR_ADD(Predictor4_C, PredictorAdd4_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor5, PredictorAdd5)
|
GENERATE_PREDICTOR_ADD(Predictor5_C, PredictorAdd5_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor6, PredictorAdd6)
|
GENERATE_PREDICTOR_ADD(Predictor6_C, PredictorAdd6_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor7, PredictorAdd7)
|
GENERATE_PREDICTOR_ADD(Predictor7_C, PredictorAdd7_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor8, PredictorAdd8)
|
GENERATE_PREDICTOR_ADD(Predictor8_C, PredictorAdd8_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor9, PredictorAdd9)
|
GENERATE_PREDICTOR_ADD(Predictor9_C, PredictorAdd9_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor10, PredictorAdd10)
|
GENERATE_PREDICTOR_ADD(Predictor10_C, PredictorAdd10_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor11, PredictorAdd11)
|
GENERATE_PREDICTOR_ADD(Predictor11_C, PredictorAdd11_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor12, PredictorAdd12)
|
GENERATE_PREDICTOR_ADD(Predictor12_C, PredictorAdd12_C)
|
||||||
GENERATE_PREDICTOR_ADD(Predictor13, PredictorAdd13)
|
GENERATE_PREDICTOR_ADD(Predictor13_C, PredictorAdd13_C)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Inverse prediction.
|
// Inverse prediction.
|
||||||
static void PredictorInverseTransform(const VP8LTransform* const transform,
|
static void PredictorInverseTransform_C(const VP8LTransform* const transform,
|
||||||
int y_start, int y_end,
|
int y_start, int y_end,
|
||||||
const uint32_t* in, uint32_t* out) {
|
const uint32_t* in, uint32_t* out) {
|
||||||
const int width = transform->xsize_;
|
const int width = transform->xsize_;
|
||||||
if (y_start == 0) { // First Row follows the L (mode=1) mode.
|
if (y_start == 0) { // First Row follows the L (mode=1) mode.
|
||||||
PredictorAdd0(in, NULL, 1, out);
|
PredictorAdd0_C(in, NULL, 1, out);
|
||||||
PredictorAdd1(in + 1, NULL, width - 1, out + 1);
|
PredictorAdd1_C(in + 1, NULL, width - 1, out + 1);
|
||||||
in += width;
|
in += width;
|
||||||
out += width;
|
out += width;
|
||||||
++y_start;
|
++y_start;
|
||||||
|
|
@ -217,7 +219,7 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
|
||||||
const uint32_t* pred_mode_src = pred_mode_base;
|
const uint32_t* pred_mode_src = pred_mode_base;
|
||||||
int x = 1;
|
int x = 1;
|
||||||
// First pixel follows the T (mode=2) mode.
|
// First pixel follows the T (mode=2) mode.
|
||||||
PredictorAdd2(in, out - width, 1, out);
|
PredictorAdd2_C(in, out - width, 1, out);
|
||||||
// .. the rest:
|
// .. the rest:
|
||||||
while (x < width) {
|
while (x < width) {
|
||||||
const VP8LPredictorAddSubFunc pred_func =
|
const VP8LPredictorAddSubFunc pred_func =
|
||||||
|
|
@ -272,8 +274,8 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
|
||||||
const uint32_t argb = src[i];
|
const uint32_t argb = src[i];
|
||||||
const uint32_t green = argb >> 8;
|
const uint32_t green = argb >> 8;
|
||||||
const uint32_t red = argb >> 16;
|
const uint32_t red = argb >> 16;
|
||||||
int new_red = red;
|
int new_red = red & 0xff;
|
||||||
int new_blue = argb;
|
int new_blue = argb & 0xff;
|
||||||
new_red += ColorTransformDelta(m->green_to_red_, green);
|
new_red += ColorTransformDelta(m->green_to_red_, green);
|
||||||
new_red &= 0xff;
|
new_red &= 0xff;
|
||||||
new_blue += ColorTransformDelta(m->green_to_blue_, green);
|
new_blue += ColorTransformDelta(m->green_to_blue_, green);
|
||||||
|
|
@ -284,9 +286,9 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color space inverse transform.
|
// Color space inverse transform.
|
||||||
static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
|
static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform,
|
||||||
int y_start, int y_end,
|
int y_start, int y_end,
|
||||||
const uint32_t* src, uint32_t* dst) {
|
const uint32_t* src, uint32_t* dst) {
|
||||||
const int width = transform->xsize_;
|
const int width = transform->xsize_;
|
||||||
const int tile_width = 1 << transform->bits_;
|
const int tile_width = 1 << transform->bits_;
|
||||||
const int mask = tile_width - 1;
|
const int mask = tile_width - 1;
|
||||||
|
|
@ -362,10 +364,10 @@ STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
COLOR_INDEX_INVERSE(ColorIndexInverseTransform, MapARGB, static, uint32_t, 32b,
|
COLOR_INDEX_INVERSE(ColorIndexInverseTransform_C, MapARGB_C, static,
|
||||||
VP8GetARGBIndex, VP8GetARGBValue)
|
uint32_t, 32b, VP8GetARGBIndex, VP8GetARGBValue)
|
||||||
COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha, , uint8_t,
|
COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, ,
|
||||||
8b, VP8GetAlphaIndex, VP8GetAlphaValue)
|
uint8_t, 8b, VP8GetAlphaIndex, VP8GetAlphaValue)
|
||||||
|
|
||||||
#undef COLOR_INDEX_INVERSE
|
#undef COLOR_INDEX_INVERSE
|
||||||
|
|
||||||
|
|
@ -380,7 +382,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
|
||||||
VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);
|
VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);
|
||||||
break;
|
break;
|
||||||
case PREDICTOR_TRANSFORM:
|
case PREDICTOR_TRANSFORM:
|
||||||
PredictorInverseTransform(transform, row_start, row_end, in, out);
|
PredictorInverseTransform_C(transform, row_start, row_end, in, out);
|
||||||
if (row_end != transform->ysize_) {
|
if (row_end != transform->ysize_) {
|
||||||
// The last predicted row in this iteration will be the top-pred row
|
// The last predicted row in this iteration will be the top-pred row
|
||||||
// for the first row in next iteration.
|
// for the first row in next iteration.
|
||||||
|
|
@ -389,7 +391,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CROSS_COLOR_TRANSFORM:
|
case CROSS_COLOR_TRANSFORM:
|
||||||
ColorSpaceInverseTransform(transform, row_start, row_end, in, out);
|
ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out);
|
||||||
break;
|
break;
|
||||||
case COLOR_INDEXING_TRANSFORM:
|
case COLOR_INDEXING_TRANSFORM:
|
||||||
if (in == out && transform->bits_ > 0) {
|
if (in == out && transform->bits_ > 0) {
|
||||||
|
|
@ -403,9 +405,9 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
|
||||||
VP8LSubSampleSize(transform->xsize_, transform->bits_);
|
VP8LSubSampleSize(transform->xsize_, transform->bits_);
|
||||||
uint32_t* const src = out + out_stride - in_stride;
|
uint32_t* const src = out + out_stride - in_stride;
|
||||||
memmove(src, out, in_stride * sizeof(*src));
|
memmove(src, out, in_stride * sizeof(*src));
|
||||||
ColorIndexInverseTransform(transform, row_start, row_end, src, out);
|
ColorIndexInverseTransform_C(transform, row_start, row_end, src, out);
|
||||||
} else {
|
} else {
|
||||||
ColorIndexInverseTransform(transform, row_start, row_end, in, out);
|
ColorIndexInverseTransform_C(transform, row_start, row_end, in, out);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -452,7 +454,7 @@ void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
|
||||||
const uint32_t argb = *src++;
|
const uint32_t argb = *src++;
|
||||||
const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
|
const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
|
||||||
const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
|
const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
*dst++ = ba;
|
*dst++ = ba;
|
||||||
*dst++ = rg;
|
*dst++ = rg;
|
||||||
#else
|
#else
|
||||||
|
|
@ -469,7 +471,7 @@ void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
|
||||||
const uint32_t argb = *src++;
|
const uint32_t argb = *src++;
|
||||||
const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
|
const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
|
||||||
const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
|
const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
*dst++ = gb;
|
*dst++ = gb;
|
||||||
*dst++ = rg;
|
*dst++ = rg;
|
||||||
#else
|
#else
|
||||||
|
|
@ -496,22 +498,7 @@ static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
|
||||||
const uint32_t* const src_end = src + num_pixels;
|
const uint32_t* const src_end = src + num_pixels;
|
||||||
while (src < src_end) {
|
while (src < src_end) {
|
||||||
const uint32_t argb = *src++;
|
const uint32_t argb = *src++;
|
||||||
|
|
||||||
#if !defined(WORDS_BIGENDIAN)
|
|
||||||
#if !defined(WEBP_REFERENCE_IMPLEMENTATION)
|
|
||||||
WebPUint32ToMem(dst, BSwap32(argb));
|
WebPUint32ToMem(dst, BSwap32(argb));
|
||||||
#else // WEBP_REFERENCE_IMPLEMENTATION
|
|
||||||
dst[0] = (argb >> 24) & 0xff;
|
|
||||||
dst[1] = (argb >> 16) & 0xff;
|
|
||||||
dst[2] = (argb >> 8) & 0xff;
|
|
||||||
dst[3] = (argb >> 0) & 0xff;
|
|
||||||
#endif
|
|
||||||
#else // WORDS_BIGENDIAN
|
|
||||||
dst[0] = (argb >> 0) & 0xff;
|
|
||||||
dst[1] = (argb >> 8) & 0xff;
|
|
||||||
dst[2] = (argb >> 16) & 0xff;
|
|
||||||
dst[3] = (argb >> 24) & 0xff;
|
|
||||||
#endif
|
|
||||||
dst += sizeof(argb);
|
dst += sizeof(argb);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -590,48 +577,46 @@ extern void VP8LDspInitNEON(void);
|
||||||
extern void VP8LDspInitMIPSdspR2(void);
|
extern void VP8LDspInitMIPSdspR2(void);
|
||||||
extern void VP8LDspInitMSA(void);
|
extern void VP8LDspInitMSA(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo lossless_last_cpuinfo_used =
|
#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \
|
||||||
(VP8CPUInfo)&lossless_last_cpuinfo_used;
|
(OUT)[0] = IN##0_C; \
|
||||||
|
(OUT)[1] = IN##1_C; \
|
||||||
#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \
|
(OUT)[2] = IN##2_C; \
|
||||||
(OUT)[0] = IN##0; \
|
(OUT)[3] = IN##3_C; \
|
||||||
(OUT)[1] = IN##1; \
|
(OUT)[4] = IN##4_C; \
|
||||||
(OUT)[2] = IN##2; \
|
(OUT)[5] = IN##5_C; \
|
||||||
(OUT)[3] = IN##3; \
|
(OUT)[6] = IN##6_C; \
|
||||||
(OUT)[4] = IN##4; \
|
(OUT)[7] = IN##7_C; \
|
||||||
(OUT)[5] = IN##5; \
|
(OUT)[8] = IN##8_C; \
|
||||||
(OUT)[6] = IN##6; \
|
(OUT)[9] = IN##9_C; \
|
||||||
(OUT)[7] = IN##7; \
|
(OUT)[10] = IN##10_C; \
|
||||||
(OUT)[8] = IN##8; \
|
(OUT)[11] = IN##11_C; \
|
||||||
(OUT)[9] = IN##9; \
|
(OUT)[12] = IN##12_C; \
|
||||||
(OUT)[10] = IN##10; \
|
(OUT)[13] = IN##13_C; \
|
||||||
(OUT)[11] = IN##11; \
|
(OUT)[14] = IN##0_C; /* <- padding security sentinels*/ \
|
||||||
(OUT)[12] = IN##12; \
|
(OUT)[15] = IN##0_C; \
|
||||||
(OUT)[13] = IN##13; \
|
|
||||||
(OUT)[14] = IN##0; /* <- padding security sentinels*/ \
|
|
||||||
(OUT)[15] = IN##0; \
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
|
WEBP_DSP_INIT_FUNC(VP8LDspInit) {
|
||||||
if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors)
|
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors)
|
||||||
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C)
|
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C)
|
||||||
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd)
|
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd)
|
||||||
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C)
|
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C)
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
|
VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
|
||||||
|
|
||||||
VP8LTransformColorInverse = VP8LTransformColorInverse_C;
|
VP8LTransformColorInverse = VP8LTransformColorInverse_C;
|
||||||
|
|
||||||
VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
|
|
||||||
VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
|
VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
|
||||||
|
VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
|
||||||
|
VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
|
VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
|
||||||
VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
|
VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
|
||||||
VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
|
|
||||||
|
|
||||||
VP8LMapColor32b = MapARGB;
|
VP8LMapColor32b = MapARGB_C;
|
||||||
VP8LMapColor8b = MapAlpha;
|
VP8LMapColor8b = MapAlpha_C;
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
|
|
@ -640,11 +625,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
|
||||||
VP8LDspInitSSE2();
|
VP8LDspInitSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
VP8LDspInitNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
||||||
VP8LDspInitMIPSdspR2();
|
VP8LDspInitMIPSdspR2();
|
||||||
|
|
@ -656,7 +636,23 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
lossless_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
VP8LDspInitNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(VP8LAddGreenToBlueAndRed != NULL);
|
||||||
|
assert(VP8LTransformColorInverse != NULL);
|
||||||
|
assert(VP8LConvertBGRAToRGBA != NULL);
|
||||||
|
assert(VP8LConvertBGRAToRGB != NULL);
|
||||||
|
assert(VP8LConvertBGRAToBGR != NULL);
|
||||||
|
assert(VP8LConvertBGRAToRGBA4444 != NULL);
|
||||||
|
assert(VP8LConvertBGRAToRGB565 != NULL);
|
||||||
|
assert(VP8LMapColor32b != NULL);
|
||||||
|
assert(VP8LMapColor8b != NULL);
|
||||||
}
|
}
|
||||||
#undef COPY_PREDICTOR_ARRAY
|
#undef COPY_PREDICTOR_ARRAY
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,6 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
|
||||||
#include "../enc/delta_palettization_enc.h"
|
|
||||||
#endif // WEBP_EXPERIMENTAL_FEATURES
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Decoding
|
// Decoding
|
||||||
|
|
||||||
|
|
@ -124,7 +120,7 @@ void VP8LDspInit(void);
|
||||||
typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels);
|
typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels);
|
||||||
extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
||||||
typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m,
|
typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m,
|
||||||
uint32_t* const dst, int num_pixels);
|
uint32_t* dst, int num_pixels);
|
||||||
extern VP8LTransformColorFunc VP8LTransformColor;
|
extern VP8LTransformColorFunc VP8LTransformColor;
|
||||||
typedef void (*VP8LCollectColorBlueTransformsFunc)(
|
typedef void (*VP8LCollectColorBlueTransformsFunc)(
|
||||||
const uint32_t* argb, int stride,
|
const uint32_t* argb, int stride,
|
||||||
|
|
|
||||||
|
|
@ -93,14 +93,6 @@ static WEBP_INLINE float VP8LFastSLog2(uint32_t v) {
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// PrefixEncode()
|
// PrefixEncode()
|
||||||
|
|
||||||
static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
|
|
||||||
const int log_floor = BitsLog2Floor(n);
|
|
||||||
if (n == (n & ~(n - 1))) { // zero or a power of two.
|
|
||||||
return log_floor;
|
|
||||||
}
|
|
||||||
return log_floor + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Splitting of distance and length codes into prefixes and
|
// Splitting of distance and length codes into prefixes and
|
||||||
// extra bits. The prefixes are encoded with an entropy code
|
// extra bits. The prefixes are encoded with an entropy code
|
||||||
// while the extra bits are stored just as normal bits.
|
// while the extra bits are stored just as normal bits.
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
|
|
||||||
#include "./lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
#include "./neon.h"
|
#include "../dsp/neon.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Colorspace conversion functions
|
// Colorspace conversion functions
|
||||||
|
|
@ -26,8 +26,8 @@
|
||||||
#if !defined(WORK_AROUND_GCC)
|
#if !defined(WORK_AROUND_GCC)
|
||||||
// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for
|
// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for
|
||||||
// gcc-4.8.x at least.
|
// gcc-4.8.x at least.
|
||||||
static void ConvertBGRAToRGBA(const uint32_t* src,
|
static void ConvertBGRAToRGBA_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~15);
|
const uint32_t* const end = src + (num_pixels & ~15);
|
||||||
for (; src < end; src += 16) {
|
for (; src < end; src += 16) {
|
||||||
uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
||||||
|
|
@ -41,8 +41,8 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
|
||||||
VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs
|
VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToBGR(const uint32_t* src,
|
static void ConvertBGRAToBGR_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~15);
|
const uint32_t* const end = src + (num_pixels & ~15);
|
||||||
for (; src < end; src += 16) {
|
for (; src < end; src += 16) {
|
||||||
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
||||||
|
|
@ -53,8 +53,8 @@ static void ConvertBGRAToBGR(const uint32_t* src,
|
||||||
VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs
|
VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToRGB(const uint32_t* src,
|
static void ConvertBGRAToRGB_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~15);
|
const uint32_t* const end = src + (num_pixels & ~15);
|
||||||
for (; src < end; src += 16) {
|
for (; src < end; src += 16) {
|
||||||
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
|
||||||
|
|
@ -71,8 +71,8 @@ static void ConvertBGRAToRGB(const uint32_t* src,
|
||||||
|
|
||||||
static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 };
|
static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 };
|
||||||
|
|
||||||
static void ConvertBGRAToRGBA(const uint32_t* src,
|
static void ConvertBGRAToRGBA_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~1);
|
const uint32_t* const end = src + (num_pixels & ~1);
|
||||||
const uint8x8_t shuffle = vld1_u8(kRGBAShuffle);
|
const uint8x8_t shuffle = vld1_u8(kRGBAShuffle);
|
||||||
for (; src < end; src += 2) {
|
for (; src < end; src += 2) {
|
||||||
|
|
@ -89,8 +89,8 @@ static const uint8_t kBGRShuffle[3][8] = {
|
||||||
{ 21, 22, 24, 25, 26, 28, 29, 30 }
|
{ 21, 22, 24, 25, 26, 28, 29, 30 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ConvertBGRAToBGR(const uint32_t* src,
|
static void ConvertBGRAToBGR_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~7);
|
const uint32_t* const end = src + (num_pixels & ~7);
|
||||||
const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]);
|
const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]);
|
||||||
const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]);
|
const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]);
|
||||||
|
|
@ -116,8 +116,8 @@ static const uint8_t kRGBShuffle[3][8] = {
|
||||||
{ 21, 20, 26, 25, 24, 30, 29, 28 }
|
{ 21, 20, 26, 25, 24, 30, 29, 28 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ConvertBGRAToRGB(const uint32_t* src,
|
static void ConvertBGRAToRGB_NEON(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~7);
|
const uint32_t* const end = src + (num_pixels & ~7);
|
||||||
const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]);
|
const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]);
|
||||||
const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]);
|
const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]);
|
||||||
|
|
@ -139,7 +139,6 @@ static void ConvertBGRAToRGB(const uint32_t* src,
|
||||||
|
|
||||||
#endif // !WORK_AROUND_GCC
|
#endif // !WORK_AROUND_GCC
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Predictor Transform
|
// Predictor Transform
|
||||||
|
|
||||||
|
|
@ -506,8 +505,8 @@ static const uint8_t kGreenShuffle[16] = {
|
||||||
1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
|
1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
|
||||||
};
|
};
|
||||||
|
|
||||||
static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
|
static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb,
|
||||||
const uint8x16_t shuffle) {
|
const uint8x16_t shuffle) {
|
||||||
return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
|
return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
|
||||||
vtbl1q_u8(argb, vget_high_u8(shuffle)));
|
vtbl1q_u8(argb, vget_high_u8(shuffle)));
|
||||||
}
|
}
|
||||||
|
|
@ -515,15 +514,15 @@ static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
|
||||||
// 255 = byte will be zeroed
|
// 255 = byte will be zeroed
|
||||||
static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
|
static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
|
||||||
|
|
||||||
static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
|
static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb,
|
||||||
const uint8x8_t shuffle) {
|
const uint8x8_t shuffle) {
|
||||||
return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
|
return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
|
||||||
vtbl1_u8(vget_high_u8(argb), shuffle));
|
vtbl1_u8(vget_high_u8(argb), shuffle));
|
||||||
}
|
}
|
||||||
#endif // USE_VTBLQ
|
#endif // USE_VTBLQ
|
||||||
|
|
||||||
static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
|
static void AddGreenToBlueAndRed_NEON(const uint32_t* src, int num_pixels,
|
||||||
uint32_t* dst) {
|
uint32_t* dst) {
|
||||||
const uint32_t* const end = src + (num_pixels & ~3);
|
const uint32_t* const end = src + (num_pixels & ~3);
|
||||||
#ifdef USE_VTBLQ
|
#ifdef USE_VTBLQ
|
||||||
const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
|
const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
|
||||||
|
|
@ -532,7 +531,7 @@ static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
|
||||||
#endif
|
#endif
|
||||||
for (; src < end; src += 4, dst += 4) {
|
for (; src < end; src += 4, dst += 4) {
|
||||||
const uint8x16_t argb = vld1q_u8((const uint8_t*)src);
|
const uint8x16_t argb = vld1q_u8((const uint8_t*)src);
|
||||||
const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
|
const uint8x16_t greens = DoGreenShuffle_NEON(argb, shuffle);
|
||||||
vst1q_u8((uint8_t*)dst, vaddq_u8(argb, greens));
|
vst1q_u8((uint8_t*)dst, vaddq_u8(argb, greens));
|
||||||
}
|
}
|
||||||
// fallthrough and finish off with plain-C
|
// fallthrough and finish off with plain-C
|
||||||
|
|
@ -542,9 +541,9 @@ static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Color Transform
|
// Color Transform
|
||||||
|
|
||||||
static void TransformColorInverse(const VP8LMultipliers* const m,
|
static void TransformColorInverse_NEON(const VP8LMultipliers* const m,
|
||||||
const uint32_t* const src, int num_pixels,
|
const uint32_t* const src,
|
||||||
uint32_t* dst) {
|
int num_pixels, uint32_t* dst) {
|
||||||
// sign-extended multiplying constants, pre-shifted by 6.
|
// sign-extended multiplying constants, pre-shifted by 6.
|
||||||
#define CST(X) (((int16_t)(m->X << 8)) >> 6)
|
#define CST(X) (((int16_t)(m->X << 8)) >> 6)
|
||||||
const int16_t rb[8] = {
|
const int16_t rb[8] = {
|
||||||
|
|
@ -575,7 +574,7 @@ static void TransformColorInverse(const VP8LMultipliers* const m,
|
||||||
const uint8x16_t in = vld1q_u8((const uint8_t*)(src + i));
|
const uint8x16_t in = vld1q_u8((const uint8_t*)(src + i));
|
||||||
const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag);
|
const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag);
|
||||||
// 0 g 0 g
|
// 0 g 0 g
|
||||||
const uint8x16_t greens = DoGreenShuffle(in, shuffle);
|
const uint8x16_t greens = DoGreenShuffle_NEON(in, shuffle);
|
||||||
// x dr x db1
|
// x dr x db1
|
||||||
const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb);
|
const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb);
|
||||||
// x r' x b'
|
// x r' x b'
|
||||||
|
|
@ -627,12 +626,12 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitNEON(void) {
|
||||||
VP8LPredictorsAdd[12] = PredictorAdd12_NEON;
|
VP8LPredictorsAdd[12] = PredictorAdd12_NEON;
|
||||||
VP8LPredictorsAdd[13] = PredictorAdd13_NEON;
|
VP8LPredictorsAdd[13] = PredictorAdd13_NEON;
|
||||||
|
|
||||||
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
|
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_NEON;
|
||||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
|
VP8LConvertBGRAToBGR = ConvertBGRAToBGR_NEON;
|
||||||
VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
|
VP8LConvertBGRAToRGB = ConvertBGRAToRGB_NEON;
|
||||||
|
|
||||||
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
|
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_NEON;
|
||||||
VP8LTransformColorInverse = TransformColorInverse;
|
VP8LTransformColorInverse = TransformColorInverse_NEON;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_NEON
|
#else // !WEBP_USE_NEON
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,22 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
#include "./common_sse2.h"
|
#include "../dsp/common_sse2.h"
|
||||||
#include "./lossless.h"
|
#include "../dsp/lossless.h"
|
||||||
#include "./lossless_common.h"
|
#include "../dsp/lossless_common.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Predictor Transform
|
// Predictor Transform
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
|
static WEBP_INLINE uint32_t ClampedAddSubtractFull_SSE2(uint32_t c0,
|
||||||
uint32_t c2) {
|
uint32_t c1,
|
||||||
|
uint32_t c2) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
|
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
|
||||||
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
|
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
|
||||||
|
|
@ -37,8 +38,9 @@ static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
|
static WEBP_INLINE uint32_t ClampedAddSubtractHalf_SSE2(uint32_t c0,
|
||||||
uint32_t c2) {
|
uint32_t c1,
|
||||||
|
uint32_t c2) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
|
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
|
||||||
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
|
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
|
||||||
|
|
@ -55,7 +57,7 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
|
static WEBP_INLINE uint32_t Select_SSE2(uint32_t a, uint32_t b, uint32_t c) {
|
||||||
int pa_minus_pb;
|
int pa_minus_pb;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i A0 = _mm_cvtsi32_si128(a);
|
const __m128i A0 = _mm_cvtsi32_si128(a);
|
||||||
|
|
@ -88,8 +90,9 @@ static WEBP_INLINE void Average2_m128i(const __m128i* const a0,
|
||||||
*avg = _mm_sub_epi8(avg1, one);
|
*avg = _mm_sub_epi8(avg1, one);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1,
|
static WEBP_INLINE void Average2_uint32_SSE2(const uint32_t a0,
|
||||||
__m128i* const avg) {
|
const uint32_t a1,
|
||||||
|
__m128i* const avg) {
|
||||||
// (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
|
// (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
|
||||||
const __m128i ones = _mm_set1_epi8(1);
|
const __m128i ones = _mm_set1_epi8(1);
|
||||||
const __m128i A0 = _mm_cvtsi32_si128(a0);
|
const __m128i A0 = _mm_cvtsi32_si128(a0);
|
||||||
|
|
@ -99,7 +102,7 @@ static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1,
|
||||||
*avg = _mm_sub_epi8(avg1, one);
|
*avg = _mm_sub_epi8(avg1, one);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) {
|
static WEBP_INLINE __m128i Average2_uint32_16_SSE2(uint32_t a0, uint32_t a1) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
|
const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
|
||||||
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
|
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
|
||||||
|
|
@ -107,15 +110,16 @@ static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) {
|
||||||
return _mm_srli_epi16(sum, 1);
|
return _mm_srli_epi16(sum, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
|
static WEBP_INLINE uint32_t Average2_SSE2(uint32_t a0, uint32_t a1) {
|
||||||
__m128i output;
|
__m128i output;
|
||||||
Average2_uint32(a0, a1, &output);
|
Average2_uint32_SSE2(a0, a1, &output);
|
||||||
return _mm_cvtsi128_si32(output);
|
return _mm_cvtsi128_si32(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
|
static WEBP_INLINE uint32_t Average3_SSE2(uint32_t a0, uint32_t a1,
|
||||||
|
uint32_t a2) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i avg1 = Average2_uint32_16(a0, a2);
|
const __m128i avg1 = Average2_uint32_16_SSE2(a0, a2);
|
||||||
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
|
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
|
||||||
const __m128i sum = _mm_add_epi16(avg1, A1);
|
const __m128i sum = _mm_add_epi16(avg1, A1);
|
||||||
const __m128i avg2 = _mm_srli_epi16(sum, 1);
|
const __m128i avg2 = _mm_srli_epi16(sum, 1);
|
||||||
|
|
@ -124,10 +128,10 @@ static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
|
static WEBP_INLINE uint32_t Average4_SSE2(uint32_t a0, uint32_t a1,
|
||||||
uint32_t a2, uint32_t a3) {
|
uint32_t a2, uint32_t a3) {
|
||||||
const __m128i avg1 = Average2_uint32_16(a0, a1);
|
const __m128i avg1 = Average2_uint32_16_SSE2(a0, a1);
|
||||||
const __m128i avg2 = Average2_uint32_16(a2, a3);
|
const __m128i avg2 = Average2_uint32_16_SSE2(a2, a3);
|
||||||
const __m128i sum = _mm_add_epi16(avg2, avg1);
|
const __m128i sum = _mm_add_epi16(avg2, avg1);
|
||||||
const __m128i avg3 = _mm_srli_epi16(sum, 1);
|
const __m128i avg3 = _mm_srli_epi16(sum, 1);
|
||||||
const __m128i A0 = _mm_packus_epi16(avg3, avg3);
|
const __m128i A0 = _mm_packus_epi16(avg3, avg3);
|
||||||
|
|
@ -136,41 +140,41 @@ static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t Predictor5_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor5_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average3(left, top[0], top[1]);
|
const uint32_t pred = Average3_SSE2(left, top[0], top[1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor6_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor6_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(left, top[-1]);
|
const uint32_t pred = Average2_SSE2(left, top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor7_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor7_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(left, top[0]);
|
const uint32_t pred = Average2_SSE2(left, top[0]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor8_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor8_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(top[-1], top[0]);
|
const uint32_t pred = Average2_SSE2(top[-1], top[0]);
|
||||||
(void)left;
|
(void)left;
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor9_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor9_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average2(top[0], top[1]);
|
const uint32_t pred = Average2_SSE2(top[0], top[1]);
|
||||||
(void)left;
|
(void)left;
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor10_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor10_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
|
const uint32_t pred = Average4_SSE2(left, top[-1], top[0], top[1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor11_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor11_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = Select(top[0], left, top[-1]);
|
const uint32_t pred = Select_SSE2(top[0], left, top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor12_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor12_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
|
const uint32_t pred = ClampedAddSubtractFull_SSE2(left, top[0], top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
static uint32_t Predictor13_SSE2(uint32_t left, const uint32_t* const top) {
|
static uint32_t Predictor13_SSE2(uint32_t left, const uint32_t* const top) {
|
||||||
const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
|
const uint32_t pred = ClampedAddSubtractHalf_SSE2(left, top[0], top[-1]);
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,9 +276,24 @@ GENERATE_PREDICTOR_2(9, upper[i + 1])
|
||||||
#undef GENERATE_PREDICTOR_2
|
#undef GENERATE_PREDICTOR_2
|
||||||
|
|
||||||
// Predictor10: average of (average of (L,TL), average of (T, TR)).
|
// Predictor10: average of (average of (L,TL), average of (T, TR)).
|
||||||
|
#define DO_PRED10(OUT) do { \
|
||||||
|
__m128i avgLTL, avg; \
|
||||||
|
Average2_m128i(&L, &TL, &avgLTL); \
|
||||||
|
Average2_m128i(&avgTTR, &avgLTL, &avg); \
|
||||||
|
L = _mm_add_epi8(avg, src); \
|
||||||
|
out[i + (OUT)] = _mm_cvtsi128_si32(L); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DO_PRED10_SHIFT do { \
|
||||||
|
/* Rotate the pre-computed values for the next iteration.*/ \
|
||||||
|
avgTTR = _mm_srli_si128(avgTTR, 4); \
|
||||||
|
TL = _mm_srli_si128(TL, 4); \
|
||||||
|
src = _mm_srli_si128(src, 4); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
|
static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
|
||||||
int num_pixels, uint32_t* out) {
|
int num_pixels, uint32_t* out) {
|
||||||
int i, j;
|
int i;
|
||||||
__m128i L = _mm_cvtsi32_si128(out[-1]);
|
__m128i L = _mm_cvtsi32_si128(out[-1]);
|
||||||
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
||||||
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
|
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
|
||||||
|
|
@ -283,79 +302,90 @@ static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
|
||||||
const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]);
|
const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]);
|
||||||
__m128i avgTTR;
|
__m128i avgTTR;
|
||||||
Average2_m128i(&T, &TR, &avgTTR);
|
Average2_m128i(&T, &TR, &avgTTR);
|
||||||
for (j = 0; j < 4; ++j) {
|
DO_PRED10(0);
|
||||||
__m128i avgLTL, avg;
|
DO_PRED10_SHIFT;
|
||||||
Average2_m128i(&L, &TL, &avgLTL);
|
DO_PRED10(1);
|
||||||
Average2_m128i(&avgTTR, &avgLTL, &avg);
|
DO_PRED10_SHIFT;
|
||||||
L = _mm_add_epi8(avg, src);
|
DO_PRED10(2);
|
||||||
out[i + j] = _mm_cvtsi128_si32(L);
|
DO_PRED10_SHIFT;
|
||||||
// Rotate the pre-computed values for the next iteration.
|
DO_PRED10(3);
|
||||||
avgTTR = _mm_srli_si128(avgTTR, 4);
|
|
||||||
TL = _mm_srli_si128(TL, 4);
|
|
||||||
src = _mm_srli_si128(src, 4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (i != num_pixels) {
|
if (i != num_pixels) {
|
||||||
VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i);
|
VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef DO_PRED10
|
||||||
|
#undef DO_PRED10_SHIFT
|
||||||
|
|
||||||
// Predictor11: select.
|
// Predictor11: select.
|
||||||
static void GetSumAbsDiff32(const __m128i* const A, const __m128i* const B,
|
#define DO_PRED11(OUT) do { \
|
||||||
__m128i* const out) {
|
const __m128i L_lo = _mm_unpacklo_epi32(L, T); \
|
||||||
// We can unpack with any value on the upper 32 bits, provided it's the same
|
const __m128i TL_lo = _mm_unpacklo_epi32(TL, T); \
|
||||||
// on both operands (to that their sum of abs diff is zero). Here we use *A.
|
const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/ \
|
||||||
const __m128i A_lo = _mm_unpacklo_epi32(*A, *A);
|
const __m128i mask = _mm_cmpgt_epi32(pb, pa); \
|
||||||
const __m128i B_lo = _mm_unpacklo_epi32(*B, *A);
|
const __m128i A = _mm_and_si128(mask, L); \
|
||||||
const __m128i A_hi = _mm_unpackhi_epi32(*A, *A);
|
const __m128i B = _mm_andnot_si128(mask, T); \
|
||||||
const __m128i B_hi = _mm_unpackhi_epi32(*B, *A);
|
const __m128i pred = _mm_or_si128(A, B); /* pred = (pa > b)? L : T*/ \
|
||||||
const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo);
|
L = _mm_add_epi8(src, pred); \
|
||||||
const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi);
|
out[i + (OUT)] = _mm_cvtsi128_si32(L); \
|
||||||
*out = _mm_packs_epi32(s_lo, s_hi);
|
} while (0)
|
||||||
}
|
|
||||||
|
#define DO_PRED11_SHIFT do { \
|
||||||
|
/* Shift the pre-computed value for the next iteration.*/ \
|
||||||
|
T = _mm_srli_si128(T, 4); \
|
||||||
|
TL = _mm_srli_si128(TL, 4); \
|
||||||
|
src = _mm_srli_si128(src, 4); \
|
||||||
|
pa = _mm_srli_si128(pa, 4); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper,
|
static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper,
|
||||||
int num_pixels, uint32_t* out) {
|
int num_pixels, uint32_t* out) {
|
||||||
int i, j;
|
int i;
|
||||||
|
__m128i pa;
|
||||||
__m128i L = _mm_cvtsi32_si128(out[-1]);
|
__m128i L = _mm_cvtsi32_si128(out[-1]);
|
||||||
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
||||||
__m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
|
__m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
|
||||||
__m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
|
__m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
|
||||||
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
|
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
|
||||||
__m128i pa;
|
{
|
||||||
GetSumAbsDiff32(&T, &TL, &pa); // pa = sum |T-TL|
|
// We can unpack with any value on the upper 32 bits, provided it's the
|
||||||
for (j = 0; j < 4; ++j) {
|
// same on both operands (so that their sum of abs diff is zero). Here we
|
||||||
const __m128i L_lo = _mm_unpacklo_epi32(L, L);
|
// use T.
|
||||||
const __m128i TL_lo = _mm_unpacklo_epi32(TL, L);
|
const __m128i T_lo = _mm_unpacklo_epi32(T, T);
|
||||||
const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); // pb = sum |L-TL|
|
const __m128i TL_lo = _mm_unpacklo_epi32(TL, T);
|
||||||
const __m128i mask = _mm_cmpgt_epi32(pb, pa);
|
const __m128i T_hi = _mm_unpackhi_epi32(T, T);
|
||||||
const __m128i A = _mm_and_si128(mask, L);
|
const __m128i TL_hi = _mm_unpackhi_epi32(TL, T);
|
||||||
const __m128i B = _mm_andnot_si128(mask, T);
|
const __m128i s_lo = _mm_sad_epu8(T_lo, TL_lo);
|
||||||
const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T
|
const __m128i s_hi = _mm_sad_epu8(T_hi, TL_hi);
|
||||||
L = _mm_add_epi8(src, pred);
|
pa = _mm_packs_epi32(s_lo, s_hi); // pa = sum |T-TL|
|
||||||
out[i + j] = _mm_cvtsi128_si32(L);
|
|
||||||
// Shift the pre-computed value for the next iteration.
|
|
||||||
T = _mm_srli_si128(T, 4);
|
|
||||||
TL = _mm_srli_si128(TL, 4);
|
|
||||||
src = _mm_srli_si128(src, 4);
|
|
||||||
pa = _mm_srli_si128(pa, 4);
|
|
||||||
}
|
}
|
||||||
|
DO_PRED11(0);
|
||||||
|
DO_PRED11_SHIFT;
|
||||||
|
DO_PRED11(1);
|
||||||
|
DO_PRED11_SHIFT;
|
||||||
|
DO_PRED11(2);
|
||||||
|
DO_PRED11_SHIFT;
|
||||||
|
DO_PRED11(3);
|
||||||
}
|
}
|
||||||
if (i != num_pixels) {
|
if (i != num_pixels) {
|
||||||
VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i);
|
VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef DO_PRED11
|
||||||
|
#undef DO_PRED11_SHIFT
|
||||||
|
|
||||||
// Predictor12: ClampedAddSubtractFull.
|
// Predictor12: ClampedAddSubtractFull.
|
||||||
#define DO_PRED12(DIFF, LANE, OUT) \
|
#define DO_PRED12(DIFF, LANE, OUT) do { \
|
||||||
do { \
|
const __m128i all = _mm_add_epi16(L, (DIFF)); \
|
||||||
const __m128i all = _mm_add_epi16(L, (DIFF)); \
|
const __m128i alls = _mm_packus_epi16(all, all); \
|
||||||
const __m128i alls = _mm_packus_epi16(all, all); \
|
const __m128i res = _mm_add_epi8(src, alls); \
|
||||||
const __m128i res = _mm_add_epi8(src, alls); \
|
out[i + (OUT)] = _mm_cvtsi128_si32(res); \
|
||||||
out[i + (OUT)] = _mm_cvtsi128_si32(res); \
|
L = _mm_unpacklo_epi8(res, zero); \
|
||||||
L = _mm_unpacklo_epi8(res, zero); \
|
} while (0)
|
||||||
|
|
||||||
|
#define DO_PRED12_SHIFT(DIFF, LANE) do { \
|
||||||
/* Shift the pre-computed value for the next iteration.*/ \
|
/* Shift the pre-computed value for the next iteration.*/ \
|
||||||
if (LANE == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \
|
if ((LANE) == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \
|
||||||
src = _mm_srli_si128(src, 4); \
|
src = _mm_srli_si128(src, 4); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
@ -377,8 +407,11 @@ static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper,
|
||||||
__m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo);
|
__m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo);
|
||||||
__m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi);
|
__m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi);
|
||||||
DO_PRED12(diff_lo, 0, 0);
|
DO_PRED12(diff_lo, 0, 0);
|
||||||
|
DO_PRED12_SHIFT(diff_lo, 0);
|
||||||
DO_PRED12(diff_lo, 1, 1);
|
DO_PRED12(diff_lo, 1, 1);
|
||||||
|
DO_PRED12_SHIFT(diff_lo, 1);
|
||||||
DO_PRED12(diff_hi, 0, 2);
|
DO_PRED12(diff_hi, 0, 2);
|
||||||
|
DO_PRED12_SHIFT(diff_hi, 0);
|
||||||
DO_PRED12(diff_hi, 1, 3);
|
DO_PRED12(diff_hi, 1, 3);
|
||||||
}
|
}
|
||||||
if (i != num_pixels) {
|
if (i != num_pixels) {
|
||||||
|
|
@ -386,6 +419,7 @@ static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef DO_PRED12
|
#undef DO_PRED12
|
||||||
|
#undef DO_PRED12_SHIFT
|
||||||
|
|
||||||
// Due to averages with integers, values cannot be accumulated in parallel for
|
// Due to averages with integers, values cannot be accumulated in parallel for
|
||||||
// predictors 13.
|
// predictors 13.
|
||||||
|
|
@ -394,8 +428,8 @@ GENERATE_PREDICTOR_ADD(Predictor13_SSE2, PredictorAdd13_SSE2)
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Subtract-Green Transform
|
// Subtract-Green Transform
|
||||||
|
|
||||||
static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels,
|
static void AddGreenToBlueAndRed_SSE2(const uint32_t* const src, int num_pixels,
|
||||||
uint32_t* dst) {
|
uint32_t* dst) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
for (i = 0; i + 4 <= num_pixels; i += 4) {
|
||||||
const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
|
const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
|
||||||
|
|
@ -414,19 +448,16 @@ static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Color Transform
|
// Color Transform
|
||||||
|
|
||||||
static void TransformColorInverse(const VP8LMultipliers* const m,
|
static void TransformColorInverse_SSE2(const VP8LMultipliers* const m,
|
||||||
const uint32_t* const src, int num_pixels,
|
const uint32_t* const src,
|
||||||
uint32_t* dst) {
|
int num_pixels, uint32_t* dst) {
|
||||||
// sign-extended multiplying constants, pre-shifted by 5.
|
// sign-extended multiplying constants, pre-shifted by 5.
|
||||||
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
|
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
|
||||||
const __m128i mults_rb = _mm_set_epi16(
|
#define MK_CST_16(HI, LO) \
|
||||||
CST(green_to_red_), CST(green_to_blue_),
|
_mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
|
||||||
CST(green_to_red_), CST(green_to_blue_),
|
const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_));
|
||||||
CST(green_to_red_), CST(green_to_blue_),
|
const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0);
|
||||||
CST(green_to_red_), CST(green_to_blue_));
|
#undef MK_CST_16
|
||||||
const __m128i mults_b2 = _mm_set_epi16(
|
|
||||||
CST(red_to_blue_), 0, CST(red_to_blue_), 0,
|
|
||||||
CST(red_to_blue_), 0, CST(red_to_blue_), 0);
|
|
||||||
#undef CST
|
#undef CST
|
||||||
const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
|
const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -454,8 +485,8 @@ static void TransformColorInverse(const VP8LMultipliers* const m,
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Color-space conversion functions
|
// Color-space conversion functions
|
||||||
|
|
||||||
static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
|
static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
const __m128i* in = (const __m128i*)src;
|
const __m128i* in = (const __m128i*)src;
|
||||||
__m128i* out = (__m128i*)dst;
|
__m128i* out = (__m128i*)dst;
|
||||||
|
|
||||||
|
|
@ -469,11 +500,11 @@ static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
|
||||||
__m128i in5 = _mm_loadu_si128(in + 5);
|
__m128i in5 = _mm_loadu_si128(in + 5);
|
||||||
__m128i in6 = _mm_loadu_si128(in + 6);
|
__m128i in6 = _mm_loadu_si128(in + 6);
|
||||||
__m128i in7 = _mm_loadu_si128(in + 7);
|
__m128i in7 = _mm_loadu_si128(in + 7);
|
||||||
VP8L32bToPlanar(&in0, &in1, &in2, &in3);
|
VP8L32bToPlanar_SSE2(&in0, &in1, &in2, &in3);
|
||||||
VP8L32bToPlanar(&in4, &in5, &in6, &in7);
|
VP8L32bToPlanar_SSE2(&in4, &in5, &in6, &in7);
|
||||||
// At this points, in1/in5 contains red only, in2/in6 green only ...
|
// At this points, in1/in5 contains red only, in2/in6 green only ...
|
||||||
// Pack the colors in 24b RGB.
|
// Pack the colors in 24b RGB.
|
||||||
VP8PlanarTo24b(&in1, &in5, &in2, &in6, &in3, &in7);
|
VP8PlanarTo24b_SSE2(&in1, &in5, &in2, &in6, &in3, &in7);
|
||||||
_mm_storeu_si128(out + 0, in1);
|
_mm_storeu_si128(out + 0, in1);
|
||||||
_mm_storeu_si128(out + 1, in5);
|
_mm_storeu_si128(out + 1, in5);
|
||||||
_mm_storeu_si128(out + 2, in2);
|
_mm_storeu_si128(out + 2, in2);
|
||||||
|
|
@ -490,27 +521,26 @@ static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToRGBA(const uint32_t* src,
|
static void ConvertBGRAToRGBA_SSE2(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
|
const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ffu);
|
||||||
const __m128i* in = (const __m128i*)src;
|
const __m128i* in = (const __m128i*)src;
|
||||||
__m128i* out = (__m128i*)dst;
|
__m128i* out = (__m128i*)dst;
|
||||||
while (num_pixels >= 8) {
|
while (num_pixels >= 8) {
|
||||||
const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
|
const __m128i A1 = _mm_loadu_si128(in++);
|
||||||
const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
|
const __m128i A2 = _mm_loadu_si128(in++);
|
||||||
const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
|
const __m128i B1 = _mm_and_si128(A1, red_blue_mask); // R 0 B 0
|
||||||
const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
|
const __m128i B2 = _mm_and_si128(A2, red_blue_mask); // R 0 B 0
|
||||||
const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
|
const __m128i C1 = _mm_andnot_si128(red_blue_mask, A1); // 0 G 0 A
|
||||||
const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
|
const __m128i C2 = _mm_andnot_si128(red_blue_mask, A2); // 0 G 0 A
|
||||||
const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
|
const __m128i D1 = _mm_shufflelo_epi16(B1, _MM_SHUFFLE(2, 3, 0, 1));
|
||||||
const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
|
const __m128i D2 = _mm_shufflelo_epi16(B2, _MM_SHUFFLE(2, 3, 0, 1));
|
||||||
const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
|
const __m128i E1 = _mm_shufflehi_epi16(D1, _MM_SHUFFLE(2, 3, 0, 1));
|
||||||
const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
|
const __m128i E2 = _mm_shufflehi_epi16(D2, _MM_SHUFFLE(2, 3, 0, 1));
|
||||||
const __m128i rg0 = _mm_unpacklo_epi8(rb0, ga0); // r0g0r1g1 ... r6g6r7g7
|
const __m128i F1 = _mm_or_si128(E1, C1);
|
||||||
const __m128i ba0 = _mm_unpackhi_epi8(rb0, ga0); // b0a0b1a1 ... b6a6b7a7
|
const __m128i F2 = _mm_or_si128(E2, C2);
|
||||||
const __m128i rgba0 = _mm_unpacklo_epi16(rg0, ba0); // rgba0|rgba1...
|
_mm_storeu_si128(out++, F1);
|
||||||
const __m128i rgba4 = _mm_unpackhi_epi16(rg0, ba0); // rgba4|rgba5...
|
_mm_storeu_si128(out++, F2);
|
||||||
_mm_storeu_si128(out++, rgba0);
|
|
||||||
_mm_storeu_si128(out++, rgba4);
|
|
||||||
num_pixels -= 8;
|
num_pixels -= 8;
|
||||||
}
|
}
|
||||||
// left-overs
|
// left-overs
|
||||||
|
|
@ -519,8 +549,8 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToRGBA4444(const uint32_t* src,
|
static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
|
const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
|
||||||
const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
|
const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
|
||||||
const __m128i* in = (const __m128i*)src;
|
const __m128i* in = (const __m128i*)src;
|
||||||
|
|
@ -541,7 +571,7 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src,
|
||||||
const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7-
|
const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7-
|
||||||
const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7
|
const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7
|
||||||
const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0
|
const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7
|
const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7
|
||||||
#else
|
#else
|
||||||
const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7
|
const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7
|
||||||
|
|
@ -555,8 +585,8 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToRGB565(const uint32_t* src,
|
static void ConvertBGRAToRGB565_SSE2(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
|
const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
|
||||||
const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
|
const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
|
||||||
const __m128i mask_0x07 = _mm_set1_epi8(0x07);
|
const __m128i mask_0x07 = _mm_set1_epi8(0x07);
|
||||||
|
|
@ -582,7 +612,7 @@ static void ConvertBGRAToRGB565(const uint32_t* src,
|
||||||
const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx
|
const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx
|
||||||
const __m128i b1 = _mm_srli_epi16(b0, 3);
|
const __m128i b1 = _mm_srli_epi16(b0, 3);
|
||||||
const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx
|
const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7
|
const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7
|
||||||
#else
|
#else
|
||||||
const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7
|
const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7
|
||||||
|
|
@ -596,8 +626,8 @@ static void ConvertBGRAToRGB565(const uint32_t* src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGRAToBGR(const uint32_t* src,
|
static void ConvertBGRAToBGR_SSE2(const uint32_t* src,
|
||||||
int num_pixels, uint8_t* dst) {
|
int num_pixels, uint8_t* dst) {
|
||||||
const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
|
const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
|
||||||
const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
|
const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
|
||||||
const __m128i* in = (const __m128i*)src;
|
const __m128i* in = (const __m128i*)src;
|
||||||
|
|
@ -660,14 +690,14 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) {
|
||||||
VP8LPredictorsAdd[12] = PredictorAdd12_SSE2;
|
VP8LPredictorsAdd[12] = PredictorAdd12_SSE2;
|
||||||
VP8LPredictorsAdd[13] = PredictorAdd13_SSE2;
|
VP8LPredictorsAdd[13] = PredictorAdd13_SSE2;
|
||||||
|
|
||||||
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
|
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_SSE2;
|
||||||
VP8LTransformColorInverse = TransformColorInverse;
|
VP8LTransformColorInverse = TransformColorInverse_SSE2;
|
||||||
|
|
||||||
VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
|
VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE2;
|
||||||
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
|
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_SSE2;
|
||||||
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
|
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_SSE2;
|
||||||
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
|
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_SSE2;
|
||||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
|
VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE2
|
#else // !WEBP_USE_SSE2
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CLANG_BUILD
|
#ifdef CLANG_BUILD
|
||||||
|
#define ALPHAVAL (-1)
|
||||||
#define ADDVI_H(a, b) __msa_addvi_h((v8i16)a, b)
|
#define ADDVI_H(a, b) __msa_addvi_h((v8i16)a, b)
|
||||||
#define ADDVI_W(a, b) __msa_addvi_w((v4i32)a, b)
|
#define ADDVI_W(a, b) __msa_addvi_w((v4i32)a, b)
|
||||||
#define SRAI_B(a, b) __msa_srai_b((v16i8)a, b)
|
#define SRAI_B(a, b) __msa_srai_b((v16i8)a, b)
|
||||||
|
|
@ -32,6 +33,7 @@
|
||||||
#define ANDI_B(a, b) __msa_andi_b((v16u8)a, b)
|
#define ANDI_B(a, b) __msa_andi_b((v16u8)a, b)
|
||||||
#define ORI_B(a, b) __msa_ori_b((v16u8)a, b)
|
#define ORI_B(a, b) __msa_ori_b((v16u8)a, b)
|
||||||
#else
|
#else
|
||||||
|
#define ALPHAVAL (0xff)
|
||||||
#define ADDVI_H(a, b) (a + b)
|
#define ADDVI_H(a, b) (a + b)
|
||||||
#define ADDVI_W(a, b) (a + b)
|
#define ADDVI_W(a, b) (a + b)
|
||||||
#define SRAI_B(a, b) (a >> b)
|
#define SRAI_B(a, b) (a >> b)
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,12 @@
|
||||||
|
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
// Right now, some intrinsics functions seem slower, so we disable them
|
// Right now, some intrinsics functions seem slower, so we disable them
|
||||||
// everywhere except aarch64 where the inline assembly is incompatible.
|
// everywhere except newer clang/gcc or aarch64 where the inline assembly is
|
||||||
#if defined(__aarch64__)
|
// incompatible.
|
||||||
|
#if LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,9) || defined(__aarch64__)
|
||||||
#define WEBP_USE_INTRINSICS // use intrinsics when possible
|
#define WEBP_USE_INTRINSICS // use intrinsics when possible
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -43,11 +44,11 @@
|
||||||
// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
|
// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
|
||||||
// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
|
// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
|
||||||
// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
|
// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
|
||||||
#if !(LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
|
#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
|
||||||
#define WORK_AROUND_GCC
|
#define WORK_AROUND_GCC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static WEBP_INLINE int32x4x4_t Transpose4x4(const int32x4x4_t rows) {
|
static WEBP_INLINE int32x4x4_t Transpose4x4_NEON(const int32x4x4_t rows) {
|
||||||
uint64x2x2_t row01, row23;
|
uint64x2x2_t row01, row23;
|
||||||
|
|
||||||
row01.val[0] = vreinterpretq_u64_s32(rows.val[0]);
|
row01.val[0] = vreinterpretq_u64_s32(rows.val[0]);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../utils/rescaler_utils.h"
|
#include "../utils/rescaler_utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -25,7 +25,8 @@
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Row import
|
// Row import
|
||||||
|
|
||||||
void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
|
void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
|
||||||
|
const uint8_t* src) {
|
||||||
const int x_stride = wrk->num_channels;
|
const int x_stride = wrk->num_channels;
|
||||||
const int x_out_max = wrk->dst_width * wrk->num_channels;
|
const int x_out_max = wrk->dst_width * wrk->num_channels;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
@ -56,7 +57,8 @@ void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
|
void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
|
||||||
|
const uint8_t* src) {
|
||||||
const int x_stride = wrk->num_channels;
|
const int x_stride = wrk->num_channels;
|
||||||
const int x_out_max = wrk->dst_width * wrk->num_channels;
|
const int x_out_max = wrk->dst_width * wrk->num_channels;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
@ -92,7 +94,7 @@ void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Row export
|
// Row export
|
||||||
|
|
||||||
void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
|
void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -123,7 +125,7 @@ void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) {
|
void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -202,16 +204,15 @@ extern void WebPRescalerDspInitMIPSdspR2(void);
|
||||||
extern void WebPRescalerDspInitMSA(void);
|
extern void WebPRescalerDspInitMSA(void);
|
||||||
extern void WebPRescalerDspInitNEON(void);
|
extern void WebPRescalerDspInitNEON(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
|
WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
|
||||||
(VP8CPUInfo)&rescaler_last_cpuinfo_used;
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
|
WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
|
||||||
|
WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
|
WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
|
||||||
if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
|
WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
|
||||||
|
|
||||||
WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
|
|
||||||
WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
|
|
||||||
WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
|
|
||||||
WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
|
|
||||||
|
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
@ -219,11 +220,6 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
|
||||||
WebPRescalerDspInitSSE2();
|
WebPRescalerDspInitSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
|
||||||
WebPRescalerDspInitNEON();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBP_USE_MIPS32)
|
#if defined(WEBP_USE_MIPS32)
|
||||||
if (VP8GetCPUInfo(kMIPS32)) {
|
if (VP8GetCPUInfo(kMIPS32)) {
|
||||||
WebPRescalerDspInitMIPS32();
|
WebPRescalerDspInitMIPS32();
|
||||||
|
|
@ -240,5 +236,17 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
rescaler_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
WebPRescalerDspInitNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(WebPRescalerExportRowExpand != NULL);
|
||||||
|
assert(WebPRescalerExportRowShrink != NULL);
|
||||||
|
assert(WebPRescalerImportRowExpand != NULL);
|
||||||
|
assert(WebPRescalerImportRowShrink != NULL);
|
||||||
|
#endif // WEBP_REDUCE_SIZE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_USE_NEON) && !defined(WEBP_REDUCE_SIZE)
|
||||||
|
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "./neon.h"
|
#include "../dsp/neon.h"
|
||||||
#include "../utils/rescaler_utils.h"
|
#include "../utils/rescaler_utils.h"
|
||||||
|
|
||||||
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
|
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
|
||||||
|
|
@ -41,9 +41,9 @@
|
||||||
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
|
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32x4_t Interpolate(const rescaler_t* const frow,
|
static uint32x4_t Interpolate_NEON(const rescaler_t* const frow,
|
||||||
const rescaler_t* const irow,
|
const rescaler_t* const irow,
|
||||||
uint32_t A, uint32_t B) {
|
uint32_t A, uint32_t B) {
|
||||||
LOAD_32x4(frow, A0);
|
LOAD_32x4(frow, A0);
|
||||||
LOAD_32x4(irow, B0);
|
LOAD_32x4(irow, B0);
|
||||||
const uint64x2_t C0 = vmull_n_u32(vget_low_u32(A0), A);
|
const uint64x2_t C0 = vmull_n_u32(vget_low_u32(A0), A);
|
||||||
|
|
@ -56,7 +56,7 @@ static uint32x4_t Interpolate(const rescaler_t* const frow,
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerExportRowExpand(WebPRescaler* const wrk) {
|
static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -91,9 +91,9 @@ static void RescalerExportRowExpand(WebPRescaler* const wrk) {
|
||||||
const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
|
const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
|
||||||
for (x_out = 0; x_out < max_span; x_out += 8) {
|
for (x_out = 0; x_out < max_span; x_out += 8) {
|
||||||
const uint32x4_t C0 =
|
const uint32x4_t C0 =
|
||||||
Interpolate(frow + x_out + 0, irow + x_out + 0, A, B);
|
Interpolate_NEON(frow + x_out + 0, irow + x_out + 0, A, B);
|
||||||
const uint32x4_t C1 =
|
const uint32x4_t C1 =
|
||||||
Interpolate(frow + x_out + 4, irow + x_out + 4, A, B);
|
Interpolate_NEON(frow + x_out + 4, irow + x_out + 4, A, B);
|
||||||
const uint32x4_t D0 = MULT_FIX(C0, fy_scale_half);
|
const uint32x4_t D0 = MULT_FIX(C0, fy_scale_half);
|
||||||
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
|
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
|
||||||
const uint16x4_t E0 = vmovn_u32(D0);
|
const uint16x4_t E0 = vmovn_u32(D0);
|
||||||
|
|
@ -112,7 +112,7 @@ static void RescalerExportRowExpand(WebPRescaler* const wrk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerExportRowShrink(WebPRescaler* const wrk) {
|
static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -175,8 +175,8 @@ static void RescalerExportRowShrink(WebPRescaler* const wrk) {
|
||||||
extern void WebPRescalerDspInitNEON(void);
|
extern void WebPRescalerDspInitNEON(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) {
|
||||||
WebPRescalerExportRowExpand = RescalerExportRowExpand;
|
WebPRescalerExportRowExpand = RescalerExportRowExpand_NEON;
|
||||||
WebPRescalerExportRowShrink = RescalerExportRowShrink;
|
WebPRescalerExportRowShrink = RescalerExportRowShrink_NEON;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_NEON
|
#else // !WEBP_USE_NEON
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2) && !defined(WEBP_REDUCE_SIZE)
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
|
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
|
||||||
|
|
||||||
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
|
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
|
||||||
static void LoadTwoPixels(const uint8_t* const src, __m128i* out) {
|
static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
|
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
|
||||||
const __m128i B = _mm_unpacklo_epi8(A, zero); // A0B0C0D0E0F0G0H0
|
const __m128i B = _mm_unpacklo_epi8(A, zero); // A0B0C0D0E0F0G0H0
|
||||||
|
|
@ -36,28 +36,30 @@ static void LoadTwoPixels(const uint8_t* const src, __m128i* out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0
|
// input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0
|
||||||
static void LoadHeightPixels(const uint8_t* const src, __m128i* out) {
|
static void LoadEightPixels_SSE2(const uint8_t* const src, __m128i* out) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
|
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
|
||||||
*out = _mm_unpacklo_epi8(A, zero);
|
*out = _mm_unpacklo_epi8(A, zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
|
static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk,
|
||||||
const uint8_t* src) {
|
const uint8_t* src) {
|
||||||
rescaler_t* frow = wrk->frow;
|
rescaler_t* frow = wrk->frow;
|
||||||
const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels;
|
const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels;
|
||||||
const int x_add = wrk->x_add;
|
const int x_add = wrk->x_add;
|
||||||
int accum = x_add;
|
int accum = x_add;
|
||||||
__m128i cur_pixels;
|
__m128i cur_pixels;
|
||||||
|
|
||||||
|
// SSE2 implementation only works with 16b signed arithmetic at max.
|
||||||
|
if (wrk->src_width < 8 || accum >= (1 << 15)) {
|
||||||
|
WebPRescalerImportRowExpand_C(wrk, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(!WebPRescalerInputDone(wrk));
|
assert(!WebPRescalerInputDone(wrk));
|
||||||
assert(wrk->x_expand);
|
assert(wrk->x_expand);
|
||||||
if (wrk->num_channels == 4) {
|
if (wrk->num_channels == 4) {
|
||||||
if (wrk->src_width < 2) {
|
LoadTwoPixels_SSE2(src, &cur_pixels);
|
||||||
WebPRescalerImportRowExpandC(wrk, src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoadTwoPixels(src, &cur_pixels);
|
|
||||||
src += 4;
|
src += 4;
|
||||||
while (1) {
|
while (1) {
|
||||||
const __m128i mult = _mm_set1_epi32(((x_add - accum) << 16) | accum);
|
const __m128i mult = _mm_set1_epi32(((x_add - accum) << 16) | accum);
|
||||||
|
|
@ -67,7 +69,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
|
||||||
if (frow >= frow_end) break;
|
if (frow >= frow_end) break;
|
||||||
accum -= wrk->x_sub;
|
accum -= wrk->x_sub;
|
||||||
if (accum < 0) {
|
if (accum < 0) {
|
||||||
LoadTwoPixels(src, &cur_pixels);
|
LoadTwoPixels_SSE2(src, &cur_pixels);
|
||||||
src += 4;
|
src += 4;
|
||||||
accum += x_add;
|
accum += x_add;
|
||||||
}
|
}
|
||||||
|
|
@ -75,11 +77,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
|
||||||
} else {
|
} else {
|
||||||
int left;
|
int left;
|
||||||
const uint8_t* const src_limit = src + wrk->src_width - 8;
|
const uint8_t* const src_limit = src + wrk->src_width - 8;
|
||||||
if (wrk->src_width < 8) {
|
LoadEightPixels_SSE2(src, &cur_pixels);
|
||||||
WebPRescalerImportRowExpandC(wrk, src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoadHeightPixels(src, &cur_pixels);
|
|
||||||
src += 7;
|
src += 7;
|
||||||
left = 7;
|
left = 7;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
@ -94,7 +92,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
|
||||||
if (--left) {
|
if (--left) {
|
||||||
cur_pixels = _mm_srli_si128(cur_pixels, 2);
|
cur_pixels = _mm_srli_si128(cur_pixels, 2);
|
||||||
} else if (src <= src_limit) {
|
} else if (src <= src_limit) {
|
||||||
LoadHeightPixels(src, &cur_pixels);
|
LoadEightPixels_SSE2(src, &cur_pixels);
|
||||||
src += 7;
|
src += 7;
|
||||||
left = 7;
|
left = 7;
|
||||||
} else { // tail
|
} else { // tail
|
||||||
|
|
@ -110,8 +108,8 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
|
||||||
assert(accum == 0);
|
assert(accum == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
|
static void RescalerImportRowShrink_SSE2(WebPRescaler* const wrk,
|
||||||
const uint8_t* src) {
|
const uint8_t* src) {
|
||||||
const int x_sub = wrk->x_sub;
|
const int x_sub = wrk->x_sub;
|
||||||
int accum = 0;
|
int accum = 0;
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
|
@ -123,7 +121,7 @@ static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
|
||||||
const rescaler_t* const frow_end = wrk->frow + 4 * wrk->dst_width;
|
const rescaler_t* const frow_end = wrk->frow + 4 * wrk->dst_width;
|
||||||
|
|
||||||
if (wrk->num_channels != 4 || wrk->x_add > (x_sub << 7)) {
|
if (wrk->num_channels != 4 || wrk->x_add > (x_sub << 7)) {
|
||||||
WebPRescalerImportRowShrinkC(wrk, src);
|
WebPRescalerImportRowShrink_C(wrk, src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(!WebPRescalerInputDone(wrk));
|
assert(!WebPRescalerInputDone(wrk));
|
||||||
|
|
@ -169,12 +167,12 @@ static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
|
||||||
// Row export
|
// Row export
|
||||||
|
|
||||||
// load *src as epi64, multiply by mult and store result in [out0 ... out3]
|
// load *src as epi64, multiply by mult and store result in [out0 ... out3]
|
||||||
static WEBP_INLINE void LoadDispatchAndMult(const rescaler_t* const src,
|
static WEBP_INLINE void LoadDispatchAndMult_SSE2(const rescaler_t* const src,
|
||||||
const __m128i* const mult,
|
const __m128i* const mult,
|
||||||
__m128i* const out0,
|
__m128i* const out0,
|
||||||
__m128i* const out1,
|
__m128i* const out1,
|
||||||
__m128i* const out2,
|
__m128i* const out2,
|
||||||
__m128i* const out3) {
|
__m128i* const out3) {
|
||||||
const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0));
|
const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0));
|
||||||
const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4));
|
const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4));
|
||||||
const __m128i A2 = _mm_srli_epi64(A0, 32);
|
const __m128i A2 = _mm_srli_epi64(A0, 32);
|
||||||
|
|
@ -192,12 +190,12 @@ static WEBP_INLINE void LoadDispatchAndMult(const rescaler_t* const src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void ProcessRow(const __m128i* const A0,
|
static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
|
||||||
const __m128i* const A1,
|
const __m128i* const A1,
|
||||||
const __m128i* const A2,
|
const __m128i* const A2,
|
||||||
const __m128i* const A3,
|
const __m128i* const A3,
|
||||||
const __m128i* const mult,
|
const __m128i* const mult,
|
||||||
uint8_t* const dst) {
|
uint8_t* const dst) {
|
||||||
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
||||||
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
|
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
|
||||||
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
|
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
|
||||||
|
|
@ -210,7 +208,7 @@ static WEBP_INLINE void ProcessRow(const __m128i* const A0,
|
||||||
const __m128i C3 = _mm_add_epi64(B3, rounder);
|
const __m128i C3 = _mm_add_epi64(B3, rounder);
|
||||||
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX);
|
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX);
|
||||||
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
|
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
|
||||||
#if (WEBP_RESCALER_FIX < 32)
|
#if (WEBP_RESCALER_RFIX < 32)
|
||||||
const __m128i D2 =
|
const __m128i D2 =
|
||||||
_mm_and_si128(_mm_slli_epi64(C2, 32 - WEBP_RESCALER_RFIX), mask);
|
_mm_and_si128(_mm_slli_epi64(C2, 32 - WEBP_RESCALER_RFIX), mask);
|
||||||
const __m128i D3 =
|
const __m128i D3 =
|
||||||
|
|
@ -226,7 +224,7 @@ static WEBP_INLINE void ProcessRow(const __m128i* const A0,
|
||||||
_mm_storel_epi64((__m128i*)dst, G);
|
_mm_storel_epi64((__m128i*)dst, G);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
|
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -240,8 +238,8 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
|
||||||
if (wrk->y_accum == 0) {
|
if (wrk->y_accum == 0) {
|
||||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||||
__m128i A0, A1, A2, A3;
|
__m128i A0, A1, A2, A3;
|
||||||
LoadDispatchAndMult(frow + x_out, NULL, &A0, &A1, &A2, &A3);
|
LoadDispatchAndMult_SSE2(frow + x_out, NULL, &A0, &A1, &A2, &A3);
|
||||||
ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
|
ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const uint32_t J = frow[x_out];
|
const uint32_t J = frow[x_out];
|
||||||
|
|
@ -257,8 +255,8 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
|
||||||
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
||||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||||
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
||||||
LoadDispatchAndMult(frow + x_out, &mA, &A0, &A1, &A2, &A3);
|
LoadDispatchAndMult_SSE2(frow + x_out, &mA, &A0, &A1, &A2, &A3);
|
||||||
LoadDispatchAndMult(irow + x_out, &mB, &B0, &B1, &B2, &B3);
|
LoadDispatchAndMult_SSE2(irow + x_out, &mB, &B0, &B1, &B2, &B3);
|
||||||
{
|
{
|
||||||
const __m128i C0 = _mm_add_epi64(A0, B0);
|
const __m128i C0 = _mm_add_epi64(A0, B0);
|
||||||
const __m128i C1 = _mm_add_epi64(A1, B1);
|
const __m128i C1 = _mm_add_epi64(A1, B1);
|
||||||
|
|
@ -272,7 +270,7 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
|
||||||
const __m128i E1 = _mm_srli_epi64(D1, WEBP_RESCALER_RFIX);
|
const __m128i E1 = _mm_srli_epi64(D1, WEBP_RESCALER_RFIX);
|
||||||
const __m128i E2 = _mm_srli_epi64(D2, WEBP_RESCALER_RFIX);
|
const __m128i E2 = _mm_srli_epi64(D2, WEBP_RESCALER_RFIX);
|
||||||
const __m128i E3 = _mm_srli_epi64(D3, WEBP_RESCALER_RFIX);
|
const __m128i E3 = _mm_srli_epi64(D3, WEBP_RESCALER_RFIX);
|
||||||
ProcessRow(&E0, &E1, &E2, &E3, &mult, dst + x_out);
|
ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult, dst + x_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
|
|
@ -286,7 +284,7 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
|
static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
||||||
int x_out;
|
int x_out;
|
||||||
uint8_t* const dst = wrk->dst;
|
uint8_t* const dst = wrk->dst;
|
||||||
rescaler_t* const irow = wrk->irow;
|
rescaler_t* const irow = wrk->irow;
|
||||||
|
|
@ -303,8 +301,8 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
|
||||||
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
||||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||||
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
||||||
LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
||||||
LoadDispatchAndMult(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
|
LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
|
||||||
{
|
{
|
||||||
const __m128i C0 = _mm_add_epi64(B0, rounder);
|
const __m128i C0 = _mm_add_epi64(B0, rounder);
|
||||||
const __m128i C1 = _mm_add_epi64(B1, rounder);
|
const __m128i C1 = _mm_add_epi64(B1, rounder);
|
||||||
|
|
@ -324,7 +322,7 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
|
||||||
const __m128i G1 = _mm_or_si128(D1, F3);
|
const __m128i G1 = _mm_or_si128(D1, F3);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
|
||||||
ProcessRow(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
|
|
@ -340,10 +338,10 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||||
__m128i A0, A1, A2, A3;
|
__m128i A0, A1, A2, A3;
|
||||||
LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 0), zero);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 0), zero);
|
||||||
_mm_storeu_si128((__m128i*)(irow + x_out + 4), zero);
|
_mm_storeu_si128((__m128i*)(irow + x_out + 4), zero);
|
||||||
ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
|
ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out);
|
||||||
}
|
}
|
||||||
for (; x_out < x_out_max; ++x_out) {
|
for (; x_out < x_out_max; ++x_out) {
|
||||||
const int v = (int)MULT_FIX(irow[x_out], scale);
|
const int v = (int)MULT_FIX(irow[x_out], scale);
|
||||||
|
|
@ -362,10 +360,10 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
|
||||||
extern void WebPRescalerDspInitSSE2(void);
|
extern void WebPRescalerDspInitSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) {
|
||||||
WebPRescalerImportRowExpand = RescalerImportRowExpandSSE2;
|
WebPRescalerImportRowExpand = RescalerImportRowExpand_SSE2;
|
||||||
WebPRescalerImportRowShrink = RescalerImportRowShrinkSSE2;
|
WebPRescalerImportRowShrink = RescalerImportRowShrink_SSE2;
|
||||||
WebPRescalerExportRowExpand = RescalerExportRowExpandSSE2;
|
WebPRescalerExportRowExpand = RescalerExportRowExpand_SSE2;
|
||||||
WebPRescalerExportRowShrink = RescalerExportRowShrinkSSE2;
|
WebPRescalerExportRowShrink = RescalerExportRowShrink_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !WEBP_USE_SSE2
|
#else // !WEBP_USE_SSE2
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: somnath@google.com (Somnath Banerjee)
|
// Author: somnath@google.com (Somnath Banerjee)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "./yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
@ -63,17 +63,17 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||||
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
|
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
|
||||||
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
|
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
|
||||||
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
|
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
|
||||||
top_dst + (2 * x - 1) * XSTEP); \
|
top_dst + (2 * x - 1) * (XSTEP)); \
|
||||||
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
|
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
|
||||||
top_dst + (2 * x - 0) * XSTEP); \
|
top_dst + (2 * x - 0) * (XSTEP)); \
|
||||||
} \
|
} \
|
||||||
if (bottom_y != NULL) { \
|
if (bottom_y != NULL) { \
|
||||||
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
|
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
|
||||||
const uint32_t uv1 = (diag_12 + uv) >> 1; \
|
const uint32_t uv1 = (diag_12 + uv) >> 1; \
|
||||||
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
|
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
|
||||||
bottom_dst + (2 * x - 1) * XSTEP); \
|
bottom_dst + (2 * x - 1) * (XSTEP)); \
|
||||||
FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
|
FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
|
||||||
bottom_dst + (2 * x + 0) * XSTEP); \
|
bottom_dst + (2 * x + 0) * (XSTEP)); \
|
||||||
} \
|
} \
|
||||||
tl_uv = t_uv; \
|
tl_uv = t_uv; \
|
||||||
l_uv = uv; \
|
l_uv = uv; \
|
||||||
|
|
@ -82,24 +82,50 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||||
{ \
|
{ \
|
||||||
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
|
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
|
||||||
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
|
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
|
||||||
top_dst + (len - 1) * XSTEP); \
|
top_dst + (len - 1) * (XSTEP)); \
|
||||||
} \
|
} \
|
||||||
if (bottom_y != NULL) { \
|
if (bottom_y != NULL) { \
|
||||||
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
|
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
|
||||||
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
|
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
|
||||||
bottom_dst + (len - 1) * XSTEP); \
|
bottom_dst + (len - 1) * (XSTEP)); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
// All variants implemented.
|
// All variants implemented.
|
||||||
UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
|
UPSAMPLE_FUNC(UpsampleRgbaLinePair_C, VP8YuvToRgba, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
|
UPSAMPLE_FUNC(UpsampleBgraLinePair_C, VP8YuvToBgra, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
UPSAMPLE_FUNC(UpsampleArgbLinePair_C, VP8YuvToArgb, 4)
|
||||||
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
UPSAMPLE_FUNC(UpsampleRgbLinePair_C, VP8YuvToRgb, 3)
|
||||||
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
UPSAMPLE_FUNC(UpsampleBgrLinePair_C, VP8YuvToBgr, 3)
|
||||||
|
UPSAMPLE_FUNC(UpsampleRgba4444LinePair_C, VP8YuvToRgba4444, 2)
|
||||||
|
UPSAMPLE_FUNC(UpsampleRgb565LinePair_C, VP8YuvToRgb565, 2)
|
||||||
|
#else
|
||||||
|
static void EmptyUpsampleFunc(const uint8_t* top_y, const uint8_t* bottom_y,
|
||||||
|
const uint8_t* top_u, const uint8_t* top_v,
|
||||||
|
const uint8_t* cur_u, const uint8_t* cur_v,
|
||||||
|
uint8_t* top_dst, uint8_t* bottom_dst, int len) {
|
||||||
|
(void)top_y;
|
||||||
|
(void)bottom_y;
|
||||||
|
(void)top_u;
|
||||||
|
(void)top_v;
|
||||||
|
(void)cur_u;
|
||||||
|
(void)cur_v;
|
||||||
|
(void)top_dst;
|
||||||
|
(void)bottom_dst;
|
||||||
|
(void)len;
|
||||||
|
assert(0); // COLORSPACE SUPPORT NOT COMPILED
|
||||||
|
}
|
||||||
|
#define UpsampleArgbLinePair_C EmptyUpsampleFunc
|
||||||
|
#define UpsampleRgbLinePair_C EmptyUpsampleFunc
|
||||||
|
#define UpsampleBgrLinePair_C EmptyUpsampleFunc
|
||||||
|
#define UpsampleRgba4444LinePair_C EmptyUpsampleFunc
|
||||||
|
#define UpsampleRgb565LinePair_C EmptyUpsampleFunc
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef LOAD_UV
|
#undef LOAD_UV
|
||||||
#undef UPSAMPLE_FUNC
|
#undef UPSAMPLE_FUNC
|
||||||
|
|
@ -141,7 +167,6 @@ DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb)
|
||||||
|
|
||||||
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
|
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
|
||||||
WebPInitUpsamplers();
|
WebPInitUpsamplers();
|
||||||
VP8YUVInit();
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
|
return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
|
||||||
#else
|
#else
|
||||||
|
|
@ -158,16 +183,33 @@ extern void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
uint8_t* dst, int len) { \
|
uint8_t* dst, int len) { \
|
||||||
int i; \
|
int i; \
|
||||||
for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
|
for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * (XSTEP)]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
YUV444_FUNC(WebPYuv444ToRgbC, VP8YuvToRgb, 3)
|
YUV444_FUNC(WebPYuv444ToRgba_C, VP8YuvToRgba, 4)
|
||||||
YUV444_FUNC(WebPYuv444ToBgrC, VP8YuvToBgr, 3)
|
YUV444_FUNC(WebPYuv444ToBgra_C, VP8YuvToBgra, 4)
|
||||||
YUV444_FUNC(WebPYuv444ToRgbaC, VP8YuvToRgba, 4)
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
YUV444_FUNC(WebPYuv444ToBgraC, VP8YuvToBgra, 4)
|
YUV444_FUNC(WebPYuv444ToRgb_C, VP8YuvToRgb, 3)
|
||||||
YUV444_FUNC(WebPYuv444ToArgbC, VP8YuvToArgb, 4)
|
YUV444_FUNC(WebPYuv444ToBgr_C, VP8YuvToBgr, 3)
|
||||||
YUV444_FUNC(WebPYuv444ToRgba4444C, VP8YuvToRgba4444, 2)
|
YUV444_FUNC(WebPYuv444ToArgb_C, VP8YuvToArgb, 4)
|
||||||
YUV444_FUNC(WebPYuv444ToRgb565C, VP8YuvToRgb565, 2)
|
YUV444_FUNC(WebPYuv444ToRgba4444_C, VP8YuvToRgba4444, 2)
|
||||||
|
YUV444_FUNC(WebPYuv444ToRgb565_C, VP8YuvToRgb565, 2)
|
||||||
|
#else
|
||||||
|
static void EmptyYuv444Func(const uint8_t* y,
|
||||||
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
|
(void)y;
|
||||||
|
(void)u;
|
||||||
|
(void)v;
|
||||||
|
(void)dst;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
#define WebPYuv444ToRgb_C EmptyYuv444Func
|
||||||
|
#define WebPYuv444ToBgr_C EmptyYuv444Func
|
||||||
|
#define WebPYuv444ToArgb_C EmptyYuv444Func
|
||||||
|
#define WebPYuv444ToRgba4444_C EmptyYuv444Func
|
||||||
|
#define WebPYuv444ToRgb565_C EmptyYuv444Func
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
#undef YUV444_FUNC
|
#undef YUV444_FUNC
|
||||||
|
|
||||||
|
|
@ -175,24 +217,20 @@ WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
|
||||||
|
|
||||||
extern void WebPInitYUV444ConvertersMIPSdspR2(void);
|
extern void WebPInitYUV444ConvertersMIPSdspR2(void);
|
||||||
extern void WebPInitYUV444ConvertersSSE2(void);
|
extern void WebPInitYUV444ConvertersSSE2(void);
|
||||||
|
extern void WebPInitYUV444ConvertersSSE41(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo upsampling_last_cpuinfo_used1 =
|
WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) {
|
||||||
(VP8CPUInfo)&upsampling_last_cpuinfo_used1;
|
WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgba_C;
|
||||||
|
WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgra_C;
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) {
|
WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgb_C;
|
||||||
if (upsampling_last_cpuinfo_used1 == VP8GetCPUInfo) return;
|
WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgr_C;
|
||||||
|
WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgb_C;
|
||||||
WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgbC;
|
WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444_C;
|
||||||
WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgbaC;
|
WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565_C;
|
||||||
WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgrC;
|
WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgba_C;
|
||||||
WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgraC;
|
WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgra_C;
|
||||||
WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgbC;
|
WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgb_C;
|
||||||
WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444C;
|
WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C;
|
||||||
WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565C;
|
|
||||||
WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgbaC;
|
|
||||||
WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgraC;
|
|
||||||
WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgbC;
|
|
||||||
WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444C;
|
|
||||||
|
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
@ -200,41 +238,43 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) {
|
||||||
WebPInitYUV444ConvertersSSE2();
|
WebPInitYUV444ConvertersSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||||
|
WebPInitYUV444ConvertersSSE41();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
if (VP8GetCPUInfo(kMIPSdspR2)) {
|
||||||
WebPInitYUV444ConvertersMIPSdspR2();
|
WebPInitYUV444ConvertersMIPSdspR2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
upsampling_last_cpuinfo_used1 = VP8GetCPUInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Main calls
|
// Main calls
|
||||||
|
|
||||||
extern void WebPInitUpsamplersSSE2(void);
|
extern void WebPInitUpsamplersSSE2(void);
|
||||||
|
extern void WebPInitUpsamplersSSE41(void);
|
||||||
extern void WebPInitUpsamplersNEON(void);
|
extern void WebPInitUpsamplersNEON(void);
|
||||||
extern void WebPInitUpsamplersMIPSdspR2(void);
|
extern void WebPInitUpsamplersMIPSdspR2(void);
|
||||||
extern void WebPInitUpsamplersMSA(void);
|
extern void WebPInitUpsamplersMSA(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 =
|
WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
|
||||||
(VP8CPUInfo)&upsampling_last_cpuinfo_used2;
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
|
|
||||||
if (upsampling_last_cpuinfo_used2 == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_C;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_C;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_C;
|
||||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_C;
|
||||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_C;
|
||||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_C;
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_C;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_C;
|
||||||
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
|
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_C;
|
||||||
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_C;
|
||||||
|
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
|
|
@ -243,9 +283,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
|
||||||
WebPInitUpsamplersSSE2();
|
WebPInitUpsamplersSSE2();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_USE_SSE41)
|
||||||
if (VP8GetCPUInfo(kNEON)) {
|
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||||
WebPInitUpsamplersNEON();
|
WebPInitUpsamplersSSE41();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(WEBP_USE_MIPS_DSP_R2)
|
#if defined(WEBP_USE_MIPS_DSP_R2)
|
||||||
|
|
@ -259,8 +299,29 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
WebPInitUpsamplersNEON();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(WebPUpsamplers[MODE_RGBA] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_BGRA] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_rgbA] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_bgrA] != NULL);
|
||||||
|
#if !defined(WEBP_REDUCE_CSP) || !WEBP_NEON_OMIT_C_CODE
|
||||||
|
assert(WebPUpsamplers[MODE_RGB] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_BGR] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_ARGB] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_RGBA_4444] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_RGB_565] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_Argb] != NULL);
|
||||||
|
assert(WebPUpsamplers[MODE_rgbA_4444] != NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
#endif // FANCY_UPSAMPLING
|
||||||
upsampling_last_cpuinfo_used2 = VP8GetCPUInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,15 @@
|
||||||
// Author: mans@mansr.com (Mans Rullgard)
|
// Author: mans@mansr.com (Mans Rullgard)
|
||||||
// Based on SSE code by: somnath@google.com (Somnath Banerjee)
|
// Based on SSE code by: somnath@google.com (Somnath Banerjee)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_NEON)
|
#if defined(WEBP_USE_NEON)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./neon.h"
|
#include "../dsp/neon.h"
|
||||||
#include "./yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
|
|
@ -58,8 +58,8 @@
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Turn the macro into a function for reducing code-size when non-critical
|
// Turn the macro into a function for reducing code-size when non-critical
|
||||||
static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
|
static void Upsample16Pixels_NEON(const uint8_t *r1, const uint8_t *r2,
|
||||||
uint8_t *out) {
|
uint8_t *out) {
|
||||||
UPSAMPLE_16PIXELS(r1, r2, out);
|
UPSAMPLE_16PIXELS(r1, r2, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
|
||||||
/* replicate last byte */ \
|
/* replicate last byte */ \
|
||||||
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \
|
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \
|
||||||
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \
|
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \
|
||||||
Upsample16Pixels(r1, r2, out); \
|
Upsample16Pixels_NEON(r1, r2, out); \
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -243,13 +243,15 @@ static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEON variants of the fancy upsampler.
|
// NEON variants of the fancy upsampler.
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair, Rgb, 3)
|
NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair_NEON, Rgba, 4)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair, Bgr, 3)
|
NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair_NEON, Bgra, 4)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair, Rgba, 4)
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair, Bgra, 4)
|
NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair_NEON, Rgb, 3)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleArgbLinePair, Argb, 4)
|
NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair_NEON, Bgr, 3)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleRgba4444LinePair, Rgba4444, 2)
|
NEON_UPSAMPLE_FUNC(UpsampleArgbLinePair_NEON, Argb, 4)
|
||||||
NEON_UPSAMPLE_FUNC(UpsampleRgb565LinePair, Rgb565, 2)
|
NEON_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_NEON, Rgba4444, 2)
|
||||||
|
NEON_UPSAMPLE_FUNC(UpsampleRgb565LinePair_NEON, Rgb565, 2)
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Entry point
|
// Entry point
|
||||||
|
|
@ -259,17 +261,19 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||||
extern void WebPInitUpsamplersNEON(void);
|
extern void WebPInitUpsamplersNEON(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersNEON(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersNEON(void) {
|
||||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
|
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_NEON;
|
||||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_NEON;
|
||||||
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_NEON;
|
||||||
|
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_NEON;
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
#endif // FANCY_UPSAMPLING
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,14 @@
|
||||||
//
|
//
|
||||||
// Author: somnath@google.com (Somnath Banerjee)
|
// Author: somnath@google.com (Somnath Banerjee)
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
#ifdef FANCY_UPSAMPLING
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
|
|
@ -83,13 +83,13 @@
|
||||||
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
|
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
|
||||||
\
|
\
|
||||||
/* pack the alternate pixels */ \
|
/* pack the alternate pixels */ \
|
||||||
PACK_AND_STORE(a, b, diag1, diag2, out + 0); /* store top */ \
|
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
|
||||||
PACK_AND_STORE(c, d, diag2, diag1, out + 2 * 32); /* store bottom */ \
|
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn the macro into a function for reducing code-size when non-critical
|
// Turn the macro into a function for reducing code-size when non-critical
|
||||||
static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
|
static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[],
|
||||||
uint8_t* const out) {
|
uint8_t* const out) {
|
||||||
UPSAMPLE_32PIXELS(r1, r2, out);
|
UPSAMPLE_32PIXELS(r1, r2, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,30 +101,15 @@ static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
|
||||||
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
|
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
|
||||||
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
|
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
|
||||||
/* using the shared function instead of the macro saves ~3k code size */ \
|
/* using the shared function instead of the macro saves ~3k code size */ \
|
||||||
Upsample32Pixels(r1, r2, out); \
|
Upsample32Pixels_SSE2(r1, r2, out); \
|
||||||
}
|
|
||||||
|
|
||||||
#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, \
|
|
||||||
top_dst, bottom_dst, cur_x, num_pixels) { \
|
|
||||||
int n; \
|
|
||||||
for (n = 0; n < (num_pixels); ++n) { \
|
|
||||||
FUNC(top_y[(cur_x) + n], r_u[n], r_v[n], \
|
|
||||||
top_dst + ((cur_x) + n) * XSTEP); \
|
|
||||||
} \
|
|
||||||
if (bottom_y != NULL) { \
|
|
||||||
for (n = 0; n < (num_pixels); ++n) { \
|
|
||||||
FUNC(bottom_y[(cur_x) + n], r_u[64 + n], r_v[64 + n], \
|
|
||||||
bottom_dst + ((cur_x) + n) * XSTEP); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
|
#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
|
||||||
top_dst, bottom_dst, cur_x) do { \
|
top_dst, bottom_dst, cur_x) do { \
|
||||||
FUNC##32(top_y + (cur_x), r_u, r_v, top_dst + (cur_x) * XSTEP); \
|
FUNC##32_SSE2((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \
|
||||||
if (bottom_y != NULL) { \
|
if ((bottom_y) != NULL) { \
|
||||||
FUNC##32(bottom_y + (cur_x), r_u + 64, r_v + 64, \
|
FUNC##32_SSE2((bottom_y) + (cur_x), r_u + 64, r_v + 64, \
|
||||||
bottom_dst + (cur_x) * XSTEP); \
|
(bottom_dst) + (cur_x) * (XSTEP)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
@ -135,7 +120,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||||
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
|
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
|
||||||
int uv_pos, pos; \
|
int uv_pos, pos; \
|
||||||
/* 16byte-aligned array to cache reconstructed u and v */ \
|
/* 16byte-aligned array to cache reconstructed u and v */ \
|
||||||
uint8_t uv_buf[4 * 32 + 15]; \
|
uint8_t uv_buf[14 * 32 + 15] = { 0 }; \
|
||||||
uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
|
uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
|
||||||
uint8_t* const r_v = r_u + 32; \
|
uint8_t* const r_v = r_u + 32; \
|
||||||
\
|
\
|
||||||
|
|
@ -160,22 +145,36 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||||
} \
|
} \
|
||||||
if (len > 1) { \
|
if (len > 1) { \
|
||||||
const int left_over = ((len + 1) >> 1) - (pos >> 1); \
|
const int left_over = ((len + 1) >> 1) - (pos >> 1); \
|
||||||
|
uint8_t* const tmp_top_dst = r_u + 4 * 32; \
|
||||||
|
uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \
|
||||||
|
uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \
|
||||||
|
uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \
|
||||||
assert(left_over > 0); \
|
assert(left_over > 0); \
|
||||||
UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
|
UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
|
||||||
UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
|
UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
|
||||||
CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, \
|
memcpy(tmp_top, top_y + pos, len - pos); \
|
||||||
pos, len - pos); \
|
if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \
|
||||||
|
CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \
|
||||||
|
tmp_bottom_dst, 0); \
|
||||||
|
memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \
|
||||||
|
if (bottom_y != NULL) { \
|
||||||
|
memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \
|
||||||
|
(len - pos) * (XSTEP)); \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSE2 variants of the fancy upsampler.
|
// SSE2 variants of the fancy upsampler.
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
|
SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair_SSE2, VP8YuvToRgba, 4)
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
|
SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair_SSE2, VP8YuvToBgra, 4)
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
|
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
|
SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE2, VP8YuvToRgb, 3)
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
|
SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE2, VP8YuvToBgr, 3)
|
||||||
SSE2_UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
|
SSE2_UPSAMPLE_FUNC(UpsampleArgbLinePair_SSE2, VP8YuvToArgb, 4)
|
||||||
|
SSE2_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_SSE2, VP8YuvToRgba4444, 2)
|
||||||
|
SSE2_UPSAMPLE_FUNC(UpsampleRgb565LinePair_SSE2, VP8YuvToRgb565, 2)
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
#undef GET_M
|
#undef GET_M
|
||||||
#undef PACK_AND_STORE
|
#undef PACK_AND_STORE
|
||||||
|
|
@ -193,17 +192,19 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||||
extern void WebPInitUpsamplersSSE2(void);
|
extern void WebPInitUpsamplersSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
|
||||||
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
|
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
|
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
|
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
|
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
|
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_SSE2;
|
||||||
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
|
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_SSE2;
|
||||||
|
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_SSE2;
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FANCY_UPSAMPLING
|
#endif // FANCY_UPSAMPLING
|
||||||
|
|
@ -213,29 +214,46 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
|
||||||
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
||||||
extern void WebPInitYUV444ConvertersSSE2(void);
|
extern void WebPInitYUV444ConvertersSSE2(void);
|
||||||
|
|
||||||
#define YUV444_FUNC(FUNC_NAME, CALL, XSTEP) \
|
#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \
|
||||||
extern void WebP##FUNC_NAME##C(const uint8_t* y, const uint8_t* u, \
|
extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
const uint8_t* v, uint8_t* dst, int len); \
|
uint8_t* dst, int len); \
|
||||||
static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
uint8_t* dst, int len) { \
|
uint8_t* dst, int len) { \
|
||||||
int i; \
|
int i; \
|
||||||
const int max_len = len & ~31; \
|
const int max_len = len & ~31; \
|
||||||
for (i = 0; i < max_len; i += 32) CALL(y + i, u + i, v + i, dst + i * XSTEP);\
|
for (i = 0; i < max_len; i += 32) { \
|
||||||
|
CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \
|
||||||
|
} \
|
||||||
if (i < len) { /* C-fallback */ \
|
if (i < len) { /* C-fallback */ \
|
||||||
WebP##FUNC_NAME##C(y + i, u + i, v + i, dst + i * XSTEP, len - i); \
|
CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba32, 4);
|
YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4);
|
||||||
YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra32, 4);
|
YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4);
|
||||||
YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb32, 3);
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr32, 3);
|
YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3);
|
||||||
|
YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3);
|
||||||
|
YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4)
|
||||||
|
YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \
|
||||||
|
WebPYuv444ToRgba4444_C, 2)
|
||||||
|
YUV444_FUNC(Yuv444ToRgb565_SSE2, VP8YuvToRgb56532_SSE2, WebPYuv444ToRgb565_C, 2)
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE2(void) {
|
||||||
WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba;
|
WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba_SSE2;
|
||||||
WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra;
|
WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra_SSE2;
|
||||||
WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb;
|
WebPYUV444Converters[MODE_rgbA] = Yuv444ToRgba_SSE2;
|
||||||
WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr;
|
WebPYUV444Converters[MODE_bgrA] = Yuv444ToBgra_SSE2;
|
||||||
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
|
WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_ARGB] = Yuv444ToArgb_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_RGB_565] = Yuv444ToRgb565_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_Argb] = Yuv444ToArgb_SSE2;
|
||||||
|
WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444_SSE2;
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
239
media/libwebp/dsp/upsampling_sse41.c
Normal file
239
media/libwebp/dsp/upsampling_sse41.c
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SSE41 version of YUV to RGB upsampling functions.
|
||||||
|
//
|
||||||
|
// Author: somnath@google.com (Somnath Banerjee)
|
||||||
|
|
||||||
|
#include "../dsp/dsp.h"
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <smmintrin.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
|
#ifdef FANCY_UPSAMPLING
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
|
|
||||||
|
// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
|
||||||
|
// u = (9*a + 3*b + 3*c + d + 8) / 16
|
||||||
|
// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2
|
||||||
|
// = (a + m + 1) / 2
|
||||||
|
// where m = (a + 3*b + 3*c + d) / 8
|
||||||
|
// = ((a + b + c + d) / 2 + b + c) / 4
|
||||||
|
//
|
||||||
|
// Let's say k = (a + b + c + d) / 4.
|
||||||
|
// We can compute k as
|
||||||
|
// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1
|
||||||
|
// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2
|
||||||
|
//
|
||||||
|
// Then m can be written as
|
||||||
|
// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1
|
||||||
|
|
||||||
|
// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1
|
||||||
|
#define GET_M(ij, in, out) do { \
|
||||||
|
const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \
|
||||||
|
const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \
|
||||||
|
const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \
|
||||||
|
const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\
|
||||||
|
const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \
|
||||||
|
(out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// pack and store two alternating pixel rows
|
||||||
|
#define PACK_AND_STORE(a, b, da, db, out) do { \
|
||||||
|
const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
|
||||||
|
const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
|
||||||
|
const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \
|
||||||
|
const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \
|
||||||
|
_mm_store_si128(((__m128i*)(out)) + 0, t_1); \
|
||||||
|
_mm_store_si128(((__m128i*)(out)) + 1, t_2); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
|
||||||
|
#define UPSAMPLE_32PIXELS(r1, r2, out) { \
|
||||||
|
const __m128i one = _mm_set1_epi8(1); \
|
||||||
|
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
|
||||||
|
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
|
||||||
|
const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \
|
||||||
|
const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \
|
||||||
|
\
|
||||||
|
const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \
|
||||||
|
const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \
|
||||||
|
const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \
|
||||||
|
\
|
||||||
|
const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \
|
||||||
|
const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \
|
||||||
|
\
|
||||||
|
const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \
|
||||||
|
const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \
|
||||||
|
const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \
|
||||||
|
const __m128i t4 = _mm_avg_epu8(s, t); \
|
||||||
|
const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \
|
||||||
|
__m128i diag1, diag2; \
|
||||||
|
\
|
||||||
|
GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \
|
||||||
|
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
|
||||||
|
\
|
||||||
|
/* pack the alternate pixels */ \
|
||||||
|
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
|
||||||
|
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn the macro into a function for reducing code-size when non-critical
|
||||||
|
static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[],
|
||||||
|
uint8_t* const out) {
|
||||||
|
UPSAMPLE_32PIXELS(r1, r2, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \
|
||||||
|
uint8_t r1[17], r2[17]; \
|
||||||
|
memcpy(r1, (tb), (num_pixels)); \
|
||||||
|
memcpy(r2, (bb), (num_pixels)); \
|
||||||
|
/* replicate last byte */ \
|
||||||
|
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
|
||||||
|
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
|
||||||
|
/* using the shared function instead of the macro saves ~3k code size */ \
|
||||||
|
Upsample32Pixels_SSE41(r1, r2, out); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
|
||||||
|
top_dst, bottom_dst, cur_x) do { \
|
||||||
|
FUNC##32_SSE41((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \
|
||||||
|
if ((bottom_y) != NULL) { \
|
||||||
|
FUNC##32_SSE41((bottom_y) + (cur_x), r_u + 64, r_v + 64, \
|
||||||
|
(bottom_dst) + (cur_x) * (XSTEP)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SSE4_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
|
||||||
|
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
||||||
|
const uint8_t* top_u, const uint8_t* top_v, \
|
||||||
|
const uint8_t* cur_u, const uint8_t* cur_v, \
|
||||||
|
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
|
||||||
|
int uv_pos, pos; \
|
||||||
|
/* 16byte-aligned array to cache reconstructed u and v */ \
|
||||||
|
uint8_t uv_buf[14 * 32 + 15] = { 0 }; \
|
||||||
|
uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
|
||||||
|
uint8_t* const r_v = r_u + 32; \
|
||||||
|
\
|
||||||
|
assert(top_y != NULL); \
|
||||||
|
{ /* Treat the first pixel in regular way */ \
|
||||||
|
const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
|
||||||
|
const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
|
||||||
|
const int u0_t = (top_u[0] + u_diag) >> 1; \
|
||||||
|
const int v0_t = (top_v[0] + v_diag) >> 1; \
|
||||||
|
FUNC(top_y[0], u0_t, v0_t, top_dst); \
|
||||||
|
if (bottom_y != NULL) { \
|
||||||
|
const int u0_b = (cur_u[0] + u_diag) >> 1; \
|
||||||
|
const int v0_b = (cur_v[0] + v_diag) >> 1; \
|
||||||
|
FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
/* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \
|
||||||
|
for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \
|
||||||
|
UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \
|
||||||
|
UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \
|
||||||
|
CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \
|
||||||
|
} \
|
||||||
|
if (len > 1) { \
|
||||||
|
const int left_over = ((len + 1) >> 1) - (pos >> 1); \
|
||||||
|
uint8_t* const tmp_top_dst = r_u + 4 * 32; \
|
||||||
|
uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \
|
||||||
|
uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \
|
||||||
|
uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \
|
||||||
|
assert(left_over > 0); \
|
||||||
|
UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
|
||||||
|
UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
|
||||||
|
memcpy(tmp_top, top_y + pos, len - pos); \
|
||||||
|
if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \
|
||||||
|
CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \
|
||||||
|
tmp_bottom_dst, 0); \
|
||||||
|
memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \
|
||||||
|
if (bottom_y != NULL) { \
|
||||||
|
memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \
|
||||||
|
(len - pos) * (XSTEP)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSE4 variants of the fancy upsampler.
|
||||||
|
SSE4_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE41, VP8YuvToRgb, 3)
|
||||||
|
SSE4_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE41, VP8YuvToBgr, 3)
|
||||||
|
|
||||||
|
#undef GET_M
|
||||||
|
#undef PACK_AND_STORE
|
||||||
|
#undef UPSAMPLE_32PIXELS
|
||||||
|
#undef UPSAMPLE_LAST_BLOCK
|
||||||
|
#undef CONVERT2RGB
|
||||||
|
#undef CONVERT2RGB_32
|
||||||
|
#undef SSE4_UPSAMPLE_FUNC
|
||||||
|
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
|
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||||
|
|
||||||
|
extern void WebPInitUpsamplersSSE41(void);
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE41(void) {
|
||||||
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
|
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE41;
|
||||||
|
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE41;
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FANCY_UPSAMPLING
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
||||||
|
extern void WebPInitYUV444ConvertersSSE41(void);
|
||||||
|
|
||||||
|
#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \
|
||||||
|
extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
|
uint8_t* dst, int len); \
|
||||||
|
static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
|
||||||
|
uint8_t* dst, int len) { \
|
||||||
|
int i; \
|
||||||
|
const int max_len = len & ~31; \
|
||||||
|
for (i = 0; i < max_len; i += 32) { \
|
||||||
|
CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \
|
||||||
|
} \
|
||||||
|
if (i < len) { /* C-fallback */ \
|
||||||
|
CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
|
YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3);
|
||||||
|
YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3);
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) {
|
||||||
|
#if !defined(WEBP_REDUCE_CSP)
|
||||||
|
WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE41;
|
||||||
|
WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE41;
|
||||||
|
#endif // WEBP_REDUCE_CSP
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE41)
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
|
|
||||||
|
#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE41))
|
||||||
|
WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE41)
|
||||||
|
#endif
|
||||||
|
|
@ -11,63 +11,11 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#if defined(WEBP_YUV_USE_TABLE)
|
|
||||||
|
|
||||||
static int done = 0;
|
|
||||||
|
|
||||||
static WEBP_INLINE uint8_t clip(int v, int max_value) {
|
|
||||||
return v < 0 ? 0 : v > max_value ? max_value : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t VP8kVToR[256], VP8kUToB[256];
|
|
||||||
int32_t VP8kVToG[256], VP8kUToG[256];
|
|
||||||
uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
|
||||||
uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {
|
|
||||||
int i;
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifndef USE_YUVj
|
|
||||||
for (i = 0; i < 256; ++i) {
|
|
||||||
VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
|
|
||||||
VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
|
|
||||||
VP8kVToG[i] = -45773 * (i - 128);
|
|
||||||
VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
|
|
||||||
}
|
|
||||||
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
|
|
||||||
const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
|
|
||||||
VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
|
|
||||||
VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (i = 0; i < 256; ++i) {
|
|
||||||
VP8kVToR[i] = (91881 * (i - 128) + YUV_HALF) >> YUV_FIX;
|
|
||||||
VP8kUToG[i] = -22554 * (i - 128) + YUV_HALF;
|
|
||||||
VP8kVToG[i] = -46802 * (i - 128);
|
|
||||||
VP8kUToB[i] = (116130 * (i - 128) + YUV_HALF) >> YUV_FIX;
|
|
||||||
}
|
|
||||||
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
|
|
||||||
const int k = i;
|
|
||||||
VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
|
|
||||||
VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {}
|
|
||||||
|
|
||||||
#endif // WEBP_YUV_USE_TABLE
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Plain-C version
|
// Plain-C version
|
||||||
|
|
||||||
|
|
@ -75,14 +23,14 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {}
|
||||||
static void FUNC_NAME(const uint8_t* y, \
|
static void FUNC_NAME(const uint8_t* y, \
|
||||||
const uint8_t* u, const uint8_t* v, \
|
const uint8_t* u, const uint8_t* v, \
|
||||||
uint8_t* dst, int len) { \
|
uint8_t* dst, int len) { \
|
||||||
const uint8_t* const end = dst + (len & ~1) * XSTEP; \
|
const uint8_t* const end = dst + (len & ~1) * (XSTEP); \
|
||||||
while (dst != end) { \
|
while (dst != end) { \
|
||||||
FUNC(y[0], u[0], v[0], dst); \
|
FUNC(y[0], u[0], v[0], dst); \
|
||||||
FUNC(y[1], u[0], v[0], dst + XSTEP); \
|
FUNC(y[1], u[0], v[0], dst + (XSTEP)); \
|
||||||
y += 2; \
|
y += 2; \
|
||||||
++u; \
|
++u; \
|
||||||
++v; \
|
++v; \
|
||||||
dst += 2 * XSTEP; \
|
dst += 2 * (XSTEP); \
|
||||||
} \
|
} \
|
||||||
if (len & 1) { \
|
if (len & 1) { \
|
||||||
FUNC(y[0], u[0], v[0], dst); \
|
FUNC(y[0], u[0], v[0], dst); \
|
||||||
|
|
@ -123,15 +71,11 @@ void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
|
||||||
WebPSamplerRowFunc WebPSamplers[MODE_LAST];
|
WebPSamplerRowFunc WebPSamplers[MODE_LAST];
|
||||||
|
|
||||||
extern void WebPInitSamplersSSE2(void);
|
extern void WebPInitSamplersSSE2(void);
|
||||||
|
extern void WebPInitSamplersSSE41(void);
|
||||||
extern void WebPInitSamplersMIPS32(void);
|
extern void WebPInitSamplersMIPS32(void);
|
||||||
extern void WebPInitSamplersMIPSdspR2(void);
|
extern void WebPInitSamplersMIPSdspR2(void);
|
||||||
|
|
||||||
static volatile VP8CPUInfo yuv_last_cpuinfo_used =
|
WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
|
||||||
(VP8CPUInfo)&yuv_last_cpuinfo_used;
|
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
|
|
||||||
if (yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
|
|
||||||
|
|
||||||
WebPSamplers[MODE_RGB] = YuvToRgbRow;
|
WebPSamplers[MODE_RGB] = YuvToRgbRow;
|
||||||
WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
|
WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
|
||||||
WebPSamplers[MODE_BGR] = YuvToBgrRow;
|
WebPSamplers[MODE_BGR] = YuvToBgrRow;
|
||||||
|
|
@ -151,6 +95,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
|
||||||
WebPInitSamplersSSE2();
|
WebPInitSamplersSSE2();
|
||||||
}
|
}
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||||
|
WebPInitSamplersSSE41();
|
||||||
|
}
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
#if defined(WEBP_USE_MIPS32)
|
#if defined(WEBP_USE_MIPS32)
|
||||||
if (VP8GetCPUInfo(kMIPS32)) {
|
if (VP8GetCPUInfo(kMIPS32)) {
|
||||||
WebPInitSamplersMIPS32();
|
WebPInitSamplersMIPS32();
|
||||||
|
|
@ -162,13 +111,12 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
|
||||||
}
|
}
|
||||||
#endif // WEBP_USE_MIPS_DSP_R2
|
#endif // WEBP_USE_MIPS_DSP_R2
|
||||||
}
|
}
|
||||||
yuv_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// ARGB -> YUV converters
|
// ARGB -> YUV converters
|
||||||
|
|
||||||
static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
|
static void ConvertARGBToY_C(const uint32_t* argb, uint8_t* y, int width) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
const uint32_t p = argb[i];
|
const uint32_t p = argb[i];
|
||||||
|
|
@ -220,14 +168,14 @@ void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
|
static void ConvertRGB24ToY_C(const uint8_t* rgb, uint8_t* y, int width) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i, rgb += 3) {
|
for (i = 0; i < width; ++i, rgb += 3) {
|
||||||
y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
|
y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
|
static void ConvertBGR24ToY_C(const uint8_t* bgr, uint8_t* y, int width) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < width; ++i, bgr += 3) {
|
for (i = 0; i < width; ++i, bgr += 3) {
|
||||||
y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
|
y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
|
||||||
|
|
@ -246,6 +194,7 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
|
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
|
||||||
static uint16_t clip_y(int v) {
|
static uint16_t clip_y(int v) {
|
||||||
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
|
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
|
||||||
|
|
@ -283,6 +232,7 @@ static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len,
|
||||||
out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
|
out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
#undef MAX_Y
|
#undef MAX_Y
|
||||||
|
|
||||||
|
|
@ -304,26 +254,26 @@ void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src,
|
||||||
void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
|
void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
|
||||||
const uint16_t* best_y, uint16_t* out);
|
const uint16_t* best_y, uint16_t* out);
|
||||||
|
|
||||||
static volatile VP8CPUInfo rgba_to_yuv_last_cpuinfo_used =
|
|
||||||
(VP8CPUInfo)&rgba_to_yuv_last_cpuinfo_used;
|
|
||||||
|
|
||||||
extern void WebPInitConvertARGBToYUVSSE2(void);
|
extern void WebPInitConvertARGBToYUVSSE2(void);
|
||||||
|
extern void WebPInitConvertARGBToYUVSSE41(void);
|
||||||
|
extern void WebPInitConvertARGBToYUVNEON(void);
|
||||||
extern void WebPInitSharpYUVSSE2(void);
|
extern void WebPInitSharpYUVSSE2(void);
|
||||||
|
extern void WebPInitSharpYUVNEON(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) {
|
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
|
||||||
if (rgba_to_yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
|
WebPConvertARGBToY = ConvertARGBToY_C;
|
||||||
|
|
||||||
WebPConvertARGBToY = ConvertARGBToY;
|
|
||||||
WebPConvertARGBToUV = WebPConvertARGBToUV_C;
|
WebPConvertARGBToUV = WebPConvertARGBToUV_C;
|
||||||
|
|
||||||
WebPConvertRGB24ToY = ConvertRGB24ToY;
|
WebPConvertRGB24ToY = ConvertRGB24ToY_C;
|
||||||
WebPConvertBGR24ToY = ConvertBGR24ToY;
|
WebPConvertBGR24ToY = ConvertBGR24ToY_C;
|
||||||
|
|
||||||
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
|
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
|
||||||
|
|
||||||
|
#if !WEBP_NEON_OMIT_C_CODE
|
||||||
WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
|
WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
|
||||||
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
|
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
|
||||||
WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
|
WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (VP8GetCPUInfo != NULL) {
|
if (VP8GetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
@ -332,6 +282,27 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) {
|
||||||
WebPInitSharpYUVSSE2();
|
WebPInitSharpYUVSSE2();
|
||||||
}
|
}
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
if (VP8GetCPUInfo(kSSE4_1)) {
|
||||||
|
WebPInitConvertARGBToYUVSSE41();
|
||||||
|
}
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
}
|
}
|
||||||
rgba_to_yuv_last_cpuinfo_used = VP8GetCPUInfo;
|
|
||||||
|
#if defined(WEBP_USE_NEON)
|
||||||
|
if (WEBP_NEON_OMIT_C_CODE ||
|
||||||
|
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
|
||||||
|
WebPInitConvertARGBToYUVNEON();
|
||||||
|
WebPInitSharpYUVNEON();
|
||||||
|
}
|
||||||
|
#endif // WEBP_USE_NEON
|
||||||
|
|
||||||
|
assert(WebPConvertARGBToY != NULL);
|
||||||
|
assert(WebPConvertARGBToUV != NULL);
|
||||||
|
assert(WebPConvertRGB24ToY != NULL);
|
||||||
|
assert(WebPConvertBGR24ToY != NULL);
|
||||||
|
assert(WebPConvertRGBA32ToUV != NULL);
|
||||||
|
assert(WebPSharpYUVUpdateY != NULL);
|
||||||
|
assert(WebPSharpYUVUpdateRGB != NULL);
|
||||||
|
assert(WebPSharpYUVFilterRow != NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,19 +35,9 @@
|
||||||
#ifndef WEBP_DSP_YUV_H_
|
#ifndef WEBP_DSP_YUV_H_
|
||||||
#define WEBP_DSP_YUV_H_
|
#define WEBP_DSP_YUV_H_
|
||||||
|
|
||||||
#include "./dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../dec/vp8_dec.h"
|
#include "../dec/vp8_dec.h"
|
||||||
|
|
||||||
#if defined(WEBP_EXPERIMENTAL_FEATURES)
|
|
||||||
// Do NOT activate this feature for real compression. This is only experimental!
|
|
||||||
// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
|
|
||||||
// This colorspace is close to Rec.601's Y'CbCr model with the notable
|
|
||||||
// difference of allowing larger range for luma/chroma.
|
|
||||||
// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
|
|
||||||
// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
|
|
||||||
// #define USE_YUVj
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// YUV -> RGB conversion
|
// YUV -> RGB conversion
|
||||||
|
|
||||||
|
|
@ -58,12 +48,8 @@ extern "C" {
|
||||||
enum {
|
enum {
|
||||||
YUV_FIX = 16, // fixed-point precision for RGB->YUV
|
YUV_FIX = 16, // fixed-point precision for RGB->YUV
|
||||||
YUV_HALF = 1 << (YUV_FIX - 1),
|
YUV_HALF = 1 << (YUV_FIX - 1),
|
||||||
YUV_MASK = (256 << YUV_FIX) - 1,
|
|
||||||
YUV_RANGE_MIN = -227, // min value of r/g/b output
|
|
||||||
YUV_RANGE_MAX = 256 + 226, // max value of r/g/b output
|
|
||||||
|
|
||||||
YUV_FIX2 = 6, // fixed-point precision for YUV->RGB
|
YUV_FIX2 = 6, // fixed-point precision for YUV->RGB
|
||||||
YUV_HALF2 = 1 << YUV_FIX2 >> 1,
|
|
||||||
YUV_MASK2 = (256 << YUV_FIX2) - 1
|
YUV_MASK2 = (256 << YUV_FIX2) - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -111,7 +97,7 @@ static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
|
||||||
const int b = VP8YUVToB(y, u); // 5 usable bits
|
const int b = VP8YUVToB(y, u); // 5 usable bits
|
||||||
const int rg = (r & 0xf8) | (g >> 5);
|
const int rg = (r & 0xf8) | (g >> 5);
|
||||||
const int gb = ((g << 3) & 0xe0) | (b >> 3);
|
const int gb = ((g << 3) & 0xe0) | (b >> 3);
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
rgb[0] = gb;
|
rgb[0] = gb;
|
||||||
rgb[1] = rg;
|
rgb[1] = rg;
|
||||||
#else
|
#else
|
||||||
|
|
@ -127,7 +113,7 @@ static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
|
||||||
const int b = VP8YUVToB(y, u); // 4 usable bits
|
const int b = VP8YUVToB(y, u); // 4 usable bits
|
||||||
const int rg = (r & 0xf0) | (g >> 4);
|
const int rg = (r & 0xf0) | (g >> 4);
|
||||||
const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits
|
const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits
|
||||||
#ifdef WEBP_SWAP_16BIT_CSP
|
#if (WEBP_SWAP_16BIT_CSP == 1)
|
||||||
argb[0] = ba;
|
argb[0] = ba;
|
||||||
argb[1] = rg;
|
argb[1] = rg;
|
||||||
#else
|
#else
|
||||||
|
|
@ -157,32 +143,42 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
|
||||||
rgba[3] = 0xff;
|
rgba[3] = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called before everything, to initialize the tables.
|
|
||||||
void VP8YUVInit(void);
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// SSE2 extra functions (mostly for upsampling_sse2.c)
|
// SSE2 extra functions (mostly for upsampling_sse2.c)
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
|
// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
|
||||||
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst);
|
uint8_t* dst);
|
||||||
void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst);
|
|
||||||
void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst);
|
|
||||||
void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst);
|
|
||||||
void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst);
|
|
||||||
void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst);
|
uint8_t* dst);
|
||||||
void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst);
|
uint8_t* dst);
|
||||||
|
void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst);
|
||||||
|
void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst);
|
||||||
|
void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u,
|
||||||
|
const uint8_t* v, uint8_t* dst);
|
||||||
|
void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst);
|
||||||
|
|
||||||
#endif // WEBP_USE_SSE2
|
#endif // WEBP_USE_SSE2
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// SSE41 extra functions (mostly for upsampling_sse41.c)
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
|
||||||
|
// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
|
||||||
|
void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst);
|
||||||
|
void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst);
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// RGB -> YUV conversion
|
// RGB -> YUV conversion
|
||||||
|
|
||||||
|
|
@ -192,8 +188,6 @@ static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
|
||||||
return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
|
return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_YUVj
|
|
||||||
|
|
||||||
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
|
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
|
||||||
const int luma = 16839 * r + 33059 * g + 6420 * b;
|
const int luma = 16839 * r + 33059 * g + 6420 * b;
|
||||||
return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip
|
return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip
|
||||||
|
|
@ -209,28 +203,6 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
|
||||||
return VP8ClipUV(v, rounding);
|
return VP8ClipUV(v, rounding);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// This JPEG-YUV colorspace, only for comparison!
|
|
||||||
// These are also 16bit precision coefficients from Rec.601, but with full
|
|
||||||
// [0..255] output range.
|
|
||||||
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
|
|
||||||
const int luma = 19595 * r + 38470 * g + 7471 * b;
|
|
||||||
return (luma + rounding) >> YUV_FIX; // no need to clip
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
|
|
||||||
const int u = -11058 * r - 21710 * g + 32768 * b;
|
|
||||||
return VP8ClipUV(u, rounding);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
|
|
||||||
const int v = 32768 * r - 27439 * g - 5329 * b;
|
|
||||||
return VP8ClipUV(v, rounding);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // USE_YUVj
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./yuv.h"
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
#if defined(WEBP_USE_SSE2)
|
#if defined(WEBP_USE_SSE2)
|
||||||
|
|
||||||
#include "./common_sse2.h"
|
#include "../dsp/common_sse2.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
|
|
@ -26,12 +26,12 @@
|
||||||
// R = (19077 * y + 26149 * v - 14234) >> 6
|
// R = (19077 * y + 26149 * v - 14234) >> 6
|
||||||
// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6
|
// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6
|
||||||
// B = (19077 * y + 33050 * u - 17685) >> 6
|
// B = (19077 * y + 33050 * u - 17685) >> 6
|
||||||
static void ConvertYUV444ToRGB(const __m128i* const Y0,
|
static void ConvertYUV444ToRGB_SSE2(const __m128i* const Y0,
|
||||||
const __m128i* const U0,
|
const __m128i* const U0,
|
||||||
const __m128i* const V0,
|
const __m128i* const V0,
|
||||||
__m128i* const R,
|
__m128i* const R,
|
||||||
__m128i* const G,
|
__m128i* const G,
|
||||||
__m128i* const B) {
|
__m128i* const B) {
|
||||||
const __m128i k19077 = _mm_set1_epi16(19077);
|
const __m128i k19077 = _mm_set1_epi16(19077);
|
||||||
const __m128i k26149 = _mm_set1_epi16(26149);
|
const __m128i k26149 = _mm_set1_epi16(26149);
|
||||||
const __m128i k14234 = _mm_set1_epi16(14234);
|
const __m128i k14234 = _mm_set1_epi16(14234);
|
||||||
|
|
@ -66,13 +66,13 @@ static void ConvertYUV444ToRGB(const __m128i* const Y0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
|
// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
|
||||||
static WEBP_INLINE __m128i Load_HI_16(const uint8_t* src) {
|
static WEBP_INLINE __m128i Load_HI_16_SSE2(const uint8_t* src) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
|
return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load and replicate the U/V samples
|
// Load and replicate the U/V samples
|
||||||
static WEBP_INLINE __m128i Load_UV_HI_8(const uint8_t* src) {
|
static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
|
const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
|
||||||
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
|
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
|
||||||
|
|
@ -80,29 +80,33 @@ static WEBP_INLINE __m128i Load_UV_HI_8(const uint8_t* src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert 32 samples of YUV444 to R/G/B
|
// Convert 32 samples of YUV444 to R/G/B
|
||||||
static void YUV444ToRGB(const uint8_t* const y,
|
static void YUV444ToRGB_SSE2(const uint8_t* const y,
|
||||||
const uint8_t* const u,
|
const uint8_t* const u,
|
||||||
const uint8_t* const v,
|
const uint8_t* const v,
|
||||||
__m128i* const R, __m128i* const G, __m128i* const B) {
|
__m128i* const R, __m128i* const G,
|
||||||
const __m128i Y0 = Load_HI_16(y), U0 = Load_HI_16(u), V0 = Load_HI_16(v);
|
__m128i* const B) {
|
||||||
ConvertYUV444ToRGB(&Y0, &U0, &V0, R, G, B);
|
const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_HI_16_SSE2(u),
|
||||||
|
V0 = Load_HI_16_SSE2(v);
|
||||||
|
ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert 32 samples of YUV420 to R/G/B
|
// Convert 32 samples of YUV420 to R/G/B
|
||||||
static void YUV420ToRGB(const uint8_t* const y,
|
static void YUV420ToRGB_SSE2(const uint8_t* const y,
|
||||||
const uint8_t* const u,
|
const uint8_t* const u,
|
||||||
const uint8_t* const v,
|
const uint8_t* const v,
|
||||||
__m128i* const R, __m128i* const G, __m128i* const B) {
|
__m128i* const R, __m128i* const G,
|
||||||
const __m128i Y0 = Load_HI_16(y), U0 = Load_UV_HI_8(u), V0 = Load_UV_HI_8(v);
|
__m128i* const B) {
|
||||||
ConvertYUV444ToRGB(&Y0, &U0, &V0, R, G, B);
|
const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_UV_HI_8_SSE2(u),
|
||||||
|
V0 = Load_UV_HI_8_SSE2(v);
|
||||||
|
ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack R/G/B/A results into 32b output.
|
// Pack R/G/B/A results into 32b output.
|
||||||
static WEBP_INLINE void PackAndStore4(const __m128i* const R,
|
static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R,
|
||||||
const __m128i* const G,
|
const __m128i* const G,
|
||||||
const __m128i* const B,
|
const __m128i* const B,
|
||||||
const __m128i* const A,
|
const __m128i* const A,
|
||||||
uint8_t* const dst) {
|
uint8_t* const dst) {
|
||||||
const __m128i rb = _mm_packus_epi16(*R, *B);
|
const __m128i rb = _mm_packus_epi16(*R, *B);
|
||||||
const __m128i ga = _mm_packus_epi16(*G, *A);
|
const __m128i ga = _mm_packus_epi16(*G, *A);
|
||||||
const __m128i rg = _mm_unpacklo_epi8(rb, ga);
|
const __m128i rg = _mm_unpacklo_epi8(rb, ga);
|
||||||
|
|
@ -114,12 +118,12 @@ static WEBP_INLINE void PackAndStore4(const __m128i* const R,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack R/G/B/A results into 16b output.
|
// Pack R/G/B/A results into 16b output.
|
||||||
static WEBP_INLINE void PackAndStore4444(const __m128i* const R,
|
static WEBP_INLINE void PackAndStore4444_SSE2(const __m128i* const R,
|
||||||
const __m128i* const G,
|
const __m128i* const G,
|
||||||
const __m128i* const B,
|
const __m128i* const B,
|
||||||
const __m128i* const A,
|
const __m128i* const A,
|
||||||
uint8_t* const dst) {
|
uint8_t* const dst) {
|
||||||
#if !defined(WEBP_SWAP_16BIT_CSP)
|
#if (WEBP_SWAP_16BIT_CSP == 0)
|
||||||
const __m128i rg0 = _mm_packus_epi16(*R, *G);
|
const __m128i rg0 = _mm_packus_epi16(*R, *G);
|
||||||
const __m128i ba0 = _mm_packus_epi16(*B, *A);
|
const __m128i ba0 = _mm_packus_epi16(*B, *A);
|
||||||
#else
|
#else
|
||||||
|
|
@ -136,10 +140,10 @@ static WEBP_INLINE void PackAndStore4444(const __m128i* const R,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack R/G/B results into 16b output.
|
// Pack R/G/B results into 16b output.
|
||||||
static WEBP_INLINE void PackAndStore565(const __m128i* const R,
|
static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R,
|
||||||
const __m128i* const G,
|
const __m128i* const G,
|
||||||
const __m128i* const B,
|
const __m128i* const B,
|
||||||
uint8_t* const dst) {
|
uint8_t* const dst) {
|
||||||
const __m128i r0 = _mm_packus_epi16(*R, *R);
|
const __m128i r0 = _mm_packus_epi16(*R, *R);
|
||||||
const __m128i g0 = _mm_packus_epi16(*G, *G);
|
const __m128i g0 = _mm_packus_epi16(*G, *G);
|
||||||
const __m128i b0 = _mm_packus_epi16(*B, *B);
|
const __m128i b0 = _mm_packus_epi16(*B, *B);
|
||||||
|
|
@ -149,7 +153,7 @@ static WEBP_INLINE void PackAndStore565(const __m128i* const R,
|
||||||
const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3);
|
const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3);
|
||||||
const __m128i rg = _mm_or_si128(r1, g1);
|
const __m128i rg = _mm_or_si128(r1, g1);
|
||||||
const __m128i gb = _mm_or_si128(g2, b1);
|
const __m128i gb = _mm_or_si128(g2, b1);
|
||||||
#if !defined(WEBP_SWAP_16BIT_CSP)
|
#if (WEBP_SWAP_16BIT_CSP == 0)
|
||||||
const __m128i rgb565 = _mm_unpacklo_epi8(rg, gb);
|
const __m128i rgb565 = _mm_unpacklo_epi8(rg, gb);
|
||||||
#else
|
#else
|
||||||
const __m128i rgb565 = _mm_unpacklo_epi8(gb, rg);
|
const __m128i rgb565 = _mm_unpacklo_epi8(gb, rg);
|
||||||
|
|
@ -160,10 +164,10 @@ static WEBP_INLINE void PackAndStore565(const __m128i* const R,
|
||||||
// Pack the planar buffers
|
// Pack the planar buffers
|
||||||
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
||||||
static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1,
|
||||||
__m128i* const in2, __m128i* const in3,
|
__m128i* const in2, __m128i* const in3,
|
||||||
__m128i* const in4, __m128i* const in5,
|
__m128i* const in4, __m128i* const in5,
|
||||||
uint8_t* const rgb) {
|
uint8_t* const rgb) {
|
||||||
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
||||||
// let's take 6 registers of four 8b values.
|
// let's take 6 registers of four 8b values.
|
||||||
// To pack, we will keep taking one every two 8b integer and move it
|
// To pack, we will keep taking one every two 8b integer and move it
|
||||||
|
|
@ -176,7 +180,7 @@ static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
||||||
// Repeat the same permutations twice more:
|
// Repeat the same permutations twice more:
|
||||||
// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
|
// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
|
||||||
// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
|
// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
|
||||||
VP8PlanarTo24b(in0, in1, in2, in3, in4, in5);
|
VP8PlanarTo24b_SSE2(in0, in1, in2, in3, in4, in5);
|
||||||
|
|
||||||
_mm_storeu_si128((__m128i*)(rgb + 0), *in0);
|
_mm_storeu_si128((__m128i*)(rgb + 0), *in0);
|
||||||
_mm_storeu_si128((__m128i*)(rgb + 16), *in1);
|
_mm_storeu_si128((__m128i*)(rgb + 16), *in1);
|
||||||
|
|
@ -186,69 +190,69 @@ static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
|
||||||
_mm_storeu_si128((__m128i*)(rgb + 80), *in5);
|
_mm_storeu_si128((__m128i*)(rgb + 80), *in5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < 32; n += 8, dst += 32) {
|
for (n = 0; n < 32; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
|
YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
|
||||||
PackAndStore4(&R, &G, &B, &kAlpha, dst);
|
PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < 32; n += 8, dst += 32) {
|
for (n = 0; n < 32; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
|
YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
|
||||||
PackAndStore4(&B, &G, &R, &kAlpha, dst);
|
PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n < 32; n += 8, dst += 32) {
|
for (n = 0; n < 32; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
|
YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
|
||||||
PackAndStore4(&kAlpha, &R, &G, &B, dst);
|
PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u,
|
||||||
|
const uint8_t* v, uint8_t* dst) {
|
||||||
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 32; n += 8, dst += 16) {
|
||||||
|
__m128i R, G, B;
|
||||||
|
YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
|
||||||
|
PackAndStore4444_SSE2(&R, &G, &B, &kAlpha, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst) {
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 32; n += 8, dst += 16) {
|
||||||
|
__m128i R, G, B;
|
||||||
|
YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
|
||||||
|
PackAndStore565_SSE2(&R, &G, &B, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < 32; n += 8, dst += 16) {
|
|
||||||
__m128i R, G, B;
|
|
||||||
YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
|
|
||||||
PackAndStore4444(&R, &G, &B, &kAlpha, dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst) {
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < 32; n += 8, dst += 16) {
|
|
||||||
__m128i R, G, B;
|
|
||||||
YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
|
|
||||||
PackAndStore565(&R, &G, &B, dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
|
||||||
uint8_t* dst) {
|
|
||||||
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
||||||
|
|
||||||
YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
||||||
YUV444ToRGB(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
||||||
YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
||||||
|
|
||||||
// Cast to 8b and store as RRRRGGGGBBBB.
|
// Cast to 8b and store as RRRRGGGGBBBB.
|
||||||
rgb0 = _mm_packus_epi16(R0, R1);
|
rgb0 = _mm_packus_epi16(R0, R1);
|
||||||
|
|
@ -259,18 +263,18 @@ void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
rgb5 = _mm_packus_epi16(B2, B3);
|
rgb5 = _mm_packus_epi16(B2, B3);
|
||||||
|
|
||||||
// Pack as RGBRGBRGBRGB.
|
// Pack as RGBRGBRGBRGB.
|
||||||
PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
uint8_t* dst) {
|
uint8_t* dst) {
|
||||||
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
||||||
|
|
||||||
YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
||||||
YUV444ToRGB(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
||||||
YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
||||||
|
|
||||||
// Cast to 8b and store as BBBBGGGGRRRR.
|
// Cast to 8b and store as BBBBGGGGRRRR.
|
||||||
bgr0 = _mm_packus_epi16(B0, B1);
|
bgr0 = _mm_packus_epi16(B0, B1);
|
||||||
|
|
@ -281,20 +285,21 @@ void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
bgr5= _mm_packus_epi16(R2, R3);
|
bgr5= _mm_packus_epi16(R2, R3);
|
||||||
|
|
||||||
// Pack as BGRBGRBGRBGR.
|
// Pack as BGRBGRBGRBGR.
|
||||||
PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Arbitrary-length row conversion functions
|
// Arbitrary-length row conversion functions
|
||||||
|
|
||||||
static void YuvToRgbaRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
static void YuvToRgbaRow_SSE2(const uint8_t* y,
|
||||||
uint8_t* dst, int len) {
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV420ToRGB(y, u, v, &R, &G, &B);
|
YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
|
||||||
PackAndStore4(&R, &G, &B, &kAlpha, dst);
|
PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
|
||||||
y += 8;
|
y += 8;
|
||||||
u += 4;
|
u += 4;
|
||||||
v += 4;
|
v += 4;
|
||||||
|
|
@ -308,14 +313,15 @@ static void YuvToRgbaRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void YuvToBgraRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
static void YuvToBgraRow_SSE2(const uint8_t* y,
|
||||||
uint8_t* dst, int len) {
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV420ToRGB(y, u, v, &R, &G, &B);
|
YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
|
||||||
PackAndStore4(&B, &G, &R, &kAlpha, dst);
|
PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
|
||||||
y += 8;
|
y += 8;
|
||||||
u += 4;
|
u += 4;
|
||||||
v += 4;
|
v += 4;
|
||||||
|
|
@ -329,14 +335,15 @@ static void YuvToBgraRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void YuvToArgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
static void YuvToArgbRow_SSE2(const uint8_t* y,
|
||||||
uint8_t* dst, int len) {
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
const __m128i kAlpha = _mm_set1_epi16(255);
|
const __m128i kAlpha = _mm_set1_epi16(255);
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
|
||||||
__m128i R, G, B;
|
__m128i R, G, B;
|
||||||
YUV420ToRGB(y, u, v, &R, &G, &B);
|
YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
|
||||||
PackAndStore4(&kAlpha, &R, &G, &B, dst);
|
PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
|
||||||
y += 8;
|
y += 8;
|
||||||
u += 4;
|
u += 4;
|
||||||
v += 4;
|
v += 4;
|
||||||
|
|
@ -350,17 +357,18 @@ static void YuvToArgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
static void YuvToRgbRow_SSE2(const uint8_t* y,
|
||||||
uint8_t* dst, int len) {
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
||||||
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
||||||
|
|
||||||
YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
||||||
YUV420ToRGB(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
||||||
YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
||||||
|
|
||||||
// Cast to 8b and store as RRRRGGGGBBBB.
|
// Cast to 8b and store as RRRRGGGGBBBB.
|
||||||
rgb0 = _mm_packus_epi16(R0, R1);
|
rgb0 = _mm_packus_epi16(R0, R1);
|
||||||
|
|
@ -371,7 +379,7 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
rgb5 = _mm_packus_epi16(B2, B3);
|
rgb5 = _mm_packus_epi16(B2, B3);
|
||||||
|
|
||||||
// Pack as RGBRGBRGBRGB.
|
// Pack as RGBRGBRGBRGB.
|
||||||
PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
||||||
|
|
||||||
y += 32;
|
y += 32;
|
||||||
u += 16;
|
u += 16;
|
||||||
|
|
@ -386,17 +394,18 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
static void YuvToBgrRow_SSE2(const uint8_t* y,
|
||||||
uint8_t* dst, int len) {
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
int n;
|
int n;
|
||||||
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
||||||
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
||||||
|
|
||||||
YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
||||||
YUV420ToRGB(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
||||||
YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
||||||
|
|
||||||
// Cast to 8b and store as BBBBGGGGRRRR.
|
// Cast to 8b and store as BBBBGGGGRRRR.
|
||||||
bgr0 = _mm_packus_epi16(B0, B1);
|
bgr0 = _mm_packus_epi16(B0, B1);
|
||||||
|
|
@ -407,7 +416,7 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
bgr5 = _mm_packus_epi16(R2, R3);
|
bgr5 = _mm_packus_epi16(R2, R3);
|
||||||
|
|
||||||
// Pack as BGRBGRBGRBGR.
|
// Pack as BGRBGRBGRBGR.
|
||||||
PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
||||||
|
|
||||||
y += 32;
|
y += 32;
|
||||||
u += 16;
|
u += 16;
|
||||||
|
|
@ -428,11 +437,11 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
extern void WebPInitSamplersSSE2(void);
|
extern void WebPInitSamplersSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
|
||||||
WebPSamplers[MODE_RGB] = YuvToRgbRow;
|
WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE2;
|
||||||
WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
|
WebPSamplers[MODE_RGBA] = YuvToRgbaRow_SSE2;
|
||||||
WebPSamplers[MODE_BGR] = YuvToBgrRow;
|
WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE2;
|
||||||
WebPSamplers[MODE_BGRA] = YuvToBgraRow;
|
WebPSamplers[MODE_BGRA] = YuvToBgraRow_SSE2;
|
||||||
WebPSamplers[MODE_ARGB] = YuvToArgbRow;
|
WebPSamplers[MODE_ARGB] = YuvToArgbRow_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -445,7 +454,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
|
||||||
|
|
||||||
// Function that inserts a value of the second half of the in buffer in between
|
// Function that inserts a value of the second half of the in buffer in between
|
||||||
// every two char of the first half.
|
// every two char of the first half.
|
||||||
static WEBP_INLINE void RGB24PackedToPlanarHelper(
|
static WEBP_INLINE void RGB24PackedToPlanarHelper_SSE2(
|
||||||
const __m128i* const in /*in[6]*/, __m128i* const out /*out[6]*/) {
|
const __m128i* const in /*in[6]*/, __m128i* const out /*out[6]*/) {
|
||||||
out[0] = _mm_unpacklo_epi8(in[0], in[3]);
|
out[0] = _mm_unpacklo_epi8(in[0], in[3]);
|
||||||
out[1] = _mm_unpackhi_epi8(in[0], in[3]);
|
out[1] = _mm_unpackhi_epi8(in[0], in[3]);
|
||||||
|
|
@ -458,8 +467,8 @@ static WEBP_INLINE void RGB24PackedToPlanarHelper(
|
||||||
// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
|
// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
|
||||||
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
// Similar to PlanarTo24bHelper(), but in reverse order.
|
// Similar to PlanarTo24bHelper(), but in reverse order.
|
||||||
static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb,
|
static WEBP_INLINE void RGB24PackedToPlanar_SSE2(
|
||||||
__m128i* const out /*out[6]*/) {
|
const uint8_t* const rgb, __m128i* const out /*out[6]*/) {
|
||||||
__m128i tmp[6];
|
__m128i tmp[6];
|
||||||
tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0));
|
tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0));
|
||||||
tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16));
|
tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16));
|
||||||
|
|
@ -468,22 +477,22 @@ static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb,
|
||||||
tmp[4] = _mm_loadu_si128((const __m128i*)(rgb + 64));
|
tmp[4] = _mm_loadu_si128((const __m128i*)(rgb + 64));
|
||||||
tmp[5] = _mm_loadu_si128((const __m128i*)(rgb + 80));
|
tmp[5] = _mm_loadu_si128((const __m128i*)(rgb + 80));
|
||||||
|
|
||||||
RGB24PackedToPlanarHelper(tmp, out);
|
RGB24PackedToPlanarHelper_SSE2(tmp, out);
|
||||||
RGB24PackedToPlanarHelper(out, tmp);
|
RGB24PackedToPlanarHelper_SSE2(out, tmp);
|
||||||
RGB24PackedToPlanarHelper(tmp, out);
|
RGB24PackedToPlanarHelper_SSE2(tmp, out);
|
||||||
RGB24PackedToPlanarHelper(out, tmp);
|
RGB24PackedToPlanarHelper_SSE2(out, tmp);
|
||||||
RGB24PackedToPlanarHelper(tmp, out);
|
RGB24PackedToPlanarHelper_SSE2(tmp, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert 8 packed ARGB to r[], g[], b[]
|
// Convert 8 packed ARGB to r[], g[], b[]
|
||||||
static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb,
|
static WEBP_INLINE void RGB32PackedToPlanar_SSE2(const uint32_t* const argb,
|
||||||
__m128i* const rgb /*in[6]*/) {
|
__m128i* const rgb /*in[6]*/) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
__m128i a0 = LOAD_16(argb + 0);
|
__m128i a0 = LOAD_16(argb + 0);
|
||||||
__m128i a1 = LOAD_16(argb + 4);
|
__m128i a1 = LOAD_16(argb + 4);
|
||||||
__m128i a2 = LOAD_16(argb + 8);
|
__m128i a2 = LOAD_16(argb + 8);
|
||||||
__m128i a3 = LOAD_16(argb + 12);
|
__m128i a3 = LOAD_16(argb + 12);
|
||||||
VP8L32bToPlanar(&a0, &a1, &a2, &a3);
|
VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3);
|
||||||
rgb[0] = _mm_unpacklo_epi8(a1, zero);
|
rgb[0] = _mm_unpacklo_epi8(a1, zero);
|
||||||
rgb[1] = _mm_unpackhi_epi8(a1, zero);
|
rgb[1] = _mm_unpackhi_epi8(a1, zero);
|
||||||
rgb[2] = _mm_unpacklo_epi8(a2, zero);
|
rgb[2] = _mm_unpacklo_epi8(a2, zero);
|
||||||
|
|
@ -511,10 +520,10 @@ static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb,
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
|
#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
|
||||||
static WEBP_INLINE void ConvertRGBToY(const __m128i* const R,
|
static WEBP_INLINE void ConvertRGBToY_SSE2(const __m128i* const R,
|
||||||
const __m128i* const G,
|
const __m128i* const G,
|
||||||
const __m128i* const B,
|
const __m128i* const B,
|
||||||
__m128i* const Y) {
|
__m128i* const Y) {
|
||||||
const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
|
const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
|
||||||
const __m128i kGB_y = MK_CST_16(16384, 6420);
|
const __m128i kGB_y = MK_CST_16(16384, 6420);
|
||||||
const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
|
const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
|
||||||
|
|
@ -526,10 +535,11 @@ static WEBP_INLINE void ConvertRGBToY(const __m128i* const R,
|
||||||
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
|
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE void ConvertRGBToUV(const __m128i* const R,
|
static WEBP_INLINE void ConvertRGBToUV_SSE2(const __m128i* const R,
|
||||||
const __m128i* const G,
|
const __m128i* const G,
|
||||||
const __m128i* const B,
|
const __m128i* const B,
|
||||||
__m128i* const U, __m128i* const V) {
|
__m128i* const U,
|
||||||
|
__m128i* const V) {
|
||||||
const __m128i kRG_u = MK_CST_16(-9719, -19081);
|
const __m128i kRG_u = MK_CST_16(-9719, -19081);
|
||||||
const __m128i kGB_u = MK_CST_16(0, 28800);
|
const __m128i kGB_u = MK_CST_16(0, 28800);
|
||||||
const __m128i kRG_v = MK_CST_16(28800, 0);
|
const __m128i kRG_v = MK_CST_16(28800, 0);
|
||||||
|
|
@ -549,14 +559,14 @@ static WEBP_INLINE void ConvertRGBToUV(const __m128i* const R,
|
||||||
#undef MK_CST_16
|
#undef MK_CST_16
|
||||||
#undef TRANSFORM
|
#undef TRANSFORM
|
||||||
|
|
||||||
static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
|
static void ConvertRGB24ToY_SSE2(const uint8_t* rgb, uint8_t* y, int width) {
|
||||||
const int max_width = width & ~31;
|
const int max_width = width & ~31;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
|
for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
|
||||||
__m128i rgb_plane[6];
|
__m128i rgb_plane[6];
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
RGB24PackedToPlanar(rgb, rgb_plane);
|
RGB24PackedToPlanar_SSE2(rgb, rgb_plane);
|
||||||
|
|
||||||
for (j = 0; j < 2; ++j, i += 16) {
|
for (j = 0; j < 2; ++j, i += 16) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
|
@ -566,13 +576,13 @@ static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
|
||||||
r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero);
|
r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero);
|
||||||
g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
|
g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
|
||||||
b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero);
|
b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero);
|
||||||
ConvertRGBToY(&r, &g, &b, &Y0);
|
ConvertRGBToY_SSE2(&r, &g, &b, &Y0);
|
||||||
|
|
||||||
// Convert to 16-bit Y.
|
// Convert to 16-bit Y.
|
||||||
r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero);
|
r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero);
|
||||||
g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
|
g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
|
||||||
b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero);
|
b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero);
|
||||||
ConvertRGBToY(&r, &g, &b, &Y1);
|
ConvertRGBToY_SSE2(&r, &g, &b, &Y1);
|
||||||
|
|
||||||
// Cast to 8-bit and store.
|
// Cast to 8-bit and store.
|
||||||
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
|
|
@ -583,14 +593,14 @@ static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
|
static void ConvertBGR24ToY_SSE2(const uint8_t* bgr, uint8_t* y, int width) {
|
||||||
const int max_width = width & ~31;
|
const int max_width = width & ~31;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
|
for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
|
||||||
__m128i bgr_plane[6];
|
__m128i bgr_plane[6];
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
RGB24PackedToPlanar(bgr, bgr_plane);
|
RGB24PackedToPlanar_SSE2(bgr, bgr_plane);
|
||||||
|
|
||||||
for (j = 0; j < 2; ++j, i += 16) {
|
for (j = 0; j < 2; ++j, i += 16) {
|
||||||
const __m128i zero = _mm_setzero_si128();
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
|
@ -600,13 +610,13 @@ static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
|
||||||
b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero);
|
b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero);
|
||||||
g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero);
|
g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero);
|
||||||
r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero);
|
r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero);
|
||||||
ConvertRGBToY(&r, &g, &b, &Y0);
|
ConvertRGBToY_SSE2(&r, &g, &b, &Y0);
|
||||||
|
|
||||||
// Convert to 16-bit Y.
|
// Convert to 16-bit Y.
|
||||||
b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero);
|
b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero);
|
||||||
g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero);
|
g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero);
|
||||||
r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero);
|
r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero);
|
||||||
ConvertRGBToY(&r, &g, &b, &Y1);
|
ConvertRGBToY_SSE2(&r, &g, &b, &Y1);
|
||||||
|
|
||||||
// Cast to 8-bit and store.
|
// Cast to 8-bit and store.
|
||||||
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
|
|
@ -617,14 +627,14 @@ static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
|
static void ConvertARGBToY_SSE2(const uint32_t* argb, uint8_t* y, int width) {
|
||||||
const int max_width = width & ~15;
|
const int max_width = width & ~15;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < max_width; i += 16) {
|
for (i = 0; i < max_width; i += 16) {
|
||||||
__m128i Y0, Y1, rgb[6];
|
__m128i Y0, Y1, rgb[6];
|
||||||
RGB32PackedToPlanar(&argb[i], rgb);
|
RGB32PackedToPlanar_SSE2(&argb[i], rgb);
|
||||||
ConvertRGBToY(&rgb[0], &rgb[2], &rgb[4], &Y0);
|
ConvertRGBToY_SSE2(&rgb[0], &rgb[2], &rgb[4], &Y0);
|
||||||
ConvertRGBToY(&rgb[1], &rgb[3], &rgb[5], &Y1);
|
ConvertRGBToY_SSE2(&rgb[1], &rgb[3], &rgb[5], &Y1);
|
||||||
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
}
|
}
|
||||||
for (; i < width; ++i) { // left-over
|
for (; i < width; ++i) { // left-over
|
||||||
|
|
@ -636,31 +646,33 @@ static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
|
||||||
|
|
||||||
// Horizontal add (doubled) of two 16b values, result is 16b.
|
// Horizontal add (doubled) of two 16b values, result is 16b.
|
||||||
// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
|
// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
|
||||||
static void HorizontalAddPack(const __m128i* const A, const __m128i* const B,
|
static void HorizontalAddPack_SSE2(const __m128i* const A,
|
||||||
__m128i* const out) {
|
const __m128i* const B,
|
||||||
|
__m128i* const out) {
|
||||||
const __m128i k2 = _mm_set1_epi16(2);
|
const __m128i k2 = _mm_set1_epi16(2);
|
||||||
const __m128i C = _mm_madd_epi16(*A, k2);
|
const __m128i C = _mm_madd_epi16(*A, k2);
|
||||||
const __m128i D = _mm_madd_epi16(*B, k2);
|
const __m128i D = _mm_madd_epi16(*B, k2);
|
||||||
*out = _mm_packs_epi32(C, D);
|
*out = _mm_packs_epi32(C, D);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v,
|
static void ConvertARGBToUV_SSE2(const uint32_t* argb,
|
||||||
int src_width, int do_store) {
|
uint8_t* u, uint8_t* v,
|
||||||
|
int src_width, int do_store) {
|
||||||
const int max_width = src_width & ~31;
|
const int max_width = src_width & ~31;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
|
for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
|
||||||
__m128i rgb[6], U0, V0, U1, V1;
|
__m128i rgb[6], U0, V0, U1, V1;
|
||||||
RGB32PackedToPlanar(&argb[i], rgb);
|
RGB32PackedToPlanar_SSE2(&argb[i], rgb);
|
||||||
HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]);
|
HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
|
||||||
HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]);
|
HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
|
||||||
HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]);
|
HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
|
||||||
ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
|
ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
|
||||||
|
|
||||||
RGB32PackedToPlanar(&argb[i + 16], rgb);
|
RGB32PackedToPlanar_SSE2(&argb[i + 16], rgb);
|
||||||
HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]);
|
HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
|
||||||
HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]);
|
HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
|
||||||
HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]);
|
HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
|
||||||
ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
|
ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
|
||||||
|
|
||||||
U0 = _mm_packus_epi16(U0, U1);
|
U0 = _mm_packus_epi16(U0, U1);
|
||||||
V0 = _mm_packus_epi16(V0, V1);
|
V0 = _mm_packus_epi16(V0, V1);
|
||||||
|
|
@ -679,10 +691,9 @@ static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert 16 packed ARGB 16b-values to r[], g[], b[]
|
// Convert 16 packed ARGB 16b-values to r[], g[], b[]
|
||||||
static WEBP_INLINE void RGBA32PackedToPlanar_16b(const uint16_t* const rgbx,
|
static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2(
|
||||||
__m128i* const r,
|
const uint16_t* const rgbx,
|
||||||
__m128i* const g,
|
__m128i* const r, __m128i* const g, __m128i* const b) {
|
||||||
__m128i* const b) {
|
|
||||||
const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
|
const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
|
||||||
const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
|
const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
|
||||||
const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
|
const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
|
||||||
|
|
@ -701,16 +712,16 @@ static WEBP_INLINE void RGBA32PackedToPlanar_16b(const uint16_t* const rgbx,
|
||||||
*b = _mm_unpacklo_epi64(B1, B3);
|
*b = _mm_unpacklo_epi64(B1, B3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertRGBA32ToUV(const uint16_t* rgb,
|
static void ConvertRGBA32ToUV_SSE2(const uint16_t* rgb,
|
||||||
uint8_t* u, uint8_t* v, int width) {
|
uint8_t* u, uint8_t* v, int width) {
|
||||||
const int max_width = width & ~15;
|
const int max_width = width & ~15;
|
||||||
const uint16_t* const last_rgb = rgb + 4 * max_width;
|
const uint16_t* const last_rgb = rgb + 4 * max_width;
|
||||||
while (rgb < last_rgb) {
|
while (rgb < last_rgb) {
|
||||||
__m128i r, g, b, U0, V0, U1, V1;
|
__m128i r, g, b, U0, V0, U1, V1;
|
||||||
RGBA32PackedToPlanar_16b(rgb + 0, &r, &g, &b);
|
RGBA32PackedToPlanar_16b_SSE2(rgb + 0, &r, &g, &b);
|
||||||
ConvertRGBToUV(&r, &g, &b, &U0, &V0);
|
ConvertRGBToUV_SSE2(&r, &g, &b, &U0, &V0);
|
||||||
RGBA32PackedToPlanar_16b(rgb + 32, &r, &g, &b);
|
RGBA32PackedToPlanar_16b_SSE2(rgb + 32, &r, &g, &b);
|
||||||
ConvertRGBToUV(&r, &g, &b, &U1, &V1);
|
ConvertRGBToUV_SSE2(&r, &g, &b, &U1, &V1);
|
||||||
STORE_16(_mm_packus_epi16(U0, U1), u);
|
STORE_16(_mm_packus_epi16(U0, U1), u);
|
||||||
STORE_16(_mm_packus_epi16(V0, V1), v);
|
STORE_16(_mm_packus_epi16(V0, V1), v);
|
||||||
u += 16;
|
u += 16;
|
||||||
|
|
@ -727,13 +738,13 @@ static void ConvertRGBA32ToUV(const uint16_t* rgb,
|
||||||
extern void WebPInitConvertARGBToYUVSSE2(void);
|
extern void WebPInitConvertARGBToYUVSSE2(void);
|
||||||
|
|
||||||
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
|
||||||
WebPConvertARGBToY = ConvertARGBToY;
|
WebPConvertARGBToY = ConvertARGBToY_SSE2;
|
||||||
WebPConvertARGBToUV = ConvertARGBToUV;
|
WebPConvertARGBToUV = ConvertARGBToUV_SSE2;
|
||||||
|
|
||||||
WebPConvertRGB24ToY = ConvertRGB24ToY;
|
WebPConvertRGB24ToY = ConvertRGB24ToY_SSE2;
|
||||||
WebPConvertBGR24ToY = ConvertBGR24ToY;
|
WebPConvertBGR24ToY = ConvertBGR24ToY_SSE2;
|
||||||
|
|
||||||
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV;
|
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
613
media/libwebp/dsp/yuv_sse41.c
Normal file
613
media/libwebp/dsp/yuv_sse41.c
Normal file
|
|
@ -0,0 +1,613 @@
|
||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the COPYING file in the root of the source
|
||||||
|
// tree. An additional intellectual property rights grant can be found
|
||||||
|
// in the file PATENTS. All contributing project authors may
|
||||||
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// YUV->RGB conversion functions
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include "../dsp/yuv.h"
|
||||||
|
|
||||||
|
#if defined(WEBP_USE_SSE41)
|
||||||
|
|
||||||
|
#include "../dsp/common_sse41.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <smmintrin.h>
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
|
||||||
|
|
||||||
|
// These constants are 14b fixed-point version of ITU-R BT.601 constants.
|
||||||
|
// R = (19077 * y + 26149 * v - 14234) >> 6
|
||||||
|
// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6
|
||||||
|
// B = (19077 * y + 33050 * u - 17685) >> 6
|
||||||
|
static void ConvertYUV444ToRGB_SSE41(const __m128i* const Y0,
|
||||||
|
const __m128i* const U0,
|
||||||
|
const __m128i* const V0,
|
||||||
|
__m128i* const R,
|
||||||
|
__m128i* const G,
|
||||||
|
__m128i* const B) {
|
||||||
|
const __m128i k19077 = _mm_set1_epi16(19077);
|
||||||
|
const __m128i k26149 = _mm_set1_epi16(26149);
|
||||||
|
const __m128i k14234 = _mm_set1_epi16(14234);
|
||||||
|
// 33050 doesn't fit in a signed short: only use this with unsigned arithmetic
|
||||||
|
const __m128i k33050 = _mm_set1_epi16((short)33050);
|
||||||
|
const __m128i k17685 = _mm_set1_epi16(17685);
|
||||||
|
const __m128i k6419 = _mm_set1_epi16(6419);
|
||||||
|
const __m128i k13320 = _mm_set1_epi16(13320);
|
||||||
|
const __m128i k8708 = _mm_set1_epi16(8708);
|
||||||
|
|
||||||
|
const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077);
|
||||||
|
|
||||||
|
const __m128i R0 = _mm_mulhi_epu16(*V0, k26149);
|
||||||
|
const __m128i R1 = _mm_sub_epi16(Y1, k14234);
|
||||||
|
const __m128i R2 = _mm_add_epi16(R1, R0);
|
||||||
|
|
||||||
|
const __m128i G0 = _mm_mulhi_epu16(*U0, k6419);
|
||||||
|
const __m128i G1 = _mm_mulhi_epu16(*V0, k13320);
|
||||||
|
const __m128i G2 = _mm_add_epi16(Y1, k8708);
|
||||||
|
const __m128i G3 = _mm_add_epi16(G0, G1);
|
||||||
|
const __m128i G4 = _mm_sub_epi16(G2, G3);
|
||||||
|
|
||||||
|
// be careful with the saturated *unsigned* arithmetic here!
|
||||||
|
const __m128i B0 = _mm_mulhi_epu16(*U0, k33050);
|
||||||
|
const __m128i B1 = _mm_adds_epu16(B0, Y1);
|
||||||
|
const __m128i B2 = _mm_subs_epu16(B1, k17685);
|
||||||
|
|
||||||
|
// use logical shift for B2, which can be larger than 32767
|
||||||
|
*R = _mm_srai_epi16(R2, 6); // range: [-14234, 30815]
|
||||||
|
*G = _mm_srai_epi16(G4, 6); // range: [-10953, 27710]
|
||||||
|
*B = _mm_srli_epi16(B2, 6); // range: [0, 34238]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
|
||||||
|
static WEBP_INLINE __m128i Load_HI_16_SSE41(const uint8_t* src) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and replicate the U/V samples
|
||||||
|
static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
|
||||||
|
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
|
||||||
|
return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert 32 samples of YUV444 to R/G/B
|
||||||
|
static void YUV444ToRGB_SSE41(const uint8_t* const y,
|
||||||
|
const uint8_t* const u,
|
||||||
|
const uint8_t* const v,
|
||||||
|
__m128i* const R, __m128i* const G,
|
||||||
|
__m128i* const B) {
|
||||||
|
const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_HI_16_SSE41(u),
|
||||||
|
V0 = Load_HI_16_SSE41(v);
|
||||||
|
ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert 32 samples of YUV420 to R/G/B
|
||||||
|
static void YUV420ToRGB_SSE41(const uint8_t* const y,
|
||||||
|
const uint8_t* const u,
|
||||||
|
const uint8_t* const v,
|
||||||
|
__m128i* const R, __m128i* const G,
|
||||||
|
__m128i* const B) {
|
||||||
|
const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_UV_HI_8_SSE41(u),
|
||||||
|
V0 = Load_UV_HI_8_SSE41(v);
|
||||||
|
ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack the planar buffers
|
||||||
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
|
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
|
||||||
|
static WEBP_INLINE void PlanarTo24b_SSE41(
|
||||||
|
__m128i* const in0, __m128i* const in1, __m128i* const in2,
|
||||||
|
__m128i* const in3, __m128i* const in4, __m128i* const in5,
|
||||||
|
uint8_t* const rgb) {
|
||||||
|
// The input is 6 registers of sixteen 8b but for the sake of explanation,
|
||||||
|
// let's take 6 registers of four 8b values.
|
||||||
|
// To pack, we will keep taking one every two 8b integer and move it
|
||||||
|
// around as follows:
|
||||||
|
// Input:
|
||||||
|
// r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
|
||||||
|
// Split the 6 registers in two sets of 3 registers: the first set as the even
|
||||||
|
// 8b bytes, the second the odd ones:
|
||||||
|
// r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
|
||||||
|
// Repeat the same permutations twice more:
|
||||||
|
// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
|
||||||
|
// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
|
||||||
|
VP8PlanarTo24b_SSE41(in0, in1, in2, in3, in4, in5);
|
||||||
|
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 0), *in0);
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 16), *in1);
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 32), *in2);
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 48), *in3);
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 64), *in4);
|
||||||
|
_mm_storeu_si128((__m128i*)(rgb + 80), *in5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst) {
|
||||||
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
|
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
||||||
|
|
||||||
|
YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
|
YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
||||||
|
YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
||||||
|
YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
||||||
|
|
||||||
|
// Cast to 8b and store as RRRRGGGGBBBB.
|
||||||
|
rgb0 = _mm_packus_epi16(R0, R1);
|
||||||
|
rgb1 = _mm_packus_epi16(R2, R3);
|
||||||
|
rgb2 = _mm_packus_epi16(G0, G1);
|
||||||
|
rgb3 = _mm_packus_epi16(G2, G3);
|
||||||
|
rgb4 = _mm_packus_epi16(B0, B1);
|
||||||
|
rgb5 = _mm_packus_epi16(B2, B3);
|
||||||
|
|
||||||
|
// Pack as RGBRGBRGBRGB.
|
||||||
|
PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst) {
|
||||||
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
|
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
||||||
|
|
||||||
|
YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
|
YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1);
|
||||||
|
YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2);
|
||||||
|
YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3);
|
||||||
|
|
||||||
|
// Cast to 8b and store as BBBBGGGGRRRR.
|
||||||
|
bgr0 = _mm_packus_epi16(B0, B1);
|
||||||
|
bgr1 = _mm_packus_epi16(B2, B3);
|
||||||
|
bgr2 = _mm_packus_epi16(G0, G1);
|
||||||
|
bgr3 = _mm_packus_epi16(G2, G3);
|
||||||
|
bgr4 = _mm_packus_epi16(R0, R1);
|
||||||
|
bgr5= _mm_packus_epi16(R2, R3);
|
||||||
|
|
||||||
|
// Pack as BGRBGRBGRBGR.
|
||||||
|
PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Arbitrary-length row conversion functions
|
||||||
|
|
||||||
|
static void YuvToRgbRow_SSE41(const uint8_t* y,
|
||||||
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
|
int n;
|
||||||
|
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
||||||
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
|
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
|
||||||
|
|
||||||
|
YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
|
YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
||||||
|
YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
||||||
|
YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
||||||
|
|
||||||
|
// Cast to 8b and store as RRRRGGGGBBBB.
|
||||||
|
rgb0 = _mm_packus_epi16(R0, R1);
|
||||||
|
rgb1 = _mm_packus_epi16(R2, R3);
|
||||||
|
rgb2 = _mm_packus_epi16(G0, G1);
|
||||||
|
rgb3 = _mm_packus_epi16(G2, G3);
|
||||||
|
rgb4 = _mm_packus_epi16(B0, B1);
|
||||||
|
rgb5 = _mm_packus_epi16(B2, B3);
|
||||||
|
|
||||||
|
// Pack as RGBRGBRGBRGB.
|
||||||
|
PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
|
||||||
|
|
||||||
|
y += 32;
|
||||||
|
u += 16;
|
||||||
|
v += 16;
|
||||||
|
}
|
||||||
|
for (; n < len; ++n) { // Finish off
|
||||||
|
VP8YuvToRgb(y[0], u[0], v[0], dst);
|
||||||
|
dst += 3;
|
||||||
|
y += 1;
|
||||||
|
u += (n & 1);
|
||||||
|
v += (n & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void YuvToBgrRow_SSE41(const uint8_t* y,
|
||||||
|
const uint8_t* u, const uint8_t* v,
|
||||||
|
uint8_t* dst, int len) {
|
||||||
|
int n;
|
||||||
|
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
|
||||||
|
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
|
||||||
|
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
|
||||||
|
|
||||||
|
YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
|
||||||
|
YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1);
|
||||||
|
YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2);
|
||||||
|
YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3);
|
||||||
|
|
||||||
|
// Cast to 8b and store as BBBBGGGGRRRR.
|
||||||
|
bgr0 = _mm_packus_epi16(B0, B1);
|
||||||
|
bgr1 = _mm_packus_epi16(B2, B3);
|
||||||
|
bgr2 = _mm_packus_epi16(G0, G1);
|
||||||
|
bgr3 = _mm_packus_epi16(G2, G3);
|
||||||
|
bgr4 = _mm_packus_epi16(R0, R1);
|
||||||
|
bgr5 = _mm_packus_epi16(R2, R3);
|
||||||
|
|
||||||
|
// Pack as BGRBGRBGRBGR.
|
||||||
|
PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
|
||||||
|
|
||||||
|
y += 32;
|
||||||
|
u += 16;
|
||||||
|
v += 16;
|
||||||
|
}
|
||||||
|
for (; n < len; ++n) { // Finish off
|
||||||
|
VP8YuvToBgr(y[0], u[0], v[0], dst);
|
||||||
|
dst += 3;
|
||||||
|
y += 1;
|
||||||
|
u += (n & 1);
|
||||||
|
v += (n & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Entry point
|
||||||
|
|
||||||
|
extern void WebPInitSamplersSSE41(void);
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE41(void) {
|
||||||
|
WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE41;
|
||||||
|
WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE41;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// RGB24/32 -> YUV converters
|
||||||
|
|
||||||
|
// Load eight 16b-words from *src.
|
||||||
|
#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src))
|
||||||
|
// Store either 16b-words into *dst
|
||||||
|
#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V))
|
||||||
|
|
||||||
|
#define WEBP_SSE41_SHUFF(OUT) do { \
|
||||||
|
const __m128i tmp0 = _mm_shuffle_epi8(A0, shuff0); \
|
||||||
|
const __m128i tmp1 = _mm_shuffle_epi8(A1, shuff1); \
|
||||||
|
const __m128i tmp2 = _mm_shuffle_epi8(A2, shuff2); \
|
||||||
|
const __m128i tmp3 = _mm_shuffle_epi8(A3, shuff0); \
|
||||||
|
const __m128i tmp4 = _mm_shuffle_epi8(A4, shuff1); \
|
||||||
|
const __m128i tmp5 = _mm_shuffle_epi8(A5, shuff2); \
|
||||||
|
\
|
||||||
|
/* OR everything to get one channel */ \
|
||||||
|
const __m128i tmp6 = _mm_or_si128(tmp0, tmp1); \
|
||||||
|
const __m128i tmp7 = _mm_or_si128(tmp3, tmp4); \
|
||||||
|
out[OUT + 0] = _mm_or_si128(tmp6, tmp2); \
|
||||||
|
out[OUT + 1] = _mm_or_si128(tmp7, tmp5); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
|
||||||
|
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
|
||||||
|
// Similar to PlanarTo24bHelper(), but in reverse order.
|
||||||
|
static WEBP_INLINE void RGB24PackedToPlanar_SSE41(
|
||||||
|
const uint8_t* const rgb, __m128i* const out /*out[6]*/) {
|
||||||
|
const __m128i A0 = _mm_loadu_si128((const __m128i*)(rgb + 0));
|
||||||
|
const __m128i A1 = _mm_loadu_si128((const __m128i*)(rgb + 16));
|
||||||
|
const __m128i A2 = _mm_loadu_si128((const __m128i*)(rgb + 32));
|
||||||
|
const __m128i A3 = _mm_loadu_si128((const __m128i*)(rgb + 48));
|
||||||
|
const __m128i A4 = _mm_loadu_si128((const __m128i*)(rgb + 64));
|
||||||
|
const __m128i A5 = _mm_loadu_si128((const __m128i*)(rgb + 80));
|
||||||
|
|
||||||
|
// Compute RR.
|
||||||
|
{
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
13, 10, 7, 4, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
|
||||||
|
WEBP_SSE41_SHUFF(0)
|
||||||
|
}
|
||||||
|
// Compute GG.
|
||||||
|
{
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
|
||||||
|
WEBP_SSE41_SHUFF(2)
|
||||||
|
}
|
||||||
|
// Compute BB.
|
||||||
|
{
|
||||||
|
const __m128i shuff0 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, 11, 8, 5, 2);
|
||||||
|
const __m128i shuff1 = _mm_set_epi8(
|
||||||
|
-1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1, -1, -1, -1, -1, -1);
|
||||||
|
const __m128i shuff2 = _mm_set_epi8(
|
||||||
|
15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
|
||||||
|
WEBP_SSE41_SHUFF(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef WEBP_SSE41_SHUFF
|
||||||
|
|
||||||
|
// Convert 8 packed ARGB to r[], g[], b[]
|
||||||
|
static WEBP_INLINE void RGB32PackedToPlanar_SSE41(
|
||||||
|
const uint32_t* const argb, __m128i* const rgb /*in[6]*/) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
__m128i a0 = LOAD_16(argb + 0);
|
||||||
|
__m128i a1 = LOAD_16(argb + 4);
|
||||||
|
__m128i a2 = LOAD_16(argb + 8);
|
||||||
|
__m128i a3 = LOAD_16(argb + 12);
|
||||||
|
VP8L32bToPlanar_SSE41(&a0, &a1, &a2, &a3);
|
||||||
|
rgb[0] = _mm_unpacklo_epi8(a1, zero);
|
||||||
|
rgb[1] = _mm_unpackhi_epi8(a1, zero);
|
||||||
|
rgb[2] = _mm_unpacklo_epi8(a2, zero);
|
||||||
|
rgb[3] = _mm_unpackhi_epi8(a2, zero);
|
||||||
|
rgb[4] = _mm_unpacklo_epi8(a3, zero);
|
||||||
|
rgb[5] = _mm_unpackhi_epi8(a3, zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX
|
||||||
|
// It's a macro and not a function because we need to use immediate values with
|
||||||
|
// srai_epi32, e.g.
|
||||||
|
#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \
|
||||||
|
ROUNDER, DESCALE_FIX, OUT) do { \
|
||||||
|
const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \
|
||||||
|
const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \
|
||||||
|
const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \
|
||||||
|
const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \
|
||||||
|
const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \
|
||||||
|
const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \
|
||||||
|
const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \
|
||||||
|
const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \
|
||||||
|
const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \
|
||||||
|
const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \
|
||||||
|
(OUT) = _mm_packs_epi32(V5_lo, V5_hi); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
|
||||||
|
static WEBP_INLINE void ConvertRGBToY_SSE41(const __m128i* const R,
|
||||||
|
const __m128i* const G,
|
||||||
|
const __m128i* const B,
|
||||||
|
__m128i* const Y) {
|
||||||
|
const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
|
||||||
|
const __m128i kGB_y = MK_CST_16(16384, 6420);
|
||||||
|
const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
|
||||||
|
|
||||||
|
const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
|
||||||
|
const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
|
||||||
|
const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
|
||||||
|
const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
|
||||||
|
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE void ConvertRGBToUV_SSE41(const __m128i* const R,
|
||||||
|
const __m128i* const G,
|
||||||
|
const __m128i* const B,
|
||||||
|
__m128i* const U,
|
||||||
|
__m128i* const V) {
|
||||||
|
const __m128i kRG_u = MK_CST_16(-9719, -19081);
|
||||||
|
const __m128i kGB_u = MK_CST_16(0, 28800);
|
||||||
|
const __m128i kRG_v = MK_CST_16(28800, 0);
|
||||||
|
const __m128i kGB_v = MK_CST_16(-24116, -4684);
|
||||||
|
const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2);
|
||||||
|
|
||||||
|
const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
|
||||||
|
const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
|
||||||
|
const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
|
||||||
|
const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
|
||||||
|
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u,
|
||||||
|
kHALF_UV, YUV_FIX + 2, *U);
|
||||||
|
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v,
|
||||||
|
kHALF_UV, YUV_FIX + 2, *V);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef MK_CST_16
|
||||||
|
#undef TRANSFORM
|
||||||
|
|
||||||
|
static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) {
|
||||||
|
const int max_width = width & ~31;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
|
||||||
|
__m128i rgb_plane[6];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
RGB24PackedToPlanar_SSE41(rgb, rgb_plane);
|
||||||
|
|
||||||
|
for (j = 0; j < 2; ++j, i += 16) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
__m128i r, g, b, Y0, Y1;
|
||||||
|
|
||||||
|
// Convert to 16-bit Y.
|
||||||
|
r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero);
|
||||||
|
g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
|
||||||
|
b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero);
|
||||||
|
ConvertRGBToY_SSE41(&r, &g, &b, &Y0);
|
||||||
|
|
||||||
|
// Convert to 16-bit Y.
|
||||||
|
r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero);
|
||||||
|
g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
|
||||||
|
b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero);
|
||||||
|
ConvertRGBToY_SSE41(&r, &g, &b, &Y1);
|
||||||
|
|
||||||
|
// Cast to 8-bit and store.
|
||||||
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < width; ++i, rgb += 3) { // left-over
|
||||||
|
y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) {
|
||||||
|
const int max_width = width & ~31;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
|
||||||
|
__m128i bgr_plane[6];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
RGB24PackedToPlanar_SSE41(bgr, bgr_plane);
|
||||||
|
|
||||||
|
for (j = 0; j < 2; ++j, i += 16) {
|
||||||
|
const __m128i zero = _mm_setzero_si128();
|
||||||
|
__m128i r, g, b, Y0, Y1;
|
||||||
|
|
||||||
|
// Convert to 16-bit Y.
|
||||||
|
b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero);
|
||||||
|
g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero);
|
||||||
|
r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero);
|
||||||
|
ConvertRGBToY_SSE41(&r, &g, &b, &Y0);
|
||||||
|
|
||||||
|
// Convert to 16-bit Y.
|
||||||
|
b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero);
|
||||||
|
g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero);
|
||||||
|
r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero);
|
||||||
|
ConvertRGBToY_SSE41(&r, &g, &b, &Y1);
|
||||||
|
|
||||||
|
// Cast to 8-bit and store.
|
||||||
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < width; ++i, bgr += 3) { // left-over
|
||||||
|
y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertARGBToY_SSE41(const uint32_t* argb, uint8_t* y, int width) {
|
||||||
|
const int max_width = width & ~15;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < max_width; i += 16) {
|
||||||
|
__m128i Y0, Y1, rgb[6];
|
||||||
|
RGB32PackedToPlanar_SSE41(&argb[i], rgb);
|
||||||
|
ConvertRGBToY_SSE41(&rgb[0], &rgb[2], &rgb[4], &Y0);
|
||||||
|
ConvertRGBToY_SSE41(&rgb[1], &rgb[3], &rgb[5], &Y1);
|
||||||
|
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
|
||||||
|
}
|
||||||
|
for (; i < width; ++i) { // left-over
|
||||||
|
const uint32_t p = argb[i];
|
||||||
|
y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff,
|
||||||
|
YUV_HALF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal add (doubled) of two 16b values, result is 16b.
|
||||||
|
// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
|
||||||
|
static void HorizontalAddPack_SSE41(const __m128i* const A,
|
||||||
|
const __m128i* const B,
|
||||||
|
__m128i* const out) {
|
||||||
|
const __m128i k2 = _mm_set1_epi16(2);
|
||||||
|
const __m128i C = _mm_madd_epi16(*A, k2);
|
||||||
|
const __m128i D = _mm_madd_epi16(*B, k2);
|
||||||
|
*out = _mm_packs_epi32(C, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertARGBToUV_SSE41(const uint32_t* argb,
|
||||||
|
uint8_t* u, uint8_t* v,
|
||||||
|
int src_width, int do_store) {
|
||||||
|
const int max_width = src_width & ~31;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
|
||||||
|
__m128i rgb[6], U0, V0, U1, V1;
|
||||||
|
RGB32PackedToPlanar_SSE41(&argb[i], rgb);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]);
|
||||||
|
ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
|
||||||
|
|
||||||
|
RGB32PackedToPlanar_SSE41(&argb[i + 16], rgb);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]);
|
||||||
|
HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]);
|
||||||
|
ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
|
||||||
|
|
||||||
|
U0 = _mm_packus_epi16(U0, U1);
|
||||||
|
V0 = _mm_packus_epi16(V0, V1);
|
||||||
|
if (!do_store) {
|
||||||
|
const __m128i prev_u = LOAD_16(u);
|
||||||
|
const __m128i prev_v = LOAD_16(v);
|
||||||
|
U0 = _mm_avg_epu8(U0, prev_u);
|
||||||
|
V0 = _mm_avg_epu8(V0, prev_v);
|
||||||
|
}
|
||||||
|
STORE_16(U0, u);
|
||||||
|
STORE_16(V0, v);
|
||||||
|
}
|
||||||
|
if (i < src_width) { // left-over
|
||||||
|
WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert 16 packed ARGB 16b-values to r[], g[], b[]
|
||||||
|
static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41(
|
||||||
|
const uint16_t* const rgbx,
|
||||||
|
__m128i* const r, __m128i* const g, __m128i* const b) {
|
||||||
|
const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
|
||||||
|
const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
|
||||||
|
const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
|
||||||
|
const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ...
|
||||||
|
// aarrggbb as 16-bit.
|
||||||
|
const __m128i shuff0 =
|
||||||
|
_mm_set_epi8(-1, -1, -1, -1, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0);
|
||||||
|
const __m128i shuff1 =
|
||||||
|
_mm_set_epi8(13, 12, 5, 4, -1, -1, -1, -1, 11, 10, 3, 2, 9, 8, 1, 0);
|
||||||
|
const __m128i A0 = _mm_shuffle_epi8(in0, shuff0);
|
||||||
|
const __m128i A1 = _mm_shuffle_epi8(in1, shuff1);
|
||||||
|
const __m128i A2 = _mm_shuffle_epi8(in2, shuff0);
|
||||||
|
const __m128i A3 = _mm_shuffle_epi8(in3, shuff1);
|
||||||
|
// R0R1G0G1
|
||||||
|
// B0B1****
|
||||||
|
// R2R3G2G3
|
||||||
|
// B2B3****
|
||||||
|
// (OR is used to free port 5 for the unpack)
|
||||||
|
const __m128i B0 = _mm_unpacklo_epi32(A0, A1);
|
||||||
|
const __m128i B1 = _mm_or_si128(A0, A1);
|
||||||
|
const __m128i B2 = _mm_unpacklo_epi32(A2, A3);
|
||||||
|
const __m128i B3 = _mm_or_si128(A2, A3);
|
||||||
|
// Gather the channels.
|
||||||
|
*r = _mm_unpacklo_epi64(B0, B2);
|
||||||
|
*g = _mm_unpackhi_epi64(B0, B2);
|
||||||
|
*b = _mm_unpackhi_epi64(B1, B3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertRGBA32ToUV_SSE41(const uint16_t* rgb,
|
||||||
|
uint8_t* u, uint8_t* v, int width) {
|
||||||
|
const int max_width = width & ~15;
|
||||||
|
const uint16_t* const last_rgb = rgb + 4 * max_width;
|
||||||
|
while (rgb < last_rgb) {
|
||||||
|
__m128i r, g, b, U0, V0, U1, V1;
|
||||||
|
RGBA32PackedToPlanar_16b_SSE41(rgb + 0, &r, &g, &b);
|
||||||
|
ConvertRGBToUV_SSE41(&r, &g, &b, &U0, &V0);
|
||||||
|
RGBA32PackedToPlanar_16b_SSE41(rgb + 32, &r, &g, &b);
|
||||||
|
ConvertRGBToUV_SSE41(&r, &g, &b, &U1, &V1);
|
||||||
|
STORE_16(_mm_packus_epi16(U0, U1), u);
|
||||||
|
STORE_16(_mm_packus_epi16(V0, V1), v);
|
||||||
|
u += 16;
|
||||||
|
v += 16;
|
||||||
|
rgb += 2 * 32;
|
||||||
|
}
|
||||||
|
if (max_width < width) { // left-over
|
||||||
|
WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern void WebPInitConvertARGBToYUVSSE41(void);
|
||||||
|
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE41(void) {
|
||||||
|
WebPConvertARGBToY = ConvertARGBToY_SSE41;
|
||||||
|
WebPConvertARGBToUV = ConvertARGBToUV_SSE41;
|
||||||
|
|
||||||
|
WebPConvertRGB24ToY = ConvertRGB24ToY_SSE41;
|
||||||
|
WebPConvertBGR24ToY = ConvertBGR24ToY_SSE41;
|
||||||
|
|
||||||
|
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE41;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#else // !WEBP_USE_SSE41
|
||||||
|
|
||||||
|
WEBP_DSP_INIT_STUB(WebPInitSamplersSSE41)
|
||||||
|
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE41)
|
||||||
|
|
||||||
|
#endif // WEBP_USE_SSE41
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
// Author: Jyrki Alakuijala (jyrki@google.com)
|
// Author: Jyrki Alakuijala (jyrki@google.com)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef WEBP_ENC_BACKWARD_REFERENCES_H_
|
#ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||||
#define WEBP_ENC_BACKWARD_REFERENCES_H_
|
#define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -91,11 +91,6 @@ static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) {
|
||||||
return p->len;
|
return p->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) {
|
|
||||||
assert(p->mode == kLiteral);
|
|
||||||
return p->argb_or_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
|
static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
|
||||||
assert(p->mode == kCacheIdx);
|
assert(p->mode == kCacheIdx);
|
||||||
assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
|
assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
|
||||||
|
|
@ -113,6 +108,16 @@ static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
|
||||||
#define HASH_BITS 18
|
#define HASH_BITS 18
|
||||||
#define HASH_SIZE (1 << HASH_BITS)
|
#define HASH_SIZE (1 << HASH_BITS)
|
||||||
|
|
||||||
|
// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it
|
||||||
|
// is used in VP8LHashChain.
|
||||||
|
#define MAX_LENGTH_BITS 12
|
||||||
|
#define WINDOW_SIZE_BITS 20
|
||||||
|
// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits.
|
||||||
|
#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1)
|
||||||
|
#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32
|
||||||
|
#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct VP8LHashChain VP8LHashChain;
|
typedef struct VP8LHashChain VP8LHashChain;
|
||||||
struct VP8LHashChain {
|
struct VP8LHashChain {
|
||||||
// The 20 most significant bits contain the offset at which the best match
|
// The 20 most significant bits contain the offset at which the best match
|
||||||
|
|
@ -134,6 +139,24 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
|
||||||
int low_effort);
|
int low_effort);
|
||||||
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
|
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
|
||||||
|
|
||||||
|
static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
|
||||||
|
const int base_position) {
|
||||||
|
return p->offset_length_[base_position] >> MAX_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p,
|
||||||
|
const int base_position) {
|
||||||
|
return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p,
|
||||||
|
int base_position,
|
||||||
|
int* const offset_ptr,
|
||||||
|
int* const length_ptr) {
|
||||||
|
*offset_ptr = VP8LHashChainFindOffset(p, base_position);
|
||||||
|
*length_ptr = VP8LHashChainFindLength(p, base_position);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// VP8LBackwardRefs (block-based backward-references storage)
|
// VP8LBackwardRefs (block-based backward-references storage)
|
||||||
|
|
||||||
|
|
@ -158,9 +181,6 @@ struct VP8LBackwardRefs {
|
||||||
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size);
|
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size);
|
||||||
// Release memory for backward references.
|
// Release memory for backward references.
|
||||||
void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs);
|
void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs);
|
||||||
// Copies the 'src' backward refs to the 'dst'. Returns 0 in case of error.
|
|
||||||
int VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
|
|
||||||
VP8LBackwardRefs* const dst);
|
|
||||||
|
|
||||||
// Cursor for iterating on references content
|
// Cursor for iterating on references content
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -189,6 +209,12 @@ static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Main entry points
|
// Main entry points
|
||||||
|
|
||||||
|
enum VP8LLZ77Type {
|
||||||
|
kLZ77Standard = 1,
|
||||||
|
kLZ77RLE = 2,
|
||||||
|
kLZ77Box = 4
|
||||||
|
};
|
||||||
|
|
||||||
// Evaluates best possible backward references for specified quality.
|
// Evaluates best possible backward references for specified quality.
|
||||||
// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
|
// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
|
||||||
// bits to use (passing 0 implies disabling the local color cache).
|
// bits to use (passing 0 implies disabling the local color cache).
|
||||||
|
|
@ -197,11 +223,12 @@ static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
|
||||||
// refs[0] or refs[1].
|
// refs[0] or refs[1].
|
||||||
VP8LBackwardRefs* VP8LGetBackwardReferences(
|
VP8LBackwardRefs* VP8LGetBackwardReferences(
|
||||||
int width, int height, const uint32_t* const argb, int quality,
|
int width, int height, const uint32_t* const argb, int quality,
|
||||||
int low_effort, int* const cache_bits,
|
int low_effort, int lz77_types_to_try, int* const cache_bits,
|
||||||
const VP8LHashChain* const hash_chain, VP8LBackwardRefs refs[2]);
|
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
|
||||||
|
VP8LBackwardRefs* const refs_tmp2);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_ENC_BACKWARD_REFERENCES_H_
|
#endif // WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_ENC_COST_H_
|
#ifndef WEBP_ENC_COST_ENC_H_
|
||||||
#define WEBP_ENC_COST_H_
|
#define WEBP_ENC_COST_ENC_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "./vp8i_enc.h"
|
#include "../enc/vp8i_enc.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_ENC_COST_H_ */
|
#endif /* WEBP_ENC_COST_ENC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@
|
||||||
//
|
//
|
||||||
// Models the histograms of literal and distance codes.
|
// Models the histograms of literal and distance codes.
|
||||||
|
|
||||||
#ifndef WEBP_ENC_HISTOGRAM_H_
|
#ifndef WEBP_ENC_HISTOGRAM_ENC_H_
|
||||||
#define WEBP_ENC_HISTOGRAM_H_
|
#define WEBP_ENC_HISTOGRAM_ENC_H_
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "./backward_references_enc.h"
|
#include "../enc/backward_references_enc.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
|
@ -90,7 +90,9 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits);
|
||||||
|
|
||||||
// Accumulate a token 'v' into a histogram.
|
// Accumulate a token 'v' into a histogram.
|
||||||
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
|
||||||
const PixOrCopy* const v);
|
const PixOrCopy* const v,
|
||||||
|
int (*const distance_modifier)(int, int),
|
||||||
|
int distance_modifier_arg0);
|
||||||
|
|
||||||
static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
|
static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
|
||||||
return NUM_LITERAL_CODES + NUM_LENGTH_CODES +
|
return NUM_LITERAL_CODES + NUM_LENGTH_CODES +
|
||||||
|
|
@ -103,14 +105,11 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
||||||
int quality, int low_effort,
|
int quality, int low_effort,
|
||||||
int histogram_bits, int cache_bits,
|
int histogram_bits, int cache_bits,
|
||||||
VP8LHistogramSet* const image_in,
|
VP8LHistogramSet* const image_in,
|
||||||
VP8LHistogramSet* const tmp_histos,
|
VP8LHistogram* const tmp_histo,
|
||||||
uint16_t* const histogram_symbols);
|
uint16_t* const histogram_symbols);
|
||||||
|
|
||||||
// Returns the entropy for the symbols in the input array.
|
// Returns the entropy for the symbols in the input array.
|
||||||
// Also sets trivial_symbol to the code value, if the array has only one code
|
double VP8LBitsEntropy(const uint32_t* const array, int n);
|
||||||
// value. Otherwise, set it to VP8L_NON_TRIVIAL_SYM.
|
|
||||||
double VP8LBitsEntropy(const uint32_t* const array, int n,
|
|
||||||
uint32_t* const trivial_symbol);
|
|
||||||
|
|
||||||
// Estimate how many bits the combined entropy of literals and distance
|
// Estimate how many bits the combined entropy of literals and distance
|
||||||
// approximately maps to.
|
// approximately maps to.
|
||||||
|
|
@ -120,4 +119,4 @@ double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_ENC_HISTOGRAM_H_
|
#endif // WEBP_ENC_HISTOGRAM_ENC_H_
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_ENC_VP8ENCI_H_
|
#ifndef WEBP_ENC_VP8I_ENC_H_
|
||||||
#define WEBP_ENC_VP8ENCI_H_
|
#define WEBP_ENC_VP8I_ENC_H_
|
||||||
|
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include "../dec/common_dec.h"
|
#include "../dec/common_dec.h"
|
||||||
|
|
@ -30,8 +30,8 @@ extern "C" {
|
||||||
// Various defines and enums
|
// Various defines and enums
|
||||||
|
|
||||||
// version numbers
|
// version numbers
|
||||||
#define ENC_MAJ_VERSION 0
|
#define ENC_MAJ_VERSION 1
|
||||||
#define ENC_MIN_VERSION 6
|
#define ENC_MIN_VERSION 0
|
||||||
#define ENC_REV_VERSION 0
|
#define ENC_REV_VERSION 0
|
||||||
|
|
||||||
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
||||||
|
|
@ -75,10 +75,10 @@ typedef enum { // Rate-distortion optimization levels
|
||||||
#define U_OFF_ENC (16)
|
#define U_OFF_ENC (16)
|
||||||
#define V_OFF_ENC (16 + 8)
|
#define V_OFF_ENC (16 + 8)
|
||||||
|
|
||||||
extern const int VP8Scan[16]; // in quant.c
|
extern const uint16_t VP8Scan[16];
|
||||||
extern const int VP8UVModeOffsets[4]; // in analyze.c
|
extern const uint16_t VP8UVModeOffsets[4];
|
||||||
extern const int VP8I16ModeOffsets[4];
|
extern const uint16_t VP8I16ModeOffsets[4];
|
||||||
extern const int VP8I4ModeOffsets[NUM_BMODES];
|
extern const uint16_t VP8I4ModeOffsets[NUM_BMODES];
|
||||||
|
|
||||||
// Layout of prediction blocks
|
// Layout of prediction blocks
|
||||||
// intra 16x16
|
// intra 16x16
|
||||||
|
|
@ -120,6 +120,9 @@ static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) {
|
||||||
// Uncomment the following to remove token-buffer code:
|
// Uncomment the following to remove token-buffer code:
|
||||||
// #define DISABLE_TOKEN_BUFFER
|
// #define DISABLE_TOKEN_BUFFER
|
||||||
|
|
||||||
|
// quality below which error-diffusion is enabled
|
||||||
|
#define ERROR_DIFFUSION_QUALITY 98
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Headers
|
// Headers
|
||||||
|
|
||||||
|
|
@ -201,6 +204,8 @@ typedef struct {
|
||||||
score_t i4_penalty_; // penalty for using Intra4
|
score_t i4_penalty_; // penalty for using Intra4
|
||||||
} VP8SegmentInfo;
|
} VP8SegmentInfo;
|
||||||
|
|
||||||
|
typedef int8_t DError[2 /* u/v */][2 /* top or left */];
|
||||||
|
|
||||||
// Handy transient struct to accumulate score and info during RD-optimization
|
// Handy transient struct to accumulate score and info during RD-optimization
|
||||||
// and mode evaluation.
|
// and mode evaluation.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -213,6 +218,7 @@ typedef struct {
|
||||||
uint8_t modes_i4[16]; // mode numbers for intra4 predictions
|
uint8_t modes_i4[16]; // mode numbers for intra4 predictions
|
||||||
int mode_uv; // mode number of chroma prediction
|
int mode_uv; // mode number of chroma prediction
|
||||||
uint32_t nz; // non-zero blocks
|
uint32_t nz; // non-zero blocks
|
||||||
|
int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3
|
||||||
} VP8ModeScore;
|
} VP8ModeScore;
|
||||||
|
|
||||||
// Iterator structure to iterate through macroblocks, pointing to the
|
// Iterator structure to iterate through macroblocks, pointing to the
|
||||||
|
|
@ -242,6 +248,9 @@ typedef struct {
|
||||||
int count_down0_; // starting counter value (for progress)
|
int count_down0_; // starting counter value (for progress)
|
||||||
int percent0_; // saved initial progress percent
|
int percent0_; // saved initial progress percent
|
||||||
|
|
||||||
|
DError left_derr_; // left error diffusion (u/v)
|
||||||
|
DError *top_derr_; // top diffusion error - NULL if disabled
|
||||||
|
|
||||||
uint8_t* y_left_; // left luma samples (addressable from index -1 to 15).
|
uint8_t* y_left_; // left luma samples (addressable from index -1 to 15).
|
||||||
uint8_t* u_left_; // left u samples (addressable from index -1 to 7)
|
uint8_t* u_left_; // left u samples (addressable from index -1 to 7)
|
||||||
uint8_t* v_left_; // left v samples (addressable from index -1 to 7)
|
uint8_t* v_left_; // left v samples (addressable from index -1 to 7)
|
||||||
|
|
@ -330,9 +339,6 @@ int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
|
||||||
// Estimate the final coded size given a set of 'probas'.
|
// Estimate the final coded size given a set of 'probas'.
|
||||||
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
|
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
|
||||||
|
|
||||||
// unused for now
|
|
||||||
void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats);
|
|
||||||
|
|
||||||
#endif // !DISABLE_TOKEN_BUFFER
|
#endif // !DISABLE_TOKEN_BUFFER
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -404,6 +410,7 @@ struct VP8Encoder {
|
||||||
uint8_t* uv_top_; // top u/v samples.
|
uint8_t* uv_top_; // top u/v samples.
|
||||||
// U and V are packed into 16 bytes (8 U + 8 V)
|
// U and V are packed into 16 bytes (8 U + 8 V)
|
||||||
LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off)
|
LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off)
|
||||||
|
DError* top_derr_; // diffusion error (NULL if disabled)
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -502,19 +509,10 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
|
||||||
// compressibility (no guarantee, though). Assumes that pic->use_argb is true.
|
// compressibility (no guarantee, though). Assumes that pic->use_argb is true.
|
||||||
void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
|
void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
|
||||||
|
|
||||||
// in near_lossless.c
|
|
||||||
// Near lossless preprocessing in RGB color-space.
|
|
||||||
int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality);
|
|
||||||
// Near lossless adjustment for predictors.
|
|
||||||
void VP8ApplyNearLosslessPredict(int xsize, int ysize, int pred_bits,
|
|
||||||
const uint32_t* argb_orig,
|
|
||||||
uint32_t* argb, uint32_t* argb_scratch,
|
|
||||||
const uint32_t* const transform_data,
|
|
||||||
int quality, int subtract_green);
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_ENC_VP8ENCI_H_ */
|
#endif /* WEBP_ENC_VP8I_ENC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,20 @@
|
||||||
//
|
//
|
||||||
// Author: Vikas Arora (vikaas.arora@gmail.com)
|
// Author: Vikas Arora (vikaas.arora@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_ENC_VP8LI_H_
|
#ifndef WEBP_ENC_VP8LI_ENC_H_
|
||||||
#define WEBP_ENC_VP8LI_H_
|
#define WEBP_ENC_VP8LI_ENC_H_
|
||||||
|
|
||||||
#include "./backward_references_enc.h"
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "./histogram_enc.h"
|
#include "../webp/config.h"
|
||||||
|
#endif
|
||||||
|
// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to
|
||||||
|
// disable near-lossless, or it is enabled by default.
|
||||||
|
#ifndef WEBP_NEAR_LOSSLESS
|
||||||
|
#define WEBP_NEAR_LOSSLESS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../enc/backward_references_enc.h"
|
||||||
|
#include "../enc/histogram_enc.h"
|
||||||
#include "../utils/bit_writer_utils.h"
|
#include "../utils/bit_writer_utils.h"
|
||||||
#include "../webp/encode.h"
|
#include "../webp/encode.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
@ -27,16 +36,24 @@ extern "C" {
|
||||||
// maximum value of transform_bits_ in VP8LEncoder.
|
// maximum value of transform_bits_ in VP8LEncoder.
|
||||||
#define MAX_TRANSFORM_BITS 6
|
#define MAX_TRANSFORM_BITS 6
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kEncoderNone = 0,
|
||||||
|
kEncoderARGB,
|
||||||
|
kEncoderNearLossless,
|
||||||
|
kEncoderPalette
|
||||||
|
} VP8LEncoderARGBContent;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const WebPConfig* config_; // user configuration and parameters
|
const WebPConfig* config_; // user configuration and parameters
|
||||||
const WebPPicture* pic_; // input picture.
|
const WebPPicture* pic_; // input picture.
|
||||||
|
|
||||||
uint32_t* argb_; // Transformed argb image data.
|
uint32_t* argb_; // Transformed argb image data.
|
||||||
uint32_t* argb_scratch_; // Scratch memory for argb rows
|
VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer.
|
||||||
// (used for prediction).
|
uint32_t* argb_scratch_; // Scratch memory for argb rows
|
||||||
uint32_t* transform_data_; // Scratch memory for transform data.
|
// (used for prediction).
|
||||||
uint32_t* transform_mem_; // Currently allocated memory.
|
uint32_t* transform_data_; // Scratch memory for transform data.
|
||||||
size_t transform_mem_size_; // Currently allocated memory size.
|
uint32_t* transform_mem_; // Currently allocated memory.
|
||||||
|
size_t transform_mem_size_; // Currently allocated memory size.
|
||||||
|
|
||||||
int current_width_; // Corresponds to packed image width.
|
int current_width_; // Corresponds to packed image width.
|
||||||
|
|
||||||
|
|
@ -54,8 +71,7 @@ typedef struct {
|
||||||
uint32_t palette_[MAX_PALETTE_SIZE];
|
uint32_t palette_[MAX_PALETTE_SIZE];
|
||||||
|
|
||||||
// Some 'scratch' (potentially large) objects.
|
// Some 'scratch' (potentially large) objects.
|
||||||
struct VP8LBackwardRefs refs_[2]; // Backward Refs array corresponding to
|
struct VP8LBackwardRefs refs_[3]; // Backward Refs array for temporaries.
|
||||||
// LZ77 & RLE coding.
|
|
||||||
VP8LHashChain hash_chain_; // HashChain data for constructing
|
VP8LHashChain hash_chain_; // HashChain data for constructing
|
||||||
// backward references.
|
// backward references.
|
||||||
} VP8LEncoder;
|
} VP8LEncoder;
|
||||||
|
|
@ -75,6 +91,13 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
||||||
const WebPPicture* const picture,
|
const WebPPicture* const picture,
|
||||||
VP8LBitWriter* const bw, int use_cache);
|
VP8LBitWriter* const bw, int use_cache);
|
||||||
|
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
// in near_lossless.c
|
||||||
|
// Near lossless preprocessing in RGB color-space.
|
||||||
|
int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
||||||
|
uint32_t* const argb_dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Image transforms in predictor.c.
|
// Image transforms in predictor.c.
|
||||||
|
|
||||||
|
|
@ -92,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_ENC_VP8LI_H_ */
|
#endif /* WEBP_ENC_VP8LI_ENC_H_ */
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_BIT_READER_INL_H_
|
#ifndef WEBP_UTILS_BIT_READER_INL_UTILS_H_
|
||||||
#define WEBP_UTILS_BIT_READER_INL_H_
|
#define WEBP_UTILS_BIT_READER_INL_UTILS_H_
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "../webp/config.h"
|
#include "../webp/config.h"
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
#include <string.h> // for memcpy
|
#include <string.h> // for memcpy
|
||||||
|
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "./bit_reader_utils.h"
|
#include "../utils/bit_reader_utils.h"
|
||||||
#include "./endian_inl_utils.h"
|
#include "../utils/endian_inl_utils.h"
|
||||||
#include "./utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -187,4 +187,4 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_UTILS_BIT_READER_INL_H_
|
#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include "../webp/config.h"
|
#include "../webp/config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./bit_reader_inl_utils.h"
|
#include "../utils/bit_reader_inl_utils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
// Vikas Arora (vikaas.arora@gmail.com)
|
// Vikas Arora (vikaas.arora@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_BIT_READER_H_
|
#ifndef WEBP_UTILS_BIT_READER_UTILS_H_
|
||||||
#define WEBP_UTILS_BIT_READER_H_
|
#define WEBP_UTILS_BIT_READER_UTILS_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
@ -155,9 +155,10 @@ static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) {
|
||||||
|
|
||||||
// For jumping over a number of bits in the bit stream when accessed with
|
// For jumping over a number of bits in the bit stream when accessed with
|
||||||
// VP8LPrefetchBits and VP8LFillBitWindow.
|
// VP8LPrefetchBits and VP8LFillBitWindow.
|
||||||
|
// This function does *not* set br->eos_, since it's speed-critical.
|
||||||
|
// Use with extreme care!
|
||||||
static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) {
|
static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) {
|
||||||
br->bit_pos_ = val;
|
br->bit_pos_ = val;
|
||||||
br->eos_ = VP8LIsEndOfStream(br);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advances the read buffer by 4 bytes to make room for reading next 32 bits.
|
// Advances the read buffer by 4 bytes to make room for reading next 32 bits.
|
||||||
|
|
@ -171,4 +172,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_BIT_READER_H_ */
|
#endif /* WEBP_UTILS_BIT_READER_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_BIT_WRITER_H_
|
#ifndef WEBP_UTILS_BIT_WRITER_UTILS_H_
|
||||||
#define WEBP_UTILS_BIT_WRITER_H_
|
#define WEBP_UTILS_BIT_WRITER_UTILS_H_
|
||||||
|
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
|
@ -100,16 +100,24 @@ typedef struct {
|
||||||
int error_;
|
int error_;
|
||||||
} VP8LBitWriter;
|
} VP8LBitWriter;
|
||||||
|
|
||||||
static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
|
static WEBP_INLINE size_t VP8LBitWriterNumBytes(const VP8LBitWriter* const bw) {
|
||||||
return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3);
|
return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns false in case of memory allocation error.
|
// Returns false in case of memory allocation error.
|
||||||
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
|
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
|
||||||
|
// Returns false in case of memory allocation error.
|
||||||
|
int VP8LBitWriterClone(const VP8LBitWriter* const src,
|
||||||
|
VP8LBitWriter* const dst);
|
||||||
// Finalize the bitstream coding. Returns a pointer to the internal buffer.
|
// Finalize the bitstream coding. Returns a pointer to the internal buffer.
|
||||||
uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw);
|
uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw);
|
||||||
// Release any pending memory and zeroes the object.
|
// Release any pending memory and zeroes the object.
|
||||||
void VP8LBitWriterWipeOut(VP8LBitWriter* const bw);
|
void VP8LBitWriterWipeOut(VP8LBitWriter* const bw);
|
||||||
|
// Resets the cursor of the BitWriter bw to when it was like in bw_init.
|
||||||
|
void VP8LBitWriterReset(const VP8LBitWriter* const bw_init,
|
||||||
|
VP8LBitWriter* const bw);
|
||||||
|
// Swaps the memory held by two BitWriters.
|
||||||
|
void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst);
|
||||||
|
|
||||||
// Internal function for VP8LPutBits flushing 32 bits from the written state.
|
// Internal function for VP8LPutBits flushing 32 bits from the written state.
|
||||||
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
|
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
|
||||||
|
|
@ -143,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_BIT_WRITER_H_ */
|
#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./color_cache_utils.h"
|
#include "../utils/color_cache_utils.h"
|
||||||
#include "./utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// VP8LColorCache.
|
// VP8LColorCache.
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@
|
||||||
// Authors: Jyrki Alakuijala (jyrki@google.com)
|
// Authors: Jyrki Alakuijala (jyrki@google.com)
|
||||||
// Urvang Joshi (urvang@google.com)
|
// Urvang Joshi (urvang@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_COLOR_CACHE_H_
|
#ifndef WEBP_UTILS_COLOR_CACHE_UTILS_H_
|
||||||
#define WEBP_UTILS_COLOR_CACHE_H_
|
#define WEBP_UTILS_COLOR_CACHE_UTILS_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
|
@ -30,7 +32,7 @@ typedef struct {
|
||||||
|
|
||||||
static const uint64_t kHashMul = 0x1e35a7bdull;
|
static const uint64_t kHashMul = 0x1e35a7bdull;
|
||||||
|
|
||||||
static WEBP_INLINE int HashPix(uint32_t argb, int shift) {
|
static WEBP_INLINE int VP8LHashPix(uint32_t argb, int shift) {
|
||||||
return (int)(((argb * kHashMul) & 0xffffffffu) >> shift);
|
return (int)(((argb * kHashMul) & 0xffffffffu) >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,19 +50,19 @@ static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc,
|
||||||
|
|
||||||
static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
|
static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
|
||||||
uint32_t argb) {
|
uint32_t argb) {
|
||||||
const int key = HashPix(argb, cc->hash_shift_);
|
const int key = VP8LHashPix(argb, cc->hash_shift_);
|
||||||
cc->colors_[key] = argb;
|
cc->colors_[key] = argb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
|
static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
|
||||||
uint32_t argb) {
|
uint32_t argb) {
|
||||||
return HashPix(argb, cc->hash_shift_);
|
return VP8LHashPix(argb, cc->hash_shift_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the key if cc contains argb, and -1 otherwise.
|
// Return the key if cc contains argb, and -1 otherwise.
|
||||||
static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
|
static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
|
||||||
uint32_t argb) {
|
uint32_t argb) {
|
||||||
const int key = HashPix(argb, cc->hash_shift_);
|
const int key = VP8LHashPix(argb, cc->hash_shift_);
|
||||||
return (cc->colors_[key] == argb) ? key : -1;
|
return (cc->colors_[key] == argb) ? key : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,4 +84,4 @@ void VP8LColorCacheClear(VP8LColorCache* const color_cache);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_UTILS_COLOR_CACHE_H_
|
#endif // WEBP_UTILS_COLOR_CACHE_UTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@
|
||||||
//
|
//
|
||||||
// Endian related functions.
|
// Endian related functions.
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_ENDIAN_INL_H_
|
#ifndef WEBP_UTILS_ENDIAN_INL_UTILS_H_
|
||||||
#define WEBP_UTILS_ENDIAN_INL_H_
|
#define WEBP_UTILS_ENDIAN_INL_UTILS_H_
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "../webp/config.h"
|
#include "../webp/config.h"
|
||||||
|
|
@ -19,13 +19,6 @@
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
|
|
||||||
#if !defined(WORDS_BIGENDIAN) && \
|
|
||||||
(defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
|
|
||||||
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
|
|
||||||
#define WORDS_BIGENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WORDS_BIGENDIAN)
|
#if defined(WORDS_BIGENDIAN)
|
||||||
#define HToLE32 BSwap32
|
#define HToLE32 BSwap32
|
||||||
#define HToLE16 BSwap16
|
#define HToLE16 BSwap16
|
||||||
|
|
@ -97,4 +90,4 @@ static WEBP_INLINE uint64_t BSwap64(uint64_t x) {
|
||||||
#endif // HAVE_BUILTIN_BSWAP64
|
#endif // HAVE_BUILTIN_BSWAP64
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WEBP_UTILS_ENDIAN_INL_H_
|
#endif // WEBP_UTILS_ENDIAN_INL_UTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//
|
//
|
||||||
// Author: Urvang (urvang@google.com)
|
// Author: Urvang (urvang@google.com)
|
||||||
|
|
||||||
#include "./filters_utils.h"
|
#include "../utils/filters_utils.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Urvang (urvang@google.com)
|
// Author: Urvang (urvang@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_FILTERS_H_
|
#ifndef WEBP_UTILS_FILTERS_UTILS_H_
|
||||||
#define WEBP_UTILS_FILTERS_H_
|
#define WEBP_UTILS_FILTERS_UTILS_H_
|
||||||
|
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
|
|
@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_FILTERS_H_ */
|
#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Entropy encoding (Huffman) for webp lossless
|
// Entropy encoding (Huffman) for webp lossless
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_HUFFMAN_ENCODE_H_
|
#ifndef WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
|
||||||
#define WEBP_UTILS_HUFFMAN_ENCODE_H_
|
#define WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
|
||||||
|
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
|
@ -57,4 +57,4 @@ void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_UTILS_HUFFMAN_ENCODE_H_
|
#endif // WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./huffman_utils.h"
|
#include "../utils/huffman_utils.h"
|
||||||
#include "./utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
||||||
// Huffman data read via DecodeImageStream is represented in two (red and green)
|
// Huffman data read via DecodeImageStream is represented in two (red and green)
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Urvang Joshi (urvang@google.com)
|
// Author: Urvang Joshi (urvang@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_HUFFMAN_H_
|
#ifndef WEBP_UTILS_HUFFMAN_UTILS_H_
|
||||||
#define WEBP_UTILS_HUFFMAN_H_
|
#define WEBP_UTILS_HUFFMAN_UTILS_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "../webp/format_constants.h"
|
#include "../webp/format_constants.h"
|
||||||
|
|
@ -85,4 +85,4 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // WEBP_UTILS_HUFFMAN_H_
|
#endif // WEBP_UTILS_HUFFMAN_UTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include "./quant_levels_dec_utils.h"
|
#include "../utils/quant_levels_dec_utils.h"
|
||||||
|
|
||||||
#include <string.h> // for memset
|
#include <string.h> // for memset
|
||||||
|
|
||||||
#include "./utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
// #define USE_DITHERING // uncomment to enable ordered dithering (not vital)
|
// #define USE_DITHERING // uncomment to enable ordered dithering (not vital)
|
||||||
|
|
||||||
|
|
@ -71,10 +71,11 @@ typedef struct {
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define CLIP_MASK (int)(~0U << (8 + DFIX))
|
#define CLIP_8b_MASK (int)(~0U << (8 + DFIX))
|
||||||
static WEBP_INLINE uint8_t clip_8b(int v) {
|
static WEBP_INLINE uint8_t clip_8b(int v) {
|
||||||
return (!(v & CLIP_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u;
|
return (!(v & CLIP_8b_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u;
|
||||||
}
|
}
|
||||||
|
#undef CLIP_8b_MASK
|
||||||
|
|
||||||
// vertical accumulation
|
// vertical accumulation
|
||||||
static void VFilter(SmoothParams* const p) {
|
static void VFilter(SmoothParams* const p) {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Vikas Arora (vikasa@google.com)
|
// Author: Vikas Arora (vikasa@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_H_
|
#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
|
||||||
#define WEBP_UTILS_QUANT_LEVELS_DEC_H_
|
#define WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
|
||||||
|
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
|
|
@ -32,4 +32,4 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_H_ */
|
#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "./quant_levels_utils.h"
|
#include "../utils/quant_levels_utils.h"
|
||||||
|
|
||||||
#define NUM_SYMBOLS 256
|
#define NUM_SYMBOLS 256
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Vikas Arora (vikasa@google.com)
|
// Author: Vikas Arora (vikasa@google.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_QUANT_LEVELS_H_
|
#ifndef WEBP_UTILS_QUANT_LEVELS_UTILS_H_
|
||||||
#define WEBP_UTILS_QUANT_LEVELS_H_
|
#define WEBP_UTILS_QUANT_LEVELS_UTILS_H_
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
@ -33,4 +33,4 @@ int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_QUANT_LEVELS_H_ */
|
#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "./random_utils.h"
|
#include "../utils/random_utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_RANDOM_H_
|
#ifndef WEBP_UTILS_RANDOM_UTILS_H_
|
||||||
#define WEBP_UTILS_RANDOM_H_
|
#define WEBP_UTILS_RANDOM_UTILS_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_RANDOM_H_ */
|
#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../dsp/dsp.h"
|
#include "../dsp/dsp.h"
|
||||||
#include "./rescaler_utils.h"
|
#include "../utils/rescaler_utils.h"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -85,11 +85,13 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||||
|
|
||||||
// if width is unspecified, scale original proportionally to height ratio.
|
// if width is unspecified, scale original proportionally to height ratio.
|
||||||
if (width == 0) {
|
if (width == 0) {
|
||||||
width = (src_width * height + src_height / 2) / src_height;
|
width =
|
||||||
|
(int)(((uint64_t)src_width * height + src_height / 2) / src_height);
|
||||||
}
|
}
|
||||||
// if height is unspecified, scale original proportionally to width ratio.
|
// if height is unspecified, scale original proportionally to width ratio.
|
||||||
if (height == 0) {
|
if (height == 0) {
|
||||||
height = (src_height * width + src_width / 2) / src_width;
|
height =
|
||||||
|
(int)(((uint64_t)src_height * width + src_width / 2) / src_width);
|
||||||
}
|
}
|
||||||
// Check if the overall dimensions still make sense.
|
// Check if the overall dimensions still make sense.
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_RESCALER_H_
|
#ifndef WEBP_UTILS_RESCALER_UTILS_H_
|
||||||
#define WEBP_UTILS_RESCALER_H_
|
#define WEBP_UTILS_RESCALER_UTILS_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_RESCALER_H_ */
|
#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h> // for memset()
|
#include <string.h> // for memset()
|
||||||
#include "./thread_utils.h"
|
#include "../utils/thread_utils.h"
|
||||||
#include "./utils.h"
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
#ifdef WEBP_USE_THREAD
|
#ifdef WEBP_USE_THREAD
|
||||||
|
|
||||||
|
|
@ -50,11 +50,11 @@ typedef struct {
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
struct WebPWorkerImpl {
|
typedef struct {
|
||||||
pthread_mutex_t mutex_;
|
pthread_mutex_t mutex_;
|
||||||
pthread_cond_t condition_;
|
pthread_cond_t condition_;
|
||||||
pthread_t thread_;
|
pthread_t thread_;
|
||||||
};
|
} WebPWorkerImpl;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
|
@ -201,25 +201,24 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void Execute(WebPWorker* const worker); // Forward declaration.
|
|
||||||
|
|
||||||
static THREADFN ThreadLoop(void* ptr) {
|
static THREADFN ThreadLoop(void* ptr) {
|
||||||
WebPWorker* const worker = (WebPWorker*)ptr;
|
WebPWorker* const worker = (WebPWorker*)ptr;
|
||||||
|
WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
pthread_mutex_lock(&worker->impl_->mutex_);
|
pthread_mutex_lock(&impl->mutex_);
|
||||||
while (worker->status_ == OK) { // wait in idling mode
|
while (worker->status_ == OK) { // wait in idling mode
|
||||||
pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
|
pthread_cond_wait(&impl->condition_, &impl->mutex_);
|
||||||
}
|
}
|
||||||
if (worker->status_ == WORK) {
|
if (worker->status_ == WORK) {
|
||||||
Execute(worker);
|
WebPGetWorkerInterface()->Execute(worker);
|
||||||
worker->status_ = OK;
|
worker->status_ = OK;
|
||||||
} else if (worker->status_ == NOT_OK) { // finish the worker
|
} else if (worker->status_ == NOT_OK) { // finish the worker
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
// signal to the main thread that we're done (for Sync())
|
// signal to the main thread that we're done (for Sync())
|
||||||
pthread_cond_signal(&worker->impl_->condition_);
|
pthread_cond_signal(&impl->condition_);
|
||||||
pthread_mutex_unlock(&worker->impl_->mutex_);
|
pthread_mutex_unlock(&impl->mutex_);
|
||||||
}
|
}
|
||||||
return THREAD_RETURN(NULL); // Thread is finished
|
return THREAD_RETURN(NULL); // Thread is finished
|
||||||
}
|
}
|
||||||
|
|
@ -229,21 +228,22 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
|
||||||
// No-op when attempting to change state on a thread that didn't come up.
|
// No-op when attempting to change state on a thread that didn't come up.
|
||||||
// Checking status_ without acquiring the lock first would result in a data
|
// Checking status_ without acquiring the lock first would result in a data
|
||||||
// race.
|
// race.
|
||||||
if (worker->impl_ == NULL) return;
|
WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
|
||||||
|
if (impl == NULL) return;
|
||||||
|
|
||||||
pthread_mutex_lock(&worker->impl_->mutex_);
|
pthread_mutex_lock(&impl->mutex_);
|
||||||
if (worker->status_ >= OK) {
|
if (worker->status_ >= OK) {
|
||||||
// wait for the worker to finish
|
// wait for the worker to finish
|
||||||
while (worker->status_ != OK) {
|
while (worker->status_ != OK) {
|
||||||
pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
|
pthread_cond_wait(&impl->condition_, &impl->mutex_);
|
||||||
}
|
}
|
||||||
// assign new status and release the working thread if needed
|
// assign new status and release the working thread if needed
|
||||||
if (new_status != OK) {
|
if (new_status != OK) {
|
||||||
worker->status_ = new_status;
|
worker->status_ = new_status;
|
||||||
pthread_cond_signal(&worker->impl_->condition_);
|
pthread_cond_signal(&impl->condition_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&worker->impl_->mutex_);
|
pthread_mutex_unlock(&impl->mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WEBP_USE_THREAD
|
#endif // WEBP_USE_THREAD
|
||||||
|
|
@ -268,26 +268,28 @@ static int Reset(WebPWorker* const worker) {
|
||||||
worker->had_error = 0;
|
worker->had_error = 0;
|
||||||
if (worker->status_ < OK) {
|
if (worker->status_ < OK) {
|
||||||
#ifdef WEBP_USE_THREAD
|
#ifdef WEBP_USE_THREAD
|
||||||
worker->impl_ = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(*worker->impl_));
|
WebPWorkerImpl* const impl =
|
||||||
|
(WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(WebPWorkerImpl));
|
||||||
|
worker->impl_ = (void*)impl;
|
||||||
if (worker->impl_ == NULL) {
|
if (worker->impl_ == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
|
if (pthread_mutex_init(&impl->mutex_, NULL)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
|
if (pthread_cond_init(&impl->condition_, NULL)) {
|
||||||
pthread_mutex_destroy(&worker->impl_->mutex_);
|
pthread_mutex_destroy(&impl->mutex_);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&worker->impl_->mutex_);
|
pthread_mutex_lock(&impl->mutex_);
|
||||||
ok = !pthread_create(&worker->impl_->thread_, NULL, ThreadLoop, worker);
|
ok = !pthread_create(&impl->thread_, NULL, ThreadLoop, worker);
|
||||||
if (ok) worker->status_ = OK;
|
if (ok) worker->status_ = OK;
|
||||||
pthread_mutex_unlock(&worker->impl_->mutex_);
|
pthread_mutex_unlock(&impl->mutex_);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
pthread_mutex_destroy(&worker->impl_->mutex_);
|
pthread_mutex_destroy(&impl->mutex_);
|
||||||
pthread_cond_destroy(&worker->impl_->condition_);
|
pthread_cond_destroy(&impl->condition_);
|
||||||
Error:
|
Error:
|
||||||
WebPSafeFree(worker->impl_);
|
WebPSafeFree(impl);
|
||||||
worker->impl_ = NULL;
|
worker->impl_ = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -318,11 +320,12 @@ static void Launch(WebPWorker* const worker) {
|
||||||
static void End(WebPWorker* const worker) {
|
static void End(WebPWorker* const worker) {
|
||||||
#ifdef WEBP_USE_THREAD
|
#ifdef WEBP_USE_THREAD
|
||||||
if (worker->impl_ != NULL) {
|
if (worker->impl_ != NULL) {
|
||||||
|
WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
|
||||||
ChangeState(worker, NOT_OK);
|
ChangeState(worker, NOT_OK);
|
||||||
pthread_join(worker->impl_->thread_, NULL);
|
pthread_join(impl->thread_, NULL);
|
||||||
pthread_mutex_destroy(&worker->impl_->mutex_);
|
pthread_mutex_destroy(&impl->mutex_);
|
||||||
pthread_cond_destroy(&worker->impl_->condition_);
|
pthread_cond_destroy(&impl->condition_);
|
||||||
WebPSafeFree(worker->impl_);
|
WebPSafeFree(impl);
|
||||||
worker->impl_ = NULL;
|
worker->impl_ = NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
//
|
//
|
||||||
// Author: Skal (pascal.massimino@gmail.com)
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
#ifndef WEBP_UTILS_THREAD_H_
|
#ifndef WEBP_UTILS_THREAD_UTILS_H_
|
||||||
#define WEBP_UTILS_THREAD_H_
|
#define WEBP_UTILS_THREAD_UTILS_H_
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "../webp/config.h"
|
#include "../webp/config.h"
|
||||||
|
|
@ -35,12 +35,9 @@ typedef enum {
|
||||||
// arguments (data1 and data2), and should return false in case of error.
|
// arguments (data1 and data2), and should return false in case of error.
|
||||||
typedef int (*WebPWorkerHook)(void*, void*);
|
typedef int (*WebPWorkerHook)(void*, void*);
|
||||||
|
|
||||||
// Platform-dependent implementation details for the worker.
|
|
||||||
typedef struct WebPWorkerImpl WebPWorkerImpl;
|
|
||||||
|
|
||||||
// Synchronization object used to launch job in the worker thread
|
// Synchronization object used to launch job in the worker thread
|
||||||
typedef struct {
|
typedef struct {
|
||||||
WebPWorkerImpl* impl_;
|
void* impl_; // platform-dependent implementation worker details
|
||||||
WebPWorkerStatus status_;
|
WebPWorkerStatus status_;
|
||||||
WebPWorkerHook hook; // hook to call
|
WebPWorkerHook hook; // hook to call
|
||||||
void* data1; // first argument passed to 'hook'
|
void* data1; // first argument passed to 'hook'
|
||||||
|
|
@ -78,11 +75,11 @@ typedef struct {
|
||||||
// decoding takes place. The contents of the interface struct are copied, it
|
// decoding takes place. The contents of the interface struct are copied, it
|
||||||
// is safe to free the corresponding memory after this call. This function is
|
// is safe to free the corresponding memory after this call. This function is
|
||||||
// not thread-safe. Return false in case of invalid pointer or methods.
|
// not thread-safe. Return false in case of invalid pointer or methods.
|
||||||
WEBP_EXTERN(int) WebPSetWorkerInterface(
|
WEBP_EXTERN int WebPSetWorkerInterface(
|
||||||
const WebPWorkerInterface* const winterface);
|
const WebPWorkerInterface* const winterface);
|
||||||
|
|
||||||
// Retrieve the currently set thread worker interface.
|
// Retrieve the currently set thread worker interface.
|
||||||
WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
|
WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -90,4 +87,4 @@ WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* WEBP_UTILS_THREAD_H_ */
|
#endif /* WEBP_UTILS_THREAD_UTILS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
#include "../webp/decode.h"
|
#include "../webp/decode.h"
|
||||||
#include "../webp/encode.h"
|
#include "../webp/encode.h"
|
||||||
#include "../webp/format_constants.h" // for MAX_PALETTE_SIZE
|
#include "../webp/format_constants.h" // for MAX_PALETTE_SIZE
|
||||||
#include "./utils.h"
|
#include "../utils/color_cache_utils.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
|
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
|
||||||
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
|
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
|
||||||
|
|
@ -252,7 +253,6 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
|
||||||
int num_colors = 0;
|
int num_colors = 0;
|
||||||
uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
|
uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
|
||||||
uint32_t colors[COLOR_HASH_SIZE];
|
uint32_t colors[COLOR_HASH_SIZE];
|
||||||
static const uint64_t kHashMul = 0x1e35a7bdull;
|
|
||||||
const uint32_t* argb = pic->argb;
|
const uint32_t* argb = pic->argb;
|
||||||
const int width = pic->width;
|
const int width = pic->width;
|
||||||
const int height = pic->height;
|
const int height = pic->height;
|
||||||
|
|
@ -267,7 +267,7 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
last_pix = argb[x];
|
last_pix = argb[x];
|
||||||
key = ((last_pix * kHashMul) & 0xffffffffu) >> COLOR_HASH_RIGHT_SHIFT;
|
key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!in_use[key]) {
|
if (!in_use[key]) {
|
||||||
colors[key] = last_pix;
|
colors[key] = last_pix;
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,13 @@ extern "C" {
|
||||||
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
|
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
|
||||||
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
|
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
|
||||||
// underlying multiply involved.
|
// underlying multiply involved.
|
||||||
WEBP_EXTERN(void*) WebPSafeMalloc(uint64_t nmemb, size_t size);
|
WEBP_EXTERN void* WebPSafeMalloc(uint64_t nmemb, size_t size);
|
||||||
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
|
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
|
||||||
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
|
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
|
||||||
WEBP_EXTERN(void*) WebPSafeCalloc(uint64_t nmemb, size_t size);
|
WEBP_EXTERN void* WebPSafeCalloc(uint64_t nmemb, size_t size);
|
||||||
|
|
||||||
// Companion deallocation function to the above allocations.
|
// Companion deallocation function to the above allocations.
|
||||||
WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
|
WEBP_EXTERN void WebPSafeFree(void* const ptr);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Alignment
|
// Alignment
|
||||||
|
|
@ -66,7 +66,7 @@ WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
|
||||||
// memcpy() is the safe way of moving potentially unaligned 32b memory.
|
// memcpy() is the safe way of moving potentially unaligned 32b memory.
|
||||||
static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
|
static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
|
||||||
uint32_t A;
|
uint32_t A;
|
||||||
memcpy(&A, (const int*)ptr, sizeof(A));
|
memcpy(&A, ptr, sizeof(A));
|
||||||
return A;
|
return A;
|
||||||
}
|
}
|
||||||
static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
|
static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
|
||||||
|
|
@ -112,12 +112,12 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
|
||||||
#define WEBP_NEED_LOG_TABLE_8BIT
|
#define WEBP_NEED_LOG_TABLE_8BIT
|
||||||
extern const uint8_t WebPLogTable8bit[256];
|
extern const uint8_t WebPLogTable8bit[256];
|
||||||
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
|
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
|
||||||
int log = 0;
|
int log_value = 0;
|
||||||
while (n >= 256) {
|
while (n >= 256) {
|
||||||
log += 8;
|
log_value += 8;
|
||||||
n >>= 8;
|
n >>= 8;
|
||||||
}
|
}
|
||||||
return log + WebPLogTable8bit[n];
|
return log_value + WebPLogTable8bit[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns (int)floor(log2(n)). n must be > 0.
|
// Returns (int)floor(log2(n)). n must be > 0.
|
||||||
|
|
@ -147,14 +147,14 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
|
||||||
struct WebPPicture;
|
struct WebPPicture;
|
||||||
|
|
||||||
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
|
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
|
||||||
WEBP_EXTERN(void) WebPCopyPlane(const uint8_t* src, int src_stride,
|
WEBP_EXTERN void WebPCopyPlane(const uint8_t* src, int src_stride,
|
||||||
uint8_t* dst, int dst_stride,
|
uint8_t* dst, int dst_stride,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
|
|
||||||
// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are
|
// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are
|
||||||
// assumed to be already allocated and using ARGB data.
|
// assumed to be already allocated and using ARGB data.
|
||||||
WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
|
WEBP_EXTERN void WebPCopyPixels(const struct WebPPicture* const src,
|
||||||
struct WebPPicture* const dst);
|
struct WebPPicture* const dst);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Unique colors.
|
// Unique colors.
|
||||||
|
|
@ -166,8 +166,8 @@ WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
|
||||||
// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'.
|
// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'.
|
||||||
// Note: 'palette' is assumed to be an array already allocated with at least
|
// Note: 'palette' is assumed to be an array already allocated with at least
|
||||||
// MAX_PALETTE_SIZE elements.
|
// MAX_PALETTE_SIZE elements.
|
||||||
WEBP_EXTERN(int) WebPGetColorPalette(const struct WebPPicture* const pic,
|
WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
|
||||||
uint32_t* const palette);
|
uint32_t* const palette);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,39 +36,39 @@ typedef struct WebPDecoderConfig WebPDecoderConfig;
|
||||||
|
|
||||||
// Return the decoder's version number, packed in hexadecimal using 8bits for
|
// Return the decoder's version number, packed in hexadecimal using 8bits for
|
||||||
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
WEBP_EXTERN(int) WebPGetDecoderVersion(void);
|
WEBP_EXTERN int WebPGetDecoderVersion(void);
|
||||||
|
|
||||||
// Retrieve basic header information: width, height.
|
// Retrieve basic header information: width, height.
|
||||||
// This function will also validate the header, returning true on success,
|
// This function will also validate the header, returning true on success,
|
||||||
// false otherwise. '*width' and '*height' are only valid on successful return.
|
// false otherwise. '*width' and '*height' are only valid on successful return.
|
||||||
// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
|
// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
|
||||||
WEBP_EXTERN(int) WebPGetInfo(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
|
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
|
||||||
// with the dimensions in *width and *height. The ordering of samples in
|
// with the dimensions in *width and *height. The ordering of samples in
|
||||||
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
|
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
|
||||||
// The returned pointer should be deleted calling WebPFree().
|
// The returned pointer should be deleted calling WebPFree().
|
||||||
// Returns NULL in case of error.
|
// Returns NULL in case of error.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeRGBA(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
|
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeARGB(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
|
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeBGRA(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
|
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
|
||||||
// If the bitstream contains transparency, it is ignored.
|
// If the bitstream contains transparency, it is ignored.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeRGB(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
|
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
|
|
||||||
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
|
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
|
||||||
|
|
@ -80,13 +80,13 @@ WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
|
||||||
// have a common stride returned as '*uv_stride'.
|
// have a common stride returned as '*uv_stride'.
|
||||||
// Return NULL in case of error.
|
// Return NULL in case of error.
|
||||||
// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
|
// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeYUV(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
|
||||||
int* width, int* height,
|
int* width, int* height,
|
||||||
uint8_t** u, uint8_t** v,
|
uint8_t** u, uint8_t** v,
|
||||||
int* stride, int* uv_stride);
|
int* stride, int* uv_stride);
|
||||||
|
|
||||||
// Releases memory returned by the WebPDecode*() functions above.
|
// Releases memory returned by the WebPDecode*() functions above.
|
||||||
WEBP_EXTERN(void) WebPFree(void* ptr);
|
WEBP_EXTERN void WebPFree(void* ptr);
|
||||||
|
|
||||||
// These five functions are variants of the above ones, that decode the image
|
// These five functions are variants of the above ones, that decode the image
|
||||||
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
|
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
|
||||||
|
|
@ -96,22 +96,22 @@ WEBP_EXTERN(void) WebPFree(void* ptr);
|
||||||
// The parameter 'output_stride' specifies the distance (in bytes)
|
// The parameter 'output_stride' specifies the distance (in bytes)
|
||||||
// between scanlines. Hence, output_buffer_size is expected to be at least
|
// between scanlines. Hence, output_buffer_size is expected to be at least
|
||||||
// output_stride x picture-height.
|
// output_stride x picture-height.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeRGBAInto(
|
WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeARGBInto(
|
WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeBGRAInto(
|
WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
|
|
||||||
// RGB and BGR variants. Here too the transparency information, if present,
|
// RGB and BGR variants. Here too the transparency information, if present,
|
||||||
// will be dropped and ignored.
|
// will be dropped and ignored.
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeRGBInto(
|
WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto(
|
WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto(
|
||||||
// 'u_size' and 'v_size' respectively.
|
// 'u_size' and 'v_size' respectively.
|
||||||
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
|
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
|
||||||
// during decoding (or because some buffers were found to be too small).
|
// during decoding (or because some buffers were found to be too small).
|
||||||
WEBP_EXTERN(uint8_t*) WebPDecodeYUVInto(
|
WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
|
||||||
const uint8_t* data, size_t data_size,
|
const uint8_t* data, size_t data_size,
|
||||||
uint8_t* luma, size_t luma_size, int luma_stride,
|
uint8_t* luma, size_t luma_size, int luma_stride,
|
||||||
uint8_t* u, size_t u_size, int u_stride,
|
uint8_t* u, size_t u_size, int u_stride,
|
||||||
|
|
@ -213,7 +213,7 @@ struct WebPDecBuffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(int) WebPInitDecBufferInternal(WebPDecBuffer*, int);
|
WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
|
||||||
|
|
||||||
// Initialize the structure as empty. Must be called before any other use.
|
// Initialize the structure as empty. Must be called before any other use.
|
||||||
// Returns false in case of version mismatch
|
// Returns false in case of version mismatch
|
||||||
|
|
@ -223,7 +223,7 @@ static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
|
||||||
|
|
||||||
// Free any memory associated with the buffer. Must always be called last.
|
// Free any memory associated with the buffer. Must always be called last.
|
||||||
// Note: doesn't free the 'buffer' structure itself.
|
// Note: doesn't free the 'buffer' structure itself.
|
||||||
WEBP_EXTERN(void) WebPFreeDecBuffer(WebPDecBuffer* buffer);
|
WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Enumeration of the status codes
|
// Enumeration of the status codes
|
||||||
|
|
@ -277,7 +277,7 @@ typedef enum VP8StatusCode {
|
||||||
// within valid bounds.
|
// within valid bounds.
|
||||||
// All other fields of WebPDecBuffer MUST remain constant between calls.
|
// All other fields of WebPDecBuffer MUST remain constant between calls.
|
||||||
// Returns NULL if the allocation failed.
|
// Returns NULL if the allocation failed.
|
||||||
WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
|
WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
|
||||||
|
|
||||||
// This function allocates and initializes an incremental-decoder object, which
|
// This function allocates and initializes an incremental-decoder object, which
|
||||||
// will output the RGB/A samples specified by 'csp' into a preallocated
|
// will output the RGB/A samples specified by 'csp' into a preallocated
|
||||||
|
|
@ -289,7 +289,7 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
|
||||||
// colorspace 'csp' is taken into account for allocating this buffer. All other
|
// colorspace 'csp' is taken into account for allocating this buffer. All other
|
||||||
// parameters are ignored.
|
// parameters are ignored.
|
||||||
// Returns NULL if the allocation failed, or if some parameters are invalid.
|
// Returns NULL if the allocation failed, or if some parameters are invalid.
|
||||||
WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
|
WEBP_EXTERN WebPIDecoder* WebPINewRGB(
|
||||||
WEBP_CSP_MODE csp,
|
WEBP_CSP_MODE csp,
|
||||||
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
|
||||||
|
|
||||||
|
|
@ -304,7 +304,7 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
|
||||||
// In this case, the output buffer will be automatically allocated (using
|
// In this case, the output buffer will be automatically allocated (using
|
||||||
// MODE_YUVA) when decoding starts. All parameters are then ignored.
|
// MODE_YUVA) when decoding starts. All parameters are then ignored.
|
||||||
// Returns NULL if the allocation failed or if a parameter is invalid.
|
// Returns NULL if the allocation failed or if a parameter is invalid.
|
||||||
WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
|
WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
|
||||||
uint8_t* luma, size_t luma_size, int luma_stride,
|
uint8_t* luma, size_t luma_size, int luma_stride,
|
||||||
uint8_t* u, size_t u_size, int u_stride,
|
uint8_t* u, size_t u_size, int u_stride,
|
||||||
uint8_t* v, size_t v_size, int v_stride,
|
uint8_t* v, size_t v_size, int v_stride,
|
||||||
|
|
@ -312,19 +312,19 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
|
||||||
|
|
||||||
// Deprecated version of the above, without the alpha plane.
|
// Deprecated version of the above, without the alpha plane.
|
||||||
// Kept for backward compatibility.
|
// Kept for backward compatibility.
|
||||||
WEBP_EXTERN(WebPIDecoder*) WebPINewYUV(
|
WEBP_EXTERN WebPIDecoder* WebPINewYUV(
|
||||||
uint8_t* luma, size_t luma_size, int luma_stride,
|
uint8_t* luma, size_t luma_size, int luma_stride,
|
||||||
uint8_t* u, size_t u_size, int u_stride,
|
uint8_t* u, size_t u_size, int u_stride,
|
||||||
uint8_t* v, size_t v_size, int v_stride);
|
uint8_t* v, size_t v_size, int v_stride);
|
||||||
|
|
||||||
// Deletes the WebPIDecoder object and associated memory. Must always be called
|
// Deletes the WebPIDecoder object and associated memory. Must always be called
|
||||||
// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
|
// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
|
||||||
WEBP_EXTERN(void) WebPIDelete(WebPIDecoder* idec);
|
WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec);
|
||||||
|
|
||||||
// Copies and decodes the next available data. Returns VP8_STATUS_OK when
|
// Copies and decodes the next available data. Returns VP8_STATUS_OK when
|
||||||
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
|
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
|
||||||
// data is expected. Returns error in other cases.
|
// data is expected. Returns error in other cases.
|
||||||
WEBP_EXTERN(VP8StatusCode) WebPIAppend(
|
WEBP_EXTERN VP8StatusCode WebPIAppend(
|
||||||
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
|
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
|
||||||
|
|
||||||
// A variant of the above function to be used when data buffer contains
|
// A variant of the above function to be used when data buffer contains
|
||||||
|
|
@ -332,7 +332,7 @@ WEBP_EXTERN(VP8StatusCode) WebPIAppend(
|
||||||
// to the internal memory.
|
// to the internal memory.
|
||||||
// Note that the value of the 'data' pointer can change between calls to
|
// Note that the value of the 'data' pointer can change between calls to
|
||||||
// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
|
// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
|
||||||
WEBP_EXTERN(VP8StatusCode) WebPIUpdate(
|
WEBP_EXTERN VP8StatusCode WebPIUpdate(
|
||||||
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
|
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
|
||||||
|
|
||||||
// Returns the RGB/A image decoded so far. Returns NULL if output params
|
// Returns the RGB/A image decoded so far. Returns NULL if output params
|
||||||
|
|
@ -340,15 +340,16 @@ WEBP_EXTERN(VP8StatusCode) WebPIUpdate(
|
||||||
// specified during call to WebPINewDecoder() or WebPINewRGB().
|
// specified during call to WebPINewDecoder() or WebPINewRGB().
|
||||||
// *last_y is the index of last decoded row in raster scan order. Some pointers
|
// *last_y is the index of last decoded row in raster scan order. Some pointers
|
||||||
// (*last_y, *width etc.) can be NULL if corresponding information is not
|
// (*last_y, *width etc.) can be NULL if corresponding information is not
|
||||||
// needed.
|
// needed. The values in these pointers are only valid on successful (non-NULL)
|
||||||
WEBP_EXTERN(uint8_t*) WebPIDecGetRGB(
|
// return.
|
||||||
|
WEBP_EXTERN uint8_t* WebPIDecGetRGB(
|
||||||
const WebPIDecoder* idec, int* last_y,
|
const WebPIDecoder* idec, int* last_y,
|
||||||
int* width, int* height, int* stride);
|
int* width, int* height, int* stride);
|
||||||
|
|
||||||
// Same as above function to get a YUVA image. Returns pointer to the luma
|
// Same as above function to get a YUVA image. Returns pointer to the luma
|
||||||
// plane or NULL in case of error. If there is no alpha information
|
// plane or NULL in case of error. If there is no alpha information
|
||||||
// the alpha pointer '*a' will be returned NULL.
|
// the alpha pointer '*a' will be returned NULL.
|
||||||
WEBP_EXTERN(uint8_t*) WebPIDecGetYUVA(
|
WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
|
||||||
const WebPIDecoder* idec, int* last_y,
|
const WebPIDecoder* idec, int* last_y,
|
||||||
uint8_t** u, uint8_t** v, uint8_t** a,
|
uint8_t** u, uint8_t** v, uint8_t** a,
|
||||||
int* width, int* height, int* stride, int* uv_stride, int* a_stride);
|
int* width, int* height, int* stride, int* uv_stride, int* a_stride);
|
||||||
|
|
@ -368,7 +369,7 @@ static WEBP_INLINE uint8_t* WebPIDecGetYUV(
|
||||||
// Returns NULL in case the incremental decoder object is in an invalid state.
|
// Returns NULL in case the incremental decoder object is in an invalid state.
|
||||||
// Otherwise returns the pointer to the internal representation. This structure
|
// Otherwise returns the pointer to the internal representation. This structure
|
||||||
// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
|
// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
|
||||||
WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
|
WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
|
||||||
const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
|
const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -416,7 +417,7 @@ struct WebPBitstreamFeatures {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal(
|
WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(
|
||||||
const uint8_t*, size_t, WebPBitstreamFeatures*, int);
|
const uint8_t*, size_t, WebPBitstreamFeatures*, int);
|
||||||
|
|
||||||
// Retrieve features from the bitstream. The *features structure is filled
|
// Retrieve features from the bitstream. The *features structure is filled
|
||||||
|
|
@ -457,7 +458,7 @@ struct WebPDecoderConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(int) WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
|
WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
|
||||||
|
|
||||||
// Initialize the configuration as empty. This function must always be
|
// Initialize the configuration as empty. This function must always be
|
||||||
// called first, unless WebPGetFeatures() is to be called.
|
// called first, unless WebPGetFeatures() is to be called.
|
||||||
|
|
@ -477,14 +478,14 @@ static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
|
||||||
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
|
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
|
||||||
// Returns NULL in case of error (and config->status will then reflect
|
// Returns NULL in case of error (and config->status will then reflect
|
||||||
// the error condition, if available).
|
// the error condition, if available).
|
||||||
WEBP_EXTERN(WebPIDecoder*) WebPIDecode(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
|
||||||
WebPDecoderConfig* config);
|
WebPDecoderConfig* config);
|
||||||
|
|
||||||
// Non-incremental version. This version decodes the full data at once, taking
|
// Non-incremental version. This version decodes the full data at once, taking
|
||||||
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
|
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
|
||||||
// if the decoding was successful). Note that 'config' cannot be NULL.
|
// if the decoding was successful). Note that 'config' cannot be NULL.
|
||||||
WEBP_EXTERN(VP8StatusCode) WebPDecode(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
||||||
WebPDecoderConfig* config);
|
WebPDecoderConfig* config);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions;
|
||||||
|
|
||||||
// Returns the version number of the demux library, packed in hexadecimal using
|
// Returns the version number of the demux library, packed in hexadecimal using
|
||||||
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
WEBP_EXTERN(int) WebPGetDemuxVersion(void);
|
WEBP_EXTERN int WebPGetDemuxVersion(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Life of a Demux object
|
// Life of a Demux object
|
||||||
|
|
@ -85,7 +85,7 @@ typedef enum WebPDemuxState {
|
||||||
} WebPDemuxState;
|
} WebPDemuxState;
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
|
WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
|
||||||
const WebPData*, int, WebPDemuxState*, int);
|
const WebPData*, int, WebPDemuxState*, int);
|
||||||
|
|
||||||
// Parses the full WebP file given by 'data'. For single images the WebP file
|
// Parses the full WebP file given by 'data'. For single images the WebP file
|
||||||
|
|
@ -109,27 +109,32 @@ static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frees memory associated with 'dmux'.
|
// Frees memory associated with 'dmux'.
|
||||||
WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux);
|
WEBP_EXTERN void WebPDemuxDelete(WebPDemuxer* dmux);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Data/information extraction.
|
// Data/information extraction.
|
||||||
|
|
||||||
typedef enum WebPFormatFeature {
|
typedef enum WebPFormatFeature {
|
||||||
WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk.
|
WEBP_FF_FORMAT_FLAGS, // bit-wise combination of WebPFeatureFlags
|
||||||
|
// corresponding to the 'VP8X' chunk (if present).
|
||||||
WEBP_FF_CANVAS_WIDTH,
|
WEBP_FF_CANVAS_WIDTH,
|
||||||
WEBP_FF_CANVAS_HEIGHT,
|
WEBP_FF_CANVAS_HEIGHT,
|
||||||
WEBP_FF_LOOP_COUNT,
|
WEBP_FF_LOOP_COUNT, // only relevant for animated file
|
||||||
WEBP_FF_BACKGROUND_COLOR,
|
WEBP_FF_BACKGROUND_COLOR, // idem.
|
||||||
WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
|
WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
|
||||||
// In case of a partial demux, this is the number of
|
// In case of a partial demux, this is the number
|
||||||
// frames seen so far, with the last frame possibly
|
// of frames seen so far, with the last frame
|
||||||
// being partial.
|
// possibly being partial.
|
||||||
} WebPFormatFeature;
|
} WebPFormatFeature;
|
||||||
|
|
||||||
// Get the 'feature' value from the 'dmux'.
|
// Get the 'feature' value from the 'dmux'.
|
||||||
// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
|
// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
|
||||||
// returned a state > WEBP_DEMUX_PARSING_HEADER.
|
// returned a state > WEBP_DEMUX_PARSING_HEADER.
|
||||||
WEBP_EXTERN(uint32_t) WebPDemuxGetI(
|
// If 'feature' is WEBP_FF_FORMAT_FLAGS, the returned value is a bit-wise
|
||||||
|
// combination of WebPFeatureFlags values.
|
||||||
|
// If 'feature' is WEBP_FF_LOOP_COUNT, WEBP_FF_BACKGROUND_COLOR, the returned
|
||||||
|
// value is only meaningful if the bitstream is animated.
|
||||||
|
WEBP_EXTERN uint32_t WebPDemuxGetI(
|
||||||
const WebPDemuxer* dmux, WebPFormatFeature feature);
|
const WebPDemuxer* dmux, WebPFormatFeature feature);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -159,20 +164,20 @@ struct WebPIterator {
|
||||||
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
|
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
|
||||||
// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
|
// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
|
||||||
// NOTE: 'dmux' must persist for the lifetime of 'iter'.
|
// NOTE: 'dmux' must persist for the lifetime of 'iter'.
|
||||||
WEBP_EXTERN(int) WebPDemuxGetFrame(
|
WEBP_EXTERN int WebPDemuxGetFrame(
|
||||||
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
|
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
|
||||||
|
|
||||||
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
|
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
|
||||||
// previous ('iter->frame_num' - 1) frame. These functions do not loop.
|
// previous ('iter->frame_num' - 1) frame. These functions do not loop.
|
||||||
// Returns true on success, false otherwise.
|
// Returns true on success, false otherwise.
|
||||||
WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
|
WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
|
||||||
WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
|
WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
|
||||||
|
|
||||||
// Releases any memory associated with 'iter'.
|
// Releases any memory associated with 'iter'.
|
||||||
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
|
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
|
||||||
// iter. Also, must be called before destroying the associated WebPDemuxer with
|
// iter. Also, must be called before destroying the associated WebPDemuxer with
|
||||||
// WebPDemuxDelete().
|
// WebPDemuxDelete().
|
||||||
WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter);
|
WEBP_EXTERN void WebPDemuxReleaseIterator(WebPIterator* iter);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Chunk iteration.
|
// Chunk iteration.
|
||||||
|
|
@ -197,20 +202,20 @@ struct WebPChunkIterator {
|
||||||
// payloads are accessed through WebPDemuxGetFrame() and related functions.
|
// payloads are accessed through WebPDemuxGetFrame() and related functions.
|
||||||
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
|
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
|
||||||
// NOTE: 'dmux' must persist for the lifetime of the iterator.
|
// NOTE: 'dmux' must persist for the lifetime of the iterator.
|
||||||
WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
|
WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
|
||||||
const char fourcc[4], int chunk_number,
|
const char fourcc[4], int chunk_number,
|
||||||
WebPChunkIterator* iter);
|
WebPChunkIterator* iter);
|
||||||
|
|
||||||
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
|
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
|
||||||
// ('iter->chunk_num' - 1) chunk. These functions do not loop.
|
// ('iter->chunk_num' - 1) chunk. These functions do not loop.
|
||||||
// Returns true on success, false otherwise.
|
// Returns true on success, false otherwise.
|
||||||
WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
|
WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
|
||||||
WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);
|
WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
|
||||||
|
|
||||||
// Releases any memory associated with 'iter'.
|
// Releases any memory associated with 'iter'.
|
||||||
// Must be called before destroying the associated WebPDemuxer with
|
// Must be called before destroying the associated WebPDemuxer with
|
||||||
// WebPDemuxDelete().
|
// WebPDemuxDelete().
|
||||||
WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
|
WEBP_EXTERN void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// WebPAnimDecoder API
|
// WebPAnimDecoder API
|
||||||
|
|
@ -252,7 +257,7 @@ struct WebPAnimDecoderOptions {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point.
|
// Internal, version-checked, entry point.
|
||||||
WEBP_EXTERN(int) WebPAnimDecoderOptionsInitInternal(
|
WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
|
||||||
WebPAnimDecoderOptions*, int);
|
WebPAnimDecoderOptions*, int);
|
||||||
|
|
||||||
// Should always be called, to initialize a fresh WebPAnimDecoderOptions
|
// Should always be called, to initialize a fresh WebPAnimDecoderOptions
|
||||||
|
|
@ -266,7 +271,7 @@ static WEBP_INLINE int WebPAnimDecoderOptionsInit(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal, version-checked, entry point.
|
// Internal, version-checked, entry point.
|
||||||
WEBP_EXTERN(WebPAnimDecoder*) WebPAnimDecoderNewInternal(
|
WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
|
||||||
const WebPData*, const WebPAnimDecoderOptions*, int);
|
const WebPData*, const WebPAnimDecoderOptions*, int);
|
||||||
|
|
||||||
// Creates and initializes a WebPAnimDecoder object.
|
// Creates and initializes a WebPAnimDecoder object.
|
||||||
|
|
@ -301,8 +306,8 @@ struct WebPAnimInfo {
|
||||||
// info - (out) global information fetched from the animation.
|
// info - (out) global information fetched from the animation.
|
||||||
// Returns:
|
// Returns:
|
||||||
// True on success.
|
// True on success.
|
||||||
WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
|
WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
|
||||||
WebPAnimInfo* info);
|
WebPAnimInfo* info);
|
||||||
|
|
||||||
// Fetch the next frame from 'dec' based on options supplied to
|
// Fetch the next frame from 'dec' based on options supplied to
|
||||||
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
|
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
|
||||||
|
|
@ -316,8 +321,8 @@ WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
|
||||||
// Returns:
|
// Returns:
|
||||||
// False if any of the arguments are NULL, or if there is a parsing or
|
// False if any of the arguments are NULL, or if there is a parsing or
|
||||||
// decoding error, or if there are no more frames. Otherwise, returns true.
|
// decoding error, or if there are no more frames. Otherwise, returns true.
|
||||||
WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
||||||
uint8_t** buf, int* timestamp);
|
uint8_t** buf, int* timestamp);
|
||||||
|
|
||||||
// Check if there are more frames left to decode.
|
// Check if there are more frames left to decode.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
|
|
@ -325,7 +330,7 @@ WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
|
||||||
// Returns:
|
// Returns:
|
||||||
// True if 'dec' is not NULL and some frames are yet to be decoded.
|
// True if 'dec' is not NULL and some frames are yet to be decoded.
|
||||||
// Otherwise, returns false.
|
// Otherwise, returns false.
|
||||||
WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
|
WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
|
||||||
|
|
||||||
// Resets the WebPAnimDecoder object, so that next call to
|
// Resets the WebPAnimDecoder object, so that next call to
|
||||||
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
|
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
|
||||||
|
|
@ -333,7 +338,7 @@ WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
|
||||||
// info.loop_count times) without destroying and recreating the 'dec' object.
|
// info.loop_count times) without destroying and recreating the 'dec' object.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// dec - (in/out) decoder instance to be reset
|
// dec - (in/out) decoder instance to be reset
|
||||||
WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec);
|
WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
|
||||||
|
|
||||||
// Grab the internal demuxer object.
|
// Grab the internal demuxer object.
|
||||||
// Getting the demuxer object can be useful if one wants to use operations only
|
// Getting the demuxer object can be useful if one wants to use operations only
|
||||||
|
|
@ -343,13 +348,13 @@ WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec);
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// dec - (in) decoder instance from which the demuxer object is to be fetched.
|
// dec - (in) decoder instance from which the demuxer object is to be fetched.
|
||||||
WEBP_EXTERN(const WebPDemuxer*) WebPAnimDecoderGetDemuxer(
|
WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
|
||||||
const WebPAnimDecoder* dec);
|
const WebPAnimDecoder* dec);
|
||||||
|
|
||||||
// Deletes the WebPAnimDecoder object.
|
// Deletes the WebPAnimDecoder object.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// dec - (in/out) decoder instance to be deleted
|
// dec - (in/out) decoder instance to be deleted
|
||||||
WEBP_EXTERN(void) WebPAnimDecoderDelete(WebPAnimDecoder* dec);
|
WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ typedef struct WebPMemoryWriter WebPMemoryWriter;
|
||||||
|
|
||||||
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
||||||
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
WEBP_EXTERN(int) WebPGetEncoderVersion(void);
|
WEBP_EXTERN int WebPGetEncoderVersion(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// One-stop-shop call! No questions asked:
|
// One-stop-shop call! No questions asked:
|
||||||
|
|
@ -46,37 +46,37 @@ WEBP_EXTERN(int) WebPGetEncoderVersion(void);
|
||||||
// These functions compress using the lossy format, and the quality_factor
|
// These functions compress using the lossy format, and the quality_factor
|
||||||
// can go from 0 (smaller output, lower quality) to 100 (best quality,
|
// can go from 0 (smaller output, lower quality) to 100 (best quality,
|
||||||
// larger output).
|
// larger output).
|
||||||
WEBP_EXTERN(size_t) WebPEncodeRGB(const uint8_t* rgb,
|
WEBP_EXTERN size_t WebPEncodeRGB(const uint8_t* rgb,
|
||||||
|
int width, int height, int stride,
|
||||||
|
float quality_factor, uint8_t** output);
|
||||||
|
WEBP_EXTERN size_t WebPEncodeBGR(const uint8_t* bgr,
|
||||||
|
int width, int height, int stride,
|
||||||
|
float quality_factor, uint8_t** output);
|
||||||
|
WEBP_EXTERN size_t WebPEncodeRGBA(const uint8_t* rgba,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
float quality_factor, uint8_t** output);
|
float quality_factor, uint8_t** output);
|
||||||
WEBP_EXTERN(size_t) WebPEncodeBGR(const uint8_t* bgr,
|
WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
float quality_factor, uint8_t** output);
|
float quality_factor, uint8_t** output);
|
||||||
WEBP_EXTERN(size_t) WebPEncodeRGBA(const uint8_t* rgba,
|
|
||||||
int width, int height, int stride,
|
|
||||||
float quality_factor, uint8_t** output);
|
|
||||||
WEBP_EXTERN(size_t) WebPEncodeBGRA(const uint8_t* bgra,
|
|
||||||
int width, int height, int stride,
|
|
||||||
float quality_factor, uint8_t** output);
|
|
||||||
|
|
||||||
// These functions are the equivalent of the above, but compressing in a
|
// These functions are the equivalent of the above, but compressing in a
|
||||||
// lossless manner. Files are usually larger than lossy format, but will
|
// lossless manner. Files are usually larger than lossy format, but will
|
||||||
// not suffer any compression loss.
|
// not suffer any compression loss.
|
||||||
WEBP_EXTERN(size_t) WebPEncodeLosslessRGB(const uint8_t* rgb,
|
WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb,
|
||||||
|
int width, int height, int stride,
|
||||||
|
uint8_t** output);
|
||||||
|
WEBP_EXTERN size_t WebPEncodeLosslessBGR(const uint8_t* bgr,
|
||||||
|
int width, int height, int stride,
|
||||||
|
uint8_t** output);
|
||||||
|
WEBP_EXTERN size_t WebPEncodeLosslessRGBA(const uint8_t* rgba,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
uint8_t** output);
|
uint8_t** output);
|
||||||
WEBP_EXTERN(size_t) WebPEncodeLosslessBGR(const uint8_t* bgr,
|
WEBP_EXTERN size_t WebPEncodeLosslessBGRA(const uint8_t* bgra,
|
||||||
int width, int height, int stride,
|
int width, int height, int stride,
|
||||||
uint8_t** output);
|
uint8_t** output);
|
||||||
WEBP_EXTERN(size_t) WebPEncodeLosslessRGBA(const uint8_t* rgba,
|
|
||||||
int width, int height, int stride,
|
|
||||||
uint8_t** output);
|
|
||||||
WEBP_EXTERN(size_t) WebPEncodeLosslessBGRA(const uint8_t* bgra,
|
|
||||||
int width, int height, int stride,
|
|
||||||
uint8_t** output);
|
|
||||||
|
|
||||||
// Releases memory returned by the WebPEncode*() functions above.
|
// Releases memory returned by the WebPEncode*() functions above.
|
||||||
WEBP_EXTERN(void) WebPFree(void* ptr);
|
WEBP_EXTERN void WebPFree(void* ptr);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Coding parameters
|
// Coding parameters
|
||||||
|
|
@ -93,12 +93,15 @@ typedef enum WebPImageHint {
|
||||||
// Compression parameters.
|
// Compression parameters.
|
||||||
struct WebPConfig {
|
struct WebPConfig {
|
||||||
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
|
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
|
||||||
float quality; // between 0 (smallest file) and 100 (biggest)
|
float quality; // between 0 and 100. For lossy, 0 gives the smallest
|
||||||
|
// size and 100 the largest. For lossless, this
|
||||||
|
// parameter is the amount of effort put into the
|
||||||
|
// compression: 0 is the fastest but gives larger
|
||||||
|
// files compared to the slowest, but best, 100.
|
||||||
int method; // quality/speed trade-off (0=fast, 6=slower-better)
|
int method; // quality/speed trade-off (0=fast, 6=slower-better)
|
||||||
|
|
||||||
WebPImageHint image_hint; // Hint for image type (lossless only for now).
|
WebPImageHint image_hint; // Hint for image type (lossless only for now).
|
||||||
|
|
||||||
// Parameters related to lossy compression only:
|
|
||||||
int target_size; // if non-zero, set the desired target size in bytes.
|
int target_size; // if non-zero, set the desired target size in bytes.
|
||||||
// Takes precedence over the 'compression' parameter.
|
// Takes precedence over the 'compression' parameter.
|
||||||
float target_PSNR; // if non-zero, specifies the minimal distortion to
|
float target_PSNR; // if non-zero, specifies the minimal distortion to
|
||||||
|
|
@ -159,7 +162,7 @@ typedef enum WebPPreset {
|
||||||
} WebPPreset;
|
} WebPPreset;
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(int) WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
|
WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
|
||||||
|
|
||||||
// Should always be called, to initialize a fresh WebPConfig structure before
|
// Should always be called, to initialize a fresh WebPConfig structure before
|
||||||
// modification. Returns false in case of version mismatch. WebPConfigInit()
|
// modification. Returns false in case of version mismatch. WebPConfigInit()
|
||||||
|
|
@ -186,15 +189,15 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
|
||||||
// speed and final compressed size.
|
// speed and final compressed size.
|
||||||
// This function will overwrite several fields from config: 'method', 'quality'
|
// This function will overwrite several fields from config: 'method', 'quality'
|
||||||
// and 'lossless'. Returns false in case of parameter error.
|
// and 'lossless'. Returns false in case of parameter error.
|
||||||
WEBP_EXTERN(int) WebPConfigLosslessPreset(WebPConfig* config, int level);
|
WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level);
|
||||||
|
|
||||||
// Returns true if 'config' is non-NULL and all configuration parameters are
|
// Returns true if 'config' is non-NULL and all configuration parameters are
|
||||||
// within their valid ranges.
|
// within their valid ranges.
|
||||||
WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* config);
|
WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Input / Output
|
// Input / Output
|
||||||
// Structure for storing auxiliary statistics (mostly for lossy encoding).
|
// Structure for storing auxiliary statistics.
|
||||||
|
|
||||||
struct WebPAuxStats {
|
struct WebPAuxStats {
|
||||||
int coded_size; // final size
|
int coded_size; // final size
|
||||||
|
|
@ -242,16 +245,16 @@ struct WebPMemoryWriter {
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following must be called first before any use.
|
// The following must be called first before any use.
|
||||||
WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer);
|
WEBP_EXTERN void WebPMemoryWriterInit(WebPMemoryWriter* writer);
|
||||||
|
|
||||||
// The following must be called to deallocate writer->mem memory. The 'writer'
|
// The following must be called to deallocate writer->mem memory. The 'writer'
|
||||||
// object itself is not deallocated.
|
// object itself is not deallocated.
|
||||||
WEBP_EXTERN(void) WebPMemoryWriterClear(WebPMemoryWriter* writer);
|
WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
|
||||||
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
|
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
|
||||||
// completion, writer.mem and writer.size will hold the coded data.
|
// completion, writer.mem and writer.size will hold the coded data.
|
||||||
// writer.mem must be freed by calling WebPMemoryWriterClear.
|
// writer.mem must be freed by calling WebPMemoryWriterClear.
|
||||||
WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
|
WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size,
|
||||||
const WebPPicture* picture);
|
const WebPPicture* picture);
|
||||||
|
|
||||||
// Progress hook, called from time to time to report progress. It can return
|
// Progress hook, called from time to time to report progress. It can return
|
||||||
// false to request an abort of the encoding process, or true otherwise if
|
// false to request an abort of the encoding process, or true otherwise if
|
||||||
|
|
@ -354,7 +357,7 @@ struct WebPPicture {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(int) WebPPictureInitInternal(WebPPicture*, int);
|
WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
|
||||||
|
|
||||||
// Should always be called, to initialize the structure. Returns false in case
|
// Should always be called, to initialize the structure. Returns false in case
|
||||||
// of version mismatch. WebPPictureInit() must have succeeded before using the
|
// of version mismatch. WebPPictureInit() must have succeeded before using the
|
||||||
|
|
@ -371,20 +374,20 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
|
||||||
// Allocate y/u/v buffers as per colorspace/width/height specification.
|
// Allocate y/u/v buffers as per colorspace/width/height specification.
|
||||||
// Note! This function will free the previous buffer if needed.
|
// Note! This function will free the previous buffer if needed.
|
||||||
// Returns false in case of memory error.
|
// Returns false in case of memory error.
|
||||||
WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
|
||||||
|
|
||||||
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
|
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
|
||||||
// Note that this function does _not_ free the memory used by the 'picture'
|
// Note that this function does _not_ free the memory used by the 'picture'
|
||||||
// object itself.
|
// object itself.
|
||||||
// Besides memory (which is reclaimed) all other fields of 'picture' are
|
// Besides memory (which is reclaimed) all other fields of 'picture' are
|
||||||
// preserved.
|
// preserved.
|
||||||
WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture);
|
WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
|
||||||
|
|
||||||
// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst
|
// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst
|
||||||
// will fully own the copied pixels (this is not a view). The 'dst' picture need
|
// will fully own the copied pixels (this is not a view). The 'dst' picture need
|
||||||
// not be initialized as its content is overwritten.
|
// not be initialized as its content is overwritten.
|
||||||
// Returns false in case of memory allocation error.
|
// Returns false in case of memory allocation error.
|
||||||
WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
|
WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
|
||||||
|
|
||||||
// Compute the single distortion for packed planes of samples.
|
// Compute the single distortion for packed planes of samples.
|
||||||
// 'src' will be compared to 'ref', and the raw distortion stored into
|
// 'src' will be compared to 'ref', and the raw distortion stored into
|
||||||
|
|
@ -393,19 +396,19 @@ WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
|
||||||
// 'x_step' is the horizontal stride (in bytes) between samples.
|
// 'x_step' is the horizontal stride (in bytes) between samples.
|
||||||
// 'src/ref_stride' is the byte distance between rows.
|
// 'src/ref_stride' is the byte distance between rows.
|
||||||
// Returns false in case of error (bad parameter, memory allocation error, ...).
|
// Returns false in case of error (bad parameter, memory allocation error, ...).
|
||||||
WEBP_EXTERN(int) WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
|
WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
|
||||||
const uint8_t* ref, size_t ref_stride,
|
const uint8_t* ref, size_t ref_stride,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
size_t x_step,
|
size_t x_step,
|
||||||
int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
|
int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
|
||||||
float* distortion, float* result);
|
float* distortion, float* result);
|
||||||
|
|
||||||
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
|
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
|
||||||
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
|
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
|
||||||
// always performed using ARGB samples. Hence if the input is YUV(A), the
|
// always performed using ARGB samples. Hence if the input is YUV(A), the
|
||||||
// picture will be internally converted to ARGB (just for the measurement).
|
// picture will be internally converted to ARGB (just for the measurement).
|
||||||
// Warning: this function is rather CPU-intensive.
|
// Warning: this function is rather CPU-intensive.
|
||||||
WEBP_EXTERN(int) WebPPictureDistortion(
|
WEBP_EXTERN int WebPPictureDistortion(
|
||||||
const WebPPicture* src, const WebPPicture* ref,
|
const WebPPicture* src, const WebPPicture* ref,
|
||||||
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
|
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
|
||||||
float result[5]);
|
float result[5]);
|
||||||
|
|
@ -418,8 +421,8 @@ WEBP_EXTERN(int) WebPPictureDistortion(
|
||||||
// must be fully be comprised inside the 'src' source picture. If the source
|
// must be fully be comprised inside the 'src' source picture. If the source
|
||||||
// picture uses the YUV420 colorspace, the top and left coordinates will be
|
// picture uses the YUV420 colorspace, the top and left coordinates will be
|
||||||
// snapped to even values.
|
// snapped to even values.
|
||||||
WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
|
WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
|
||||||
int left, int top, int width, int height);
|
int left, int top, int width, int height);
|
||||||
|
|
||||||
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
|
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
|
||||||
// is defined by the top-left corner pixel coordinates (left, top) as well
|
// is defined by the top-left corner pixel coordinates (left, top) as well
|
||||||
|
|
@ -432,42 +435,42 @@ WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
|
||||||
// with WebPPictureInit() if it is different from 'src', since its content will
|
// with WebPPictureInit() if it is different from 'src', since its content will
|
||||||
// be overwritten.
|
// be overwritten.
|
||||||
// Returns false in case of memory allocation error or invalid parameters.
|
// Returns false in case of memory allocation error or invalid parameters.
|
||||||
WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src,
|
WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
|
||||||
int left, int top, int width, int height,
|
int left, int top, int width, int height,
|
||||||
WebPPicture* dst);
|
WebPPicture* dst);
|
||||||
|
|
||||||
// Returns true if the 'picture' is actually a view and therefore does
|
// Returns true if the 'picture' is actually a view and therefore does
|
||||||
// not own the memory for pixels.
|
// not own the memory for pixels.
|
||||||
WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
|
||||||
|
|
||||||
// Rescale a picture to new dimension width x height.
|
// Rescale a picture to new dimension width x height.
|
||||||
// If either 'width' or 'height' (but not both) is 0 the corresponding
|
// If either 'width' or 'height' (but not both) is 0 the corresponding
|
||||||
// dimension will be calculated preserving the aspect ratio.
|
// dimension will be calculated preserving the aspect ratio.
|
||||||
// No gamma correction is applied.
|
// No gamma correction is applied.
|
||||||
// Returns false in case of error (invalid parameter or insufficient memory).
|
// Returns false in case of error (invalid parameter or insufficient memory).
|
||||||
WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* pic, int width, int height);
|
WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
|
||||||
|
|
||||||
// Colorspace conversion function to import RGB samples.
|
// Colorspace conversion function to import RGB samples.
|
||||||
// Previous buffer will be free'd, if any.
|
// Previous buffer will be free'd, if any.
|
||||||
// *rgb buffer should have a size of at least height * rgb_stride.
|
// *rgb buffer should have a size of at least height * rgb_stride.
|
||||||
// Returns false in case of memory error.
|
// Returns false in case of memory error.
|
||||||
WEBP_EXTERN(int) WebPPictureImportRGB(
|
WEBP_EXTERN int WebPPictureImportRGB(
|
||||||
WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
|
WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
|
||||||
// Same, but for RGBA buffer.
|
// Same, but for RGBA buffer.
|
||||||
WEBP_EXTERN(int) WebPPictureImportRGBA(
|
WEBP_EXTERN int WebPPictureImportRGBA(
|
||||||
WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
|
WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
|
||||||
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
|
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
|
||||||
// input buffer ignoring the alpha channel. Avoids needing to copy the data
|
// input buffer ignoring the alpha channel. Avoids needing to copy the data
|
||||||
// to a temporary 24-bit RGB buffer to import the RGB only.
|
// to a temporary 24-bit RGB buffer to import the RGB only.
|
||||||
WEBP_EXTERN(int) WebPPictureImportRGBX(
|
WEBP_EXTERN int WebPPictureImportRGBX(
|
||||||
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
|
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
|
||||||
|
|
||||||
// Variants of the above, but taking BGR(A|X) input.
|
// Variants of the above, but taking BGR(A|X) input.
|
||||||
WEBP_EXTERN(int) WebPPictureImportBGR(
|
WEBP_EXTERN int WebPPictureImportBGR(
|
||||||
WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
|
WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
|
||||||
WEBP_EXTERN(int) WebPPictureImportBGRA(
|
WEBP_EXTERN int WebPPictureImportBGRA(
|
||||||
WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
|
WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
|
||||||
WEBP_EXTERN(int) WebPPictureImportBGRX(
|
WEBP_EXTERN int WebPPictureImportBGRX(
|
||||||
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
|
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
|
||||||
|
|
||||||
// Converts picture->argb data to the YUV420A format. The 'colorspace'
|
// Converts picture->argb data to the YUV420A format. The 'colorspace'
|
||||||
|
|
@ -476,14 +479,14 @@ WEBP_EXTERN(int) WebPPictureImportBGRX(
|
||||||
// non-opaque transparent values is detected, and 'colorspace' will be
|
// non-opaque transparent values is detected, and 'colorspace' will be
|
||||||
// adjusted accordingly. Note that this method is lossy.
|
// adjusted accordingly. Note that this method is lossy.
|
||||||
// Returns false in case of error.
|
// Returns false in case of error.
|
||||||
WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture,
|
WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture,
|
||||||
WebPEncCSP /*colorspace = WEBP_YUV420*/);
|
WebPEncCSP /*colorspace = WEBP_YUV420*/);
|
||||||
|
|
||||||
// Same as WebPPictureARGBToYUVA(), but the conversion is done using
|
// Same as WebPPictureARGBToYUVA(), but the conversion is done using
|
||||||
// pseudo-random dithering with a strength 'dithering' between
|
// pseudo-random dithering with a strength 'dithering' between
|
||||||
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
|
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
|
||||||
// for photographic picture.
|
// for photographic picture.
|
||||||
WEBP_EXTERN(int) WebPPictureARGBToYUVADithered(
|
WEBP_EXTERN int WebPPictureARGBToYUVADithered(
|
||||||
WebPPicture* picture, WebPEncCSP colorspace, float dithering);
|
WebPPicture* picture, WebPEncCSP colorspace, float dithering);
|
||||||
|
|
||||||
// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
|
// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
|
||||||
|
|
@ -491,9 +494,9 @@ WEBP_EXTERN(int) WebPPictureARGBToYUVADithered(
|
||||||
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
|
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
|
||||||
// and sharper YUV representation.
|
// and sharper YUV representation.
|
||||||
// Returns false in case of error.
|
// Returns false in case of error.
|
||||||
WEBP_EXTERN(int) WebPPictureSharpARGBToYUVA(WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
|
||||||
// kept for backward compatibility:
|
// kept for backward compatibility:
|
||||||
WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
|
||||||
|
|
||||||
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
|
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
|
||||||
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
|
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
|
||||||
|
|
@ -501,22 +504,22 @@ WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture);
|
||||||
// Note that the use of this colorspace is discouraged if one has access to the
|
// Note that the use of this colorspace is discouraged if one has access to the
|
||||||
// raw ARGB samples, since using YUV420 is comparatively lossy.
|
// raw ARGB samples, since using YUV420 is comparatively lossy.
|
||||||
// Returns false in case of error.
|
// Returns false in case of error.
|
||||||
WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
|
||||||
|
|
||||||
// Helper function: given a width x height plane of RGBA or YUV(A) samples
|
// Helper function: given a width x height plane of RGBA or YUV(A) samples
|
||||||
// clean-up the YUV or RGB samples under fully transparent area, to help
|
// clean-up or smoothen the YUV or RGB samples under fully transparent area,
|
||||||
// compressibility (no guarantee, though).
|
// to help compressibility (no guarantee, though).
|
||||||
WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture);
|
WEBP_EXTERN void WebPCleanupTransparentArea(WebPPicture* picture);
|
||||||
|
|
||||||
// Scan the picture 'picture' for the presence of non fully opaque alpha values.
|
// Scan the picture 'picture' for the presence of non fully opaque alpha values.
|
||||||
// Returns true in such case. Otherwise returns false (indicating that the
|
// Returns true in such case. Otherwise returns false (indicating that the
|
||||||
// alpha plane can be ignored altogether e.g.).
|
// alpha plane can be ignored altogether e.g.).
|
||||||
WEBP_EXTERN(int) WebPPictureHasTransparency(const WebPPicture* picture);
|
WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture);
|
||||||
|
|
||||||
// Remove the transparency information (if present) by blending the color with
|
// Remove the transparency information (if present) by blending the color with
|
||||||
// the background color 'background_rgb' (specified as 24bit RGB triplet).
|
// the background color 'background_rgb' (specified as 24bit RGB triplet).
|
||||||
// After this call, all alpha values are reset to 0xff.
|
// After this call, all alpha values are reset to 0xff.
|
||||||
WEBP_EXTERN(void) WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
|
WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Main call
|
// Main call
|
||||||
|
|
@ -531,7 +534,7 @@ WEBP_EXTERN(void) WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
|
||||||
// the former for lossy encoding, and the latter for lossless encoding
|
// the former for lossy encoding, and the latter for lossless encoding
|
||||||
// (when config.lossless is true). Automatic conversion from one format to
|
// (when config.lossless is true). Automatic conversion from one format to
|
||||||
// another is provided but they both incur some loss.
|
// another is provided but they both incur some loss.
|
||||||
WEBP_EXTERN(int) WebPEncode(const WebPConfig* config, WebPPicture* picture);
|
WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ typedef enum WebPChunkId {
|
||||||
|
|
||||||
// Returns the version number of the mux library, packed in hexadecimal using
|
// Returns the version number of the mux library, packed in hexadecimal using
|
||||||
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
WEBP_EXTERN(int) WebPGetMuxVersion(void);
|
WEBP_EXTERN int WebPGetMuxVersion(void);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Life of a Mux object
|
// Life of a Mux object
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(WebPMux*) WebPNewInternal(int);
|
WEBP_EXTERN WebPMux* WebPNewInternal(int);
|
||||||
|
|
||||||
// Creates an empty mux object.
|
// Creates an empty mux object.
|
||||||
// Returns:
|
// Returns:
|
||||||
|
|
@ -117,13 +117,13 @@ static WEBP_INLINE WebPMux* WebPMuxNew(void) {
|
||||||
// Deletes the mux object.
|
// Deletes the mux object.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// mux - (in/out) object to be deleted
|
// mux - (in/out) object to be deleted
|
||||||
WEBP_EXTERN(void) WebPMuxDelete(WebPMux* mux);
|
WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Mux creation.
|
// Mux creation.
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int);
|
WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int);
|
||||||
|
|
||||||
// Creates a mux object from raw data given in WebP RIFF format.
|
// Creates a mux object from raw data given in WebP RIFF format.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
|
|
@ -160,7 +160,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
|
||||||
// or if fourcc corresponds to an image chunk.
|
// or if fourcc corresponds to an image chunk.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
|
WEBP_EXTERN WebPMuxError WebPMuxSetChunk(
|
||||||
WebPMux* mux, const char fourcc[4], const WebPData* chunk_data,
|
WebPMux* mux, const char fourcc[4], const WebPData* chunk_data,
|
||||||
int copy_data);
|
int copy_data);
|
||||||
|
|
||||||
|
|
@ -176,7 +176,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
|
||||||
// or if fourcc corresponds to an image chunk.
|
// or if fourcc corresponds to an image chunk.
|
||||||
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id.
|
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
|
WEBP_EXTERN WebPMuxError WebPMuxGetChunk(
|
||||||
const WebPMux* mux, const char fourcc[4], WebPData* chunk_data);
|
const WebPMux* mux, const char fourcc[4], WebPData* chunk_data);
|
||||||
|
|
||||||
// Deletes the chunk with the given 'fourcc' from the mux object.
|
// Deletes the chunk with the given 'fourcc' from the mux object.
|
||||||
|
|
@ -189,7 +189,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
|
||||||
// or if fourcc corresponds to an image chunk.
|
// or if fourcc corresponds to an image chunk.
|
||||||
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc.
|
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk(
|
WEBP_EXTERN WebPMuxError WebPMuxDeleteChunk(
|
||||||
WebPMux* mux, const char fourcc[4]);
|
WebPMux* mux, const char fourcc[4]);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -222,7 +222,7 @@ struct WebPMuxFrameInfo {
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
|
WEBP_EXTERN WebPMuxError WebPMuxSetImage(
|
||||||
WebPMux* mux, const WebPData* bitstream, int copy_data);
|
WebPMux* mux, const WebPData* bitstream, int copy_data);
|
||||||
|
|
||||||
// Adds a frame at the end of the mux object.
|
// Adds a frame at the end of the mux object.
|
||||||
|
|
@ -241,7 +241,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
|
||||||
// or if content of 'frame' is invalid.
|
// or if content of 'frame' is invalid.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
|
WEBP_EXTERN WebPMuxError WebPMuxPushFrame(
|
||||||
WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data);
|
WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data);
|
||||||
|
|
||||||
// Gets the nth frame from the mux object.
|
// Gets the nth frame from the mux object.
|
||||||
|
|
@ -259,7 +259,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
|
||||||
// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
|
// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
|
WEBP_EXTERN WebPMuxError WebPMuxGetFrame(
|
||||||
const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame);
|
const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame);
|
||||||
|
|
||||||
// Deletes a frame from the mux object.
|
// Deletes a frame from the mux object.
|
||||||
|
|
@ -272,7 +272,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
|
||||||
// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
|
// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
|
||||||
// before deletion.
|
// before deletion.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
|
WEBP_EXTERN WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Animation.
|
// Animation.
|
||||||
|
|
@ -296,7 +296,7 @@ struct WebPMuxAnimParams {
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxSetAnimationParams(
|
WEBP_EXTERN WebPMuxError WebPMuxSetAnimationParams(
|
||||||
WebPMux* mux, const WebPMuxAnimParams* params);
|
WebPMux* mux, const WebPMuxAnimParams* params);
|
||||||
|
|
||||||
// Gets the animation parameters from the mux object.
|
// Gets the animation parameters from the mux object.
|
||||||
|
|
@ -307,7 +307,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetAnimationParams(
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
|
||||||
// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object.
|
// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetAnimationParams(
|
WEBP_EXTERN WebPMuxError WebPMuxGetAnimationParams(
|
||||||
const WebPMux* mux, WebPMuxAnimParams* params);
|
const WebPMux* mux, WebPMuxAnimParams* params);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
@ -328,8 +328,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetAnimationParams(
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or
|
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or
|
||||||
// width or height are invalid or out of bounds
|
// width or height are invalid or out of bounds
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxSetCanvasSize(WebPMux* mux,
|
WEBP_EXTERN WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
|
|
||||||
// Gets the canvas size from the mux object.
|
// Gets the canvas size from the mux object.
|
||||||
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
|
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
|
||||||
|
|
@ -343,8 +343,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetCanvasSize(WebPMux* mux,
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL.
|
||||||
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
|
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
|
WEBP_EXTERN WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux,
|
||||||
int* width, int* height);
|
int* width, int* height);
|
||||||
|
|
||||||
// Gets the feature flags from the mux object.
|
// Gets the feature flags from the mux object.
|
||||||
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
|
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
|
||||||
|
|
@ -359,8 +359,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
|
||||||
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
|
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
|
WEBP_EXTERN WebPMuxError WebPMuxGetFeatures(const WebPMux* mux,
|
||||||
uint32_t* flags);
|
uint32_t* flags);
|
||||||
|
|
||||||
// Gets number of chunks with the given 'id' in the mux object.
|
// Gets number of chunks with the given 'id' in the mux object.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
|
|
@ -370,8 +370,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
|
||||||
// Returns:
|
// Returns:
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
|
WEBP_EXTERN WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
|
||||||
WebPChunkId id, int* num_elements);
|
WebPChunkId id, int* num_elements);
|
||||||
|
|
||||||
// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'.
|
// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'.
|
||||||
// This function also validates the mux object.
|
// This function also validates the mux object.
|
||||||
|
|
@ -388,8 +388,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL.
|
// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL.
|
||||||
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
|
||||||
// WEBP_MUX_OK - on success.
|
// WEBP_MUX_OK - on success.
|
||||||
WEBP_EXTERN(WebPMuxError) WebPMuxAssemble(WebPMux* mux,
|
WEBP_EXTERN WebPMuxError WebPMuxAssemble(WebPMux* mux,
|
||||||
WebPData* assembled_data);
|
WebPData* assembled_data);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// WebPAnimEncoder API
|
// WebPAnimEncoder API
|
||||||
|
|
@ -442,7 +442,7 @@ struct WebPAnimEncoderOptions {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point.
|
// Internal, version-checked, entry point.
|
||||||
WEBP_EXTERN(int) WebPAnimEncoderOptionsInitInternal(
|
WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
|
||||||
WebPAnimEncoderOptions*, int);
|
WebPAnimEncoderOptions*, int);
|
||||||
|
|
||||||
// Should always be called, to initialize a fresh WebPAnimEncoderOptions
|
// Should always be called, to initialize a fresh WebPAnimEncoderOptions
|
||||||
|
|
@ -455,7 +455,7 @@ static WEBP_INLINE int WebPAnimEncoderOptionsInit(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal, version-checked, entry point.
|
// Internal, version-checked, entry point.
|
||||||
WEBP_EXTERN(WebPAnimEncoder*) WebPAnimEncoderNewInternal(
|
WEBP_EXTERN WebPAnimEncoder* WebPAnimEncoderNewInternal(
|
||||||
int, int, const WebPAnimEncoderOptions*, int);
|
int, int, const WebPAnimEncoderOptions*, int);
|
||||||
|
|
||||||
// Creates and initializes a WebPAnimEncoder object.
|
// Creates and initializes a WebPAnimEncoder object.
|
||||||
|
|
@ -490,7 +490,7 @@ static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
|
||||||
// Returns:
|
// Returns:
|
||||||
// On error, returns false and frame->error_code is set appropriately.
|
// On error, returns false and frame->error_code is set appropriately.
|
||||||
// Otherwise, returns true.
|
// Otherwise, returns true.
|
||||||
WEBP_EXTERN(int) WebPAnimEncoderAdd(
|
WEBP_EXTERN int WebPAnimEncoderAdd(
|
||||||
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
|
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
|
||||||
const struct WebPConfig* config);
|
const struct WebPConfig* config);
|
||||||
|
|
||||||
|
|
@ -503,8 +503,8 @@ WEBP_EXTERN(int) WebPAnimEncoderAdd(
|
||||||
// webp_data - (out) generated WebP bitstream.
|
// webp_data - (out) generated WebP bitstream.
|
||||||
// Returns:
|
// Returns:
|
||||||
// True on success.
|
// True on success.
|
||||||
WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
|
WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
|
||||||
WebPData* webp_data);
|
WebPData* webp_data);
|
||||||
|
|
||||||
// Get error string corresponding to the most recent call using 'enc'. The
|
// Get error string corresponding to the most recent call using 'enc'. The
|
||||||
// returned string is owned by 'enc' and is valid only until the next call to
|
// returned string is owned by 'enc' and is valid only until the next call to
|
||||||
|
|
@ -514,12 +514,12 @@ WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
|
||||||
// Returns:
|
// Returns:
|
||||||
// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
|
// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
|
||||||
// to 'enc' had an error, or an empty string if the last call was a success.
|
// to 'enc' had an error, or an empty string if the last call was a success.
|
||||||
WEBP_EXTERN(const char*) WebPAnimEncoderGetError(WebPAnimEncoder* enc);
|
WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
|
||||||
|
|
||||||
// Deletes the WebPAnimEncoder object.
|
// Deletes the WebPAnimEncoder object.
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// enc - (in/out) object to be deleted
|
// enc - (in/out) object to be deleted
|
||||||
WEBP_EXTERN(void) WebPAnimEncoderDelete(WebPAnimEncoder* enc);
|
WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ typedef long long int int64_t;
|
||||||
// This explicitly marks library functions and allows for changing the
|
// This explicitly marks library functions and allows for changing the
|
||||||
// signature for e.g., Windows DLL builds.
|
// signature for e.g., Windows DLL builds.
|
||||||
# if defined(__GNUC__) && __GNUC__ >= 4
|
# if defined(__GNUC__) && __GNUC__ >= 4
|
||||||
# define WEBP_EXTERN(type) extern __attribute__ ((visibility ("default"))) type
|
# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
|
||||||
# else
|
# else
|
||||||
# define WEBP_EXTERN(type) extern type
|
# define WEBP_EXTERN extern
|
||||||
# endif /* __GNUC__ >= 4 */
|
# endif /* __GNUC__ >= 4 */
|
||||||
#endif /* WEBP_EXTERN */
|
#endif /* WEBP_EXTERN */
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue