1 // Copyright 2011 Google Inc. All Rights Reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
10 // WebPPicture class basis
12 // Author: Skal (pascal.massimino@gmail.com)
17 #include "./vp8enci.h"
18 #include "../utils/utils.h"
20 //------------------------------------------------------------------------------
22 //------------------------------------------------------------------------------
24 static int DummyWriter(const uint8_t* data
, size_t data_size
,
25 const WebPPicture
* const picture
) {
26 // The following are to prevent 'unused variable' error message.
33 int WebPPictureInitInternal(WebPPicture
* picture
, int version
) {
34 if (WEBP_ABI_IS_INCOMPATIBLE(version
, WEBP_ENCODER_ABI_VERSION
)) {
35 return 0; // caller/system version mismatch!
37 if (picture
!= NULL
) {
38 memset(picture
, 0, sizeof(*picture
));
39 picture
->writer
= DummyWriter
;
40 WebPEncodingSetError(picture
, VP8_ENC_OK
);
45 //------------------------------------------------------------------------------
47 static void WebPPictureResetBufferARGB(WebPPicture
* const picture
) {
48 picture
->memory_argb_
= NULL
;
50 picture
->argb_stride
= 0;
53 static void WebPPictureResetBufferYUVA(WebPPicture
* const picture
) {
54 picture
->memory_
= NULL
;
55 picture
->y
= picture
->u
= picture
->v
= picture
->a
= NULL
;
56 picture
->y_stride
= picture
->uv_stride
= 0;
57 picture
->a_stride
= 0;
60 void WebPPictureResetBuffers(WebPPicture
* const picture
) {
61 WebPPictureResetBufferARGB(picture
);
62 WebPPictureResetBufferYUVA(picture
);
65 int WebPPictureAllocARGB(WebPPicture
* const picture
, int width
, int height
) {
67 const uint64_t argb_size
= (uint64_t)width
* height
;
69 assert(picture
!= NULL
);
71 WebPSafeFree(picture
->memory_argb_
);
72 WebPPictureResetBufferARGB(picture
);
74 if (width
<= 0 || height
<= 0) {
75 return WebPEncodingSetError(picture
, VP8_ENC_ERROR_BAD_DIMENSION
);
77 // allocate a new buffer.
78 memory
= WebPSafeMalloc(argb_size
, sizeof(*picture
->argb
));
80 return WebPEncodingSetError(picture
, VP8_ENC_ERROR_OUT_OF_MEMORY
);
82 // TODO(skal): align plane to cache line?
83 picture
->memory_argb_
= memory
;
84 picture
->argb
= (uint32_t*)memory
;
85 picture
->argb_stride
= width
;
89 int WebPPictureAllocYUVA(WebPPicture
* const picture
, int width
, int height
) {
90 const WebPEncCSP uv_csp
= picture
->colorspace
& WEBP_CSP_UV_MASK
;
91 const int has_alpha
= picture
->colorspace
& WEBP_CSP_ALPHA_BIT
;
92 const int y_stride
= width
;
93 const int uv_width
= (width
+ 1) >> 1;
94 const int uv_height
= (height
+ 1) >> 1;
95 const int uv_stride
= uv_width
;
96 int a_width
, a_stride
;
97 uint64_t y_size
, uv_size
, a_size
, total_size
;
100 assert(picture
!= NULL
);
102 WebPSafeFree(picture
->memory_
);
103 WebPPictureResetBufferYUVA(picture
);
105 if (uv_csp
!= WEBP_YUV420
) {
106 return WebPEncodingSetError(picture
, VP8_ENC_ERROR_INVALID_CONFIGURATION
);
110 a_width
= has_alpha
? width
: 0;
112 y_size
= (uint64_t)y_stride
* height
;
113 uv_size
= (uint64_t)uv_stride
* uv_height
;
114 a_size
= (uint64_t)a_stride
* height
;
116 total_size
= y_size
+ a_size
+ 2 * uv_size
;
118 // Security and validation checks
119 if (width
<= 0 || height
<= 0 || // luma/alpha param error
120 uv_width
< 0 || uv_height
< 0) { // u/v param error
121 return WebPEncodingSetError(picture
, VP8_ENC_ERROR_BAD_DIMENSION
);
123 // allocate a new buffer.
124 mem
= (uint8_t*)WebPSafeMalloc(total_size
, sizeof(*mem
));
126 return WebPEncodingSetError(picture
, VP8_ENC_ERROR_OUT_OF_MEMORY
);
129 // From now on, we're in the clear, we can no longer fail...
130 picture
->memory_
= (void*)mem
;
131 picture
->y_stride
= y_stride
;
132 picture
->uv_stride
= uv_stride
;
133 picture
->a_stride
= a_stride
;
135 // TODO(skal): we could align the y/u/v planes and adjust stride.
148 (void)mem
; // makes the static analyzer happy
152 int WebPPictureAlloc(WebPPicture
* picture
) {
153 if (picture
!= NULL
) {
154 const int width
= picture
->width
;
155 const int height
= picture
->height
;
157 WebPPictureFree(picture
); // erase previous buffer
159 if (!picture
->use_argb
) {
160 return WebPPictureAllocYUVA(picture
, width
, height
);
162 return WebPPictureAllocARGB(picture
, width
, height
);
168 void WebPPictureFree(WebPPicture
* picture
) {
169 if (picture
!= NULL
) {
170 WebPSafeFree(picture
->memory_
);
171 WebPSafeFree(picture
->memory_argb_
);
172 WebPPictureResetBuffers(picture
);
176 //------------------------------------------------------------------------------
177 // WebPMemoryWriter: Write-to-memory
179 void WebPMemoryWriterInit(WebPMemoryWriter
* writer
) {
182 writer
->max_size
= 0;
185 int WebPMemoryWrite(const uint8_t* data
, size_t data_size
,
186 const WebPPicture
* picture
) {
187 WebPMemoryWriter
* const w
= (WebPMemoryWriter
*)picture
->custom_ptr
;
192 next_size
= (uint64_t)w
->size
+ data_size
;
193 if (next_size
> w
->max_size
) {
195 uint64_t next_max_size
= 2ULL * w
->max_size
;
196 if (next_max_size
< next_size
) next_max_size
= next_size
;
197 if (next_max_size
< 8192ULL) next_max_size
= 8192ULL;
198 new_mem
= (uint8_t*)WebPSafeMalloc(next_max_size
, 1);
199 if (new_mem
== NULL
) {
203 memcpy(new_mem
, w
->mem
, w
->size
);
205 WebPSafeFree(w
->mem
);
207 // down-cast is ok, thanks to WebPSafeMalloc
208 w
->max_size
= (size_t)next_max_size
;
211 memcpy(w
->mem
+ w
->size
, data
, data_size
);
212 w
->size
+= data_size
;
217 void WebPMemoryWriterClear(WebPMemoryWriter
* writer
) {
218 if (writer
!= NULL
) {
219 WebPSafeFree(writer
->mem
);
222 writer
->max_size
= 0;
226 //------------------------------------------------------------------------------
227 // Simplest high-level calls:
229 typedef int (*Importer
)(WebPPicture
* const, const uint8_t* const, int);
231 static size_t Encode(const uint8_t* rgba
, int width
, int height
, int stride
,
232 Importer import
, float quality_factor
, int lossless
,
236 WebPMemoryWriter wrt
;
239 if (!WebPConfigPreset(&config
, WEBP_PRESET_DEFAULT
, quality_factor
) ||
240 !WebPPictureInit(&pic
)) {
241 return 0; // shouldn't happen, except if system installation is broken
244 config
.lossless
= !!lossless
;
245 pic
.use_argb
= !!lossless
;
248 pic
.writer
= WebPMemoryWrite
;
249 pic
.custom_ptr
= &wrt
;
250 WebPMemoryWriterInit(&wrt
);
252 ok
= import(&pic
, rgba
, stride
) && WebPEncode(&config
, &pic
);
253 WebPPictureFree(&pic
);
255 WebPMemoryWriterClear(&wrt
);
263 #define ENCODE_FUNC(NAME, IMPORTER) \
264 size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \
266 return Encode(in, w, h, bps, IMPORTER, q, 0, out); \
269 ENCODE_FUNC(WebPEncodeRGB
, WebPPictureImportRGB
)
270 ENCODE_FUNC(WebPEncodeBGR
, WebPPictureImportBGR
)
271 ENCODE_FUNC(WebPEncodeRGBA
, WebPPictureImportRGBA
)
272 ENCODE_FUNC(WebPEncodeBGRA
, WebPPictureImportBGRA
)
276 #define LOSSLESS_DEFAULT_QUALITY 70.
277 #define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \
278 size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \
279 return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \
282 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB
, WebPPictureImportRGB
)
283 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR
, WebPPictureImportBGR
)
284 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA
, WebPPictureImportRGBA
)
285 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA
, WebPPictureImportBGRA
)
287 #undef LOSSLESS_ENCODE_FUNC
289 //------------------------------------------------------------------------------