1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
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 // -----------------------------------------------------------------------------
9 //
10 // WebPPicture class basis
11 //
12 // Author: Skal (pascal.massimino@gmail.com)
13 
14 #include <assert.h>
15 #include <stdlib.h>
16 
17 #include "./vp8enci.h"
18 #include "../utils/utils.h"
19 
20 //------------------------------------------------------------------------------
21 // WebPPicture
22 //------------------------------------------------------------------------------
23 
DummyWriter(const uint8_t * data,size_t data_size,const WebPPicture * const picture)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.
27   (void)data;
28   (void)data_size;
29   (void)picture;
30   return 1;
31 }
32 
WebPPictureInitInternal(WebPPicture * picture,int version)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!
36   }
37   if (picture != NULL) {
38     memset(picture, 0, sizeof(*picture));
39     picture->writer = DummyWriter;
40     WebPEncodingSetError(picture, VP8_ENC_OK);
41   }
42   return 1;
43 }
44 
45 //------------------------------------------------------------------------------
46 
WebPPictureResetBufferARGB(WebPPicture * const picture)47 static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
48   picture->memory_argb_ = NULL;
49   picture->argb = NULL;
50   picture->argb_stride = 0;
51 }
52 
WebPPictureResetBufferYUVA(WebPPicture * const picture)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;
58 }
59 
WebPPictureResetBuffers(WebPPicture * const picture)60 void WebPPictureResetBuffers(WebPPicture* const picture) {
61   WebPPictureResetBufferARGB(picture);
62   WebPPictureResetBufferYUVA(picture);
63 }
64 
WebPPictureAllocARGB(WebPPicture * const picture,int width,int height)65 int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
66   void* memory;
67   const uint64_t argb_size = (uint64_t)width * height;
68 
69   assert(picture != NULL);
70 
71   WebPSafeFree(picture->memory_argb_);
72   WebPPictureResetBufferARGB(picture);
73 
74   if (width <= 0 || height <= 0) {
75     return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
76   }
77   // allocate a new buffer.
78   memory = WebPSafeMalloc(argb_size, sizeof(*picture->argb));
79   if (memory == NULL) {
80     return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
81   }
82   // TODO(skal): align plane to cache line?
83   picture->memory_argb_ = memory;
84   picture->argb = (uint32_t*)memory;
85   picture->argb_stride = width;
86   return 1;
87 }
88 
WebPPictureAllocYUVA(WebPPicture * const picture,int width,int height)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;
98   uint8_t* mem;
99 
100   assert(picture != NULL);
101 
102   WebPSafeFree(picture->memory_);
103   WebPPictureResetBufferYUVA(picture);
104 
105   if (uv_csp != WEBP_YUV420) {
106     return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
107   }
108 
109   // alpha
110   a_width = has_alpha ? width : 0;
111   a_stride = a_width;
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;
115 
116   total_size = y_size + a_size + 2 * uv_size;
117 
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);
122   }
123   // allocate a new buffer.
124   mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
125   if (mem == NULL) {
126     return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
127   }
128 
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;
134 
135   // TODO(skal): we could align the y/u/v planes and adjust stride.
136   picture->y = mem;
137   mem += y_size;
138 
139   picture->u = mem;
140   mem += uv_size;
141   picture->v = mem;
142   mem += uv_size;
143 
144   if (a_size > 0) {
145     picture->a = mem;
146     mem += a_size;
147   }
148   (void)mem;  // makes the static analyzer happy
149   return 1;
150 }
151 
WebPPictureAlloc(WebPPicture * picture)152 int WebPPictureAlloc(WebPPicture* picture) {
153   if (picture != NULL) {
154     const int width = picture->width;
155     const int height = picture->height;
156 
157     WebPPictureFree(picture);   // erase previous buffer
158 
159     if (!picture->use_argb) {
160       return WebPPictureAllocYUVA(picture, width, height);
161     } else {
162       return WebPPictureAllocARGB(picture, width, height);
163     }
164   }
165   return 1;
166 }
167 
WebPPictureFree(WebPPicture * picture)168 void WebPPictureFree(WebPPicture* picture) {
169   if (picture != NULL) {
170     WebPSafeFree(picture->memory_);
171     WebPSafeFree(picture->memory_argb_);
172     WebPPictureResetBuffers(picture);
173   }
174 }
175 
176 //------------------------------------------------------------------------------
177 // WebPMemoryWriter: Write-to-memory
178 
WebPMemoryWriterInit(WebPMemoryWriter * writer)179 void WebPMemoryWriterInit(WebPMemoryWriter* writer) {
180   writer->mem = NULL;
181   writer->size = 0;
182   writer->max_size = 0;
183 }
184 
WebPMemoryWrite(const uint8_t * data,size_t data_size,const WebPPicture * picture)185 int WebPMemoryWrite(const uint8_t* data, size_t data_size,
186                     const WebPPicture* picture) {
187   WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;
188   uint64_t next_size;
189   if (w == NULL) {
190     return 1;
191   }
192   next_size = (uint64_t)w->size + data_size;
193   if (next_size > w->max_size) {
194     uint8_t* new_mem;
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) {
200       return 0;
201     }
202     if (w->size > 0) {
203       memcpy(new_mem, w->mem, w->size);
204     }
205     WebPSafeFree(w->mem);
206     w->mem = new_mem;
207     // down-cast is ok, thanks to WebPSafeMalloc
208     w->max_size = (size_t)next_max_size;
209   }
210   if (data_size > 0) {
211     memcpy(w->mem + w->size, data, data_size);
212     w->size += data_size;
213   }
214   return 1;
215 }
216 
WebPMemoryWriterClear(WebPMemoryWriter * writer)217 void WebPMemoryWriterClear(WebPMemoryWriter* writer) {
218   if (writer != NULL) {
219     WebPSafeFree(writer->mem);
220     writer->mem = NULL;
221     writer->size = 0;
222     writer->max_size = 0;
223   }
224 }
225 
226 //------------------------------------------------------------------------------
227 // Simplest high-level calls:
228 
229 typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
230 
Encode(const uint8_t * rgba,int width,int height,int stride,Importer import,float quality_factor,int lossless,uint8_t ** output)231 static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
232                      Importer import, float quality_factor, int lossless,
233                      uint8_t** output) {
234   WebPPicture pic;
235   WebPConfig config;
236   WebPMemoryWriter wrt;
237   int ok;
238 
239   if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||
240       !WebPPictureInit(&pic)) {
241     return 0;  // shouldn't happen, except if system installation is broken
242   }
243 
244   config.lossless = !!lossless;
245   pic.use_argb = !!lossless;
246   pic.width = width;
247   pic.height = height;
248   pic.writer = WebPMemoryWrite;
249   pic.custom_ptr = &wrt;
250   WebPMemoryWriterInit(&wrt);
251 
252   ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
253   WebPPictureFree(&pic);
254   if (!ok) {
255     WebPMemoryWriterClear(&wrt);
256     *output = NULL;
257     return 0;
258   }
259   *output = wrt.mem;
260   return wrt.size;
261 }
262 
263 #define ENCODE_FUNC(NAME, IMPORTER)                                     \
264 size_t NAME(const uint8_t* in, int w, int h, int bps, float q,          \
265             uint8_t** out) {                                            \
266   return Encode(in, w, h, bps, IMPORTER, q, 0, out);                    \
267 }
268 
269 ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)
270 ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)
271 ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)
272 ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)
273 
274 #undef ENCODE_FUNC
275 
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);  \
280 }
281 
282 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)
283 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)
284 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)
285 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
286 
287 #undef LOSSLESS_ENCODE_FUNC
288 
289 //------------------------------------------------------------------------------
290