Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: third_party/libwebp/webp.c

Issue 3614010: Add WebP library to Chromium... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/libwebp/vp8i.h ('k') | third_party/libwebp/webp/decode.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 Google Inc.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // Main decoding functions for WEBP images.
9 //
10 // Author: Skal (pascal.massimino@gmail.com)
11
12 #include <stdlib.h>
13 #include "vp8i.h"
14 #include "yuv.h"
15
16 #if defined(__cplusplus) || defined(c_plusplus)
17 extern "C" {
18 #endif
19
20 //-----------------------------------------------------------------------------
21 // RIFF layout is:
22 // 0ffset tag
23 // 0...3 "RIFF" 4-byte tag
24 // 4...7 size of image data (including metadata) starting at offset 8
25 // 8...11 "WEBP" our form-type signature
26 // 12..15 "VP8 ": 4-bytes tags, describing the raw video format used
27 // 16..19 size of the raw VP8 image data, starting at offset 20
28 // 20.... the VP8 bytes
29 // There can be extra chunks after the "VP8 " chunk (ICMT, ICOP, ...)
30 // All 32-bits sizes are in little-endian order.
31 // Note: chunk data must be padded to multiple of 2 in size
32
33 static inline uint32_t get_le32(const uint8_t* const data) {
34 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
35 }
36
37 // If a RIFF container is detected, validate it and skip over it.
38 static int CheckRIFFHeader(const uint8_t** data_ptr, uint32_t *data_size_ptr) {
39 uint32_t chunk_size = 0xffffffffu;
40 if (*data_size_ptr >= 10 + 20 && !memcmp(*data_ptr, "RIFF", 4)) {
41 if (memcmp(*data_ptr + 8, "WEBP", 4)) {
42 return 0; // wrong image file signature
43 }
44 const uint32_t riff_size = get_le32(*data_ptr + 4);
45 if (memcmp(*data_ptr + 12, "VP8 ", 4)) {
46 return 0; // invalid compression format
47 }
48 chunk_size = get_le32(*data_ptr + 16);
49 if ((chunk_size > riff_size + 8) || (chunk_size & 1)) {
50 return 0; // inconsistent size information.
51 }
52 // We have a IFF container. Skip it.
53 *data_ptr += 20;
54 *data_size_ptr -= 20;
55 }
56 return chunk_size;
57 }
58
59 //-----------------------------------------------------------------------------
60
61 typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
62 MODE_BGR = 2, MODE_BGRA = 3,
63 MODE_YUV = 4 } CSP_MODE;
64
65 typedef struct {
66 uint8_t* output; // rgb(a) or luma
67 uint8_t *u, *v;
68 int stride; // rgb(a) stride or luma stride
69 int u_stride;
70 int v_stride;
71 CSP_MODE mode;
72 } Params;
73
74 static void CustomPut(const VP8Io* io) {
75 Params *p = (Params*)io->opaque;
76 const int mb_w = io->mb_w;
77 const int mb_h = io->mb_h;
78 if (p->mode == MODE_YUV) {
79 uint8_t* const y_dst = p->output + io->mb_x + io->mb_y * p->stride;
80 for (int j = 0; j < mb_h; ++j) {
81 memcpy(y_dst + j * p->stride, io->y + j * io->y_stride, mb_w);
82 }
83 uint8_t* const u_dst = p->u + (io->mb_x / 2) + (io->mb_y / 2) * p->u_stride;
84 uint8_t* const v_dst = p->v + (io->mb_x / 2) + (io->mb_y / 2) * p->v_stride;
85 const int uv_w = (mb_w + 1) / 2;
86 for (int j = 0; j < (mb_h + 1) / 2; ++j) {
87 memcpy(u_dst + j * p->u_stride, io->u + j * io->uv_stride, uv_w);
88 memcpy(v_dst + j * p->v_stride, io->v + j * io->uv_stride, uv_w);
89 }
90 } else {
91 const int psize = (p->mode == MODE_RGB || p->mode == MODE_BGR) ? 3 : 4;
92 uint8_t* dst = p->output + psize * io->mb_x + io->mb_y * p->stride;
93 for (int j = 0; j < mb_h; ++j) {
94 const uint8_t* y_src = io->y + j * io->y_stride;
95 for (int i = 0; i < mb_w; ++i) {
96 const int y = y_src[i];
97 const int u = io->u[(j / 2) * io->uv_stride + (i / 2)];
98 const int v = io->v[(j / 2) * io->uv_stride + (i / 2)];
99 if (p->mode == MODE_RGB) {
100 VP8YuvToRgb(y, u, v, dst + i * 3);
101 } else if (p->mode == MODE_BGR) {
102 VP8YuvToBgr(y, u, v, dst + i * 3);
103 } else if (p->mode == MODE_RGBA) {
104 VP8YuvToRgba(y, u, v, dst + i * 4);
105 } else {
106 VP8YuvToBgra(y, u, v, dst + i * 4);
107 }
108 }
109 dst += p->stride;
110 }
111 }
112 }
113
114
115 //-----------------------------------------------------------------------------
116 // "Into" variants
117
118 static uint8_t* DecodeInto(CSP_MODE mode,
119 const uint8_t* data, uint32_t data_size,
120 Params* params, int output_size,
121 int output_u_size, int output_v_size) {
122 VP8Decoder* dec = VP8New();
123 if (dec == NULL) {
124 return NULL;
125 }
126
127 VP8Io io;
128 VP8InitIo(&io);
129 io.data = data;
130 io.data_size = data_size;
131
132 params->mode = mode;
133 io.opaque = params;
134 io.put = CustomPut;
135
136 if (!VP8GetHeaders(dec, &io)) {
137 VP8Delete(dec);
138 return NULL;
139 }
140 // check output buffers
141 int ok = 1;
142 ok &= (params->stride * io.height <= output_size);
143 if (mode == MODE_RGB || mode == MODE_BGR) {
144 ok &= (params->stride >= io.width * 3);
145 } else if (mode == MODE_RGBA || mode == MODE_BGRA) {
146 ok &= (params->stride >= io.width * 4);
147 } else {
148 ok &= (params->stride >= io.width);
149 // some extra checks for U/V
150 const int u_size = params->u_stride * ((io.height + 1) / 2);
151 const int v_size = params->v_stride * ((io.height + 1) / 2);
152 ok &= (params->u_stride >= (io.width + 1) / 2) &&
153 (params->v_stride >= (io.width + 1) / 2);
154 ok &= (u_size <= output_u_size && v_size <= output_v_size);
155 }
156 if (!ok) {
157 VP8Delete(dec);
158 return NULL;
159 }
160
161 if (mode != MODE_YUV) {
162 VP8YUVInit();
163 }
164
165 ok = VP8Decode(dec, &io);
166 VP8Delete(dec);
167 return ok ? params->output : NULL;
168 }
169
170 uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
171 uint8_t* output, int output_size,
172 int output_stride) {
173 if (output == NULL) {
174 return NULL;
175 }
176 Params params;
177 params.output = output;
178 params.stride = output_stride;
179 return DecodeInto(MODE_RGB, data, data_size, &params, output_size, 0, 0);
180 }
181
182 uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
183 uint8_t* output, int output_size,
184 int output_stride) {
185 if (output == NULL) {
186 return NULL;
187 }
188 Params params;
189 params.output = output;
190 params.stride = output_stride;
191 return DecodeInto(MODE_RGBA, data, data_size, &params, output_size, 0, 0);
192 }
193
194 uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
195 uint8_t* output, int output_size,
196 int output_stride) {
197 if (output == NULL) {
198 return NULL;
199 }
200 Params params;
201 params.output = output;
202 params.stride = output_stride;
203 return DecodeInto(MODE_BGR, data, data_size, &params, output_size, 0, 0);
204 }
205
206 uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
207 uint8_t* output, int output_size,
208 int output_stride) {
209 if (output == NULL) {
210 return NULL;
211 }
212 Params params;
213 params.output = output;
214 params.stride = output_stride;
215 return DecodeInto(MODE_BGRA, data, data_size, &params, output_size, 0, 0);
216 }
217
218 uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
219 uint8_t* luma, int luma_size, int luma_stride,
220 uint8_t* u, int u_size, int u_stride,
221 uint8_t* v, int v_size, int v_stride) {
222 if (luma == NULL) {
223 return NULL;
224 }
225 Params params;
226 params.output = luma;
227 params.stride = luma_stride;
228 params.u = u;
229 params.u_stride = u_stride;
230 params.v = v;
231 params.v_stride = v_stride;
232 return DecodeInto(MODE_YUV, data, data_size, &params,
233 luma_size, u_size, v_size);
234 }
235
236 //-----------------------------------------------------------------------------
237
238 static uint8_t* Decode(CSP_MODE mode, const uint8_t* data, uint32_t data_size,
239 int* width, int* height, Params* params_out) {
240 int w, h;
241 if (!WebPGetInfo(data, data_size, &w, &h)) {
242 return NULL;
243 }
244 if (width) *width = w;
245 if (height) *height = h;
246
247 // initialize output buffer, now that dimensions are known.
248 int stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
249 : (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
250 : w;
251 const int size = stride * h;
252 int uv_size = 0;
253 int uv_stride = 0;
254 if (mode == MODE_YUV) {
255 uv_stride = (w + 1) / 2;
256 uv_size = uv_stride * ((h + 1) / 2);
257 }
258 uint8_t* const output = (uint8_t*)malloc(size + 2 * uv_size);
259 if (!output) {
260 return NULL;
261 }
262 Params params = { 0 };
263 params.output = output;
264 params.stride = stride;
265 if (mode == MODE_YUV) {
266 params.u = output + size;
267 params.u_stride = uv_stride;
268 params.v = output + size + uv_size;
269 params.v_stride = uv_stride;
270 }
271 if (params_out) *params_out = params;
272 return DecodeInto(mode, data, data_size, &params, size, uv_size, uv_size);
273 }
274
275 uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
276 int *width, int *height) {
277 return Decode(MODE_RGB, data, data_size, width, height, NULL);
278 }
279
280 uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
281 int *width, int *height) {
282 return Decode(MODE_RGBA, data, data_size, width, height, NULL);
283 }
284
285 uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
286 int *width, int *height) {
287 return Decode(MODE_BGR, data, data_size, width, height, NULL);
288 }
289
290 uint8_t* WebPDecodeBGRA(const uint8_t* data, uint32_t data_size,
291 int *width, int *height) {
292 return Decode(MODE_BGRA, data, data_size, width, height, NULL);
293 }
294
295 uint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size,
296 int *width, int *height, uint8_t** u, uint8_t** v,
297 int *stride, int* uv_stride) {
298 Params params;
299 uint8_t* const out = Decode(MODE_YUV, data, data_size,
300 width, height, &params);
301
302 if (out) {
303 *u = params.u;
304 *v = params.v;
305 *stride = params.stride;
306 *uv_stride = params.u_stride;
307 assert(params.u_stride == params.v_stride);
308 }
309 return out;
310 }
311
312 //-----------------------------------------------------------------------------
313 // WebPGetInfo()
314
315 int WebPGetInfo(const uint8_t* data, uint32_t data_size,
316 int *width, int *height) {
317 const uint32_t chunk_size = CheckRIFFHeader(&data, &data_size);
318 if (!chunk_size) {
319 return 0; // unsupported RIFF header
320 }
321 // Validate raw video data
322 if (data_size < 10) {
323 return 0; // not enough data
324 }
325 // check signature
326 if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) {
327 return 0; // Wrong signature.
328 }
329 const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
330 const int key_frame = !(bits & 1);
331 if (!key_frame) { // Not a keyframe.
332 return 0;
333 }
334 const int profile = (bits >> 1) & 7;
335 const int show_frame = (bits >> 4) & 1;
336 const uint32_t partition_length = (bits >> 5);
337 if (profile > 3) {
338 return 0; // unknown profile
339 }
340 if (!show_frame) {
341 return 0; // first frame is invisible!
342 }
343 if (partition_length >= chunk_size) {
344 return 0; // inconsistent size information.
345 }
346
347 const int w = ((data[7] << 8) | data[6]) & 0x3fff;
348 const int h = ((data[9] << 8) | data[8]) & 0x3fff;
349 if (width) {
350 *width = w;
351 }
352 if (height) {
353 *height = h;
354 }
355
356 return 1;
357 }
358
359 #if defined(__cplusplus) || defined(c_plusplus)
360 } // extern "C"
361 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/vp8i.h ('k') | third_party/libwebp/webp/decode.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698