SkImageDecoder_libwebp.cpp revision 8432fc7b32e4de877bb86b38c050b944bed53f14
1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkImageDecoder.h"
18#include "SkImageEncoder.h"
19#include "SkColorPriv.h"
20#include "SkDither.h"
21#include "SkScaledBitmapSampler.h"
22#include "SkStream.h"
23#include "SkTemplates.h"
24#include "SkUtils.h"
25
26// A WebP decoder only, on top of (subset of) libwebp
27// For more information on WebP image format, and libwebp library, see:
28//   http://code.google.com/speed/webp/
29//   http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
30//   http://review.webmproject.org/gitweb?p=libwebp.git
31
32#include <stdio.h>
33extern "C" {
34// If moving libwebp out of skia source tree, path for webp headers must be updated accordingly.
35// Here, we enforce using local copy in webp sub-directory.
36#include "webp/decode.h"
37#include "webp/decode_vp8.h"
38}
39
40/* If defined, work around missing padding byte in content generated by webpconv */
41#define WEBPCONV_MISSING_PADDING 1
42
43#ifdef ANDROID
44#include <cutils/properties.h>
45
46// Key to lookup the size of memory buffer set in system property
47static const char KEY_MEM_CAP[] = "ro.media.dec.webp.memcap";
48#endif
49
50// this enables timing code to report milliseconds for a decode
51//#define TIME_DECODE
52
53//////////////////////////////////////////////////////////////////////////
54//////////////////////////////////////////////////////////////////////////
55
56// Define VP8 I/O on top of Skia stream
57
58//////////////////////////////////////////////////////////////////////////
59//////////////////////////////////////////////////////////////////////////
60
61// An helper to extract a integer (little endian) from byte array. This is
62// called only once per decoding, so no real need to optimize it in any way
63static uint32_t getint32l(unsigned char *in) {
64    int result;
65    unsigned char *buffer = (unsigned char*) in;
66
67    if (buffer == NULL) {
68        return 0;
69    }
70
71    result = buffer[3];
72    result = (result << 8) + buffer[2];
73    result = (result << 8) + buffer[1];
74    result = (result << 8) + buffer[0];
75
76    return result;
77}
78
79// Parse headers of RIFF container, and check for valid Webp (VP8) content
80// return VP8 chunk content size on success, 0 on error.
81static const size_t WEBP_HEADER_SIZE = 20;
82static const size_t VP8_HEADER_SIZE = 10;
83
84static uint32_t webp_parse_header(SkStream* stream) {
85    unsigned char buffer[WEBP_HEADER_SIZE];
86    size_t len;
87    uint32_t totalSize;
88    uint32_t contentSize;
89
90    // RIFF container for WEBP image should always have:
91    // 0  "RIFF" 4-byte tag
92    // 4  size of image data (including metadata) starting at offset 8
93    // 8  "WEBP" the form-type signature
94    // 12 "VP8 " 4-bytes tags, describing the raw video format used
95    // 16 size of the raw VP8 image data, starting at offset 20
96    // 20 the VP8 bytes
97    // First check for RIFF top chunk, consuming only 8 bytes
98    len = stream->read(buffer, 8);
99    if (len != 8) {
100        return 0; // can't read enough
101    }
102    // Inline magic matching instead of memcmp()
103    if (buffer[0] != 'R' || buffer[1] != 'I' || buffer[2] != 'F' || buffer[3] != 'F') {
104        return 0;
105    }
106
107    totalSize = getint32l(buffer + 4);
108    if (totalSize < (int) (WEBP_HEADER_SIZE - 8)) {
109        return 0;
110    }
111
112    // If RIFF header found, check for RIFF content to start with WEBP/VP8 chunk
113    len = stream->read(buffer + 8, WEBP_HEADER_SIZE - 8);
114    if (len != (int) (WEBP_HEADER_SIZE - 8)) {
115        return 0;
116    }
117    if (buffer[8] != 'W' || buffer[9] != 'E' || buffer[10] != 'B' || buffer[11] != 'P') {
118        return 0;
119    }
120    if (buffer[12] != 'V' || buffer[13] != 'P' || buffer[14] != '8' || buffer[15] != ' ') {
121        return 0;
122    }
123
124    // Magic matches, extract content size
125    contentSize = getint32l(buffer + 16);
126
127    // Check consistency of reported sizes
128    if (contentSize <= 0 || contentSize > 0x7fffffff) {
129        return 0;
130    }
131    if (totalSize < 12 + contentSize) {
132        return 0;
133    }
134    if (contentSize & 1) {
135        return 0;
136    }
137
138    return contentSize;
139}
140
141class SkWEBPImageDecoder: public SkImageDecoder {
142public:
143    virtual Format getFormat() const {
144        return kWEBP_Format;
145    }
146
147protected:
148    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
149};
150
151//////////////////////////////////////////////////////////////////////////
152
153#include "SkTime.h"
154
155class AutoTimeMillis {
156public:
157    AutoTimeMillis(const char label[]) :
158        fLabel(label) {
159        if (!fLabel) {
160            fLabel = "";
161        }
162        fNow = SkTime::GetMSecs();
163    }
164    ~AutoTimeMillis() {
165        SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
166    }
167private:
168    const char* fLabel;
169    SkMSec fNow;
170};
171
172///////////////////////////////////////////////////////////////////////////////
173
174// This guy exists just to aid in debugging, as it allows debuggers to just
175// set a break-point in one place to see all error exists.
176static bool return_false(const SkBitmap& bm, const char msg[]) {
177#if 0
178    SkDebugf("libwebp error %s [%d %d]", msg, bm.width(), bm.height());
179#endif
180    return false; // must always return false
181}
182
183typedef struct {
184    SkBitmap* image;
185    SkStream* stream;
186} WEBPImage;
187
188// WebP library embeds its own YUV to RGB converter. However, High-level API doesn't take benefit
189// of (U,v) clipped values being valid for up to 4 pixels, and so there is a significant improvement
190// in performance in handling this on our own.
191// TODO: use architecture-optimized (eventually hardware-accelerated) YUV converters
192#define YUV_HALF (1 << (YUV_FIX - 1))
193#define YUV_FIX 16                   // fixed-point precision
194#define YUV_RANGE_MIN (-227)         // min value of r/g/b output
195#define YUV_RANGE_MAX (256 + 226)    // max value of r/g/b output
196static int16_t VP8kVToR[256], VP8kUToB[256];
197static int32_t VP8kVToG[256], VP8kUToG[256];
198static uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
199
200static void yuv_init_tables() {
201    int i;
202
203    for (i = 0; i < 256; ++i) {
204        VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
205        VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
206        VP8kVToG[i] = -45773 * (i - 128);
207        VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
208    }
209    for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
210        const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
211        VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
212    }
213}
214
215// Static global mutex to protect Webp initialization
216static SkMutex gYUVMutex;
217static bool gYUVReady = false;
218
219static bool yuv_init() {
220    if (!gYUVReady) {
221        gYUVMutex.acquire();
222        if (!gYUVReady) {
223            yuv_init_tables();
224            gYUVReady = true;
225        }
226        gYUVMutex.release();
227    }
228
229    return gYUVReady;
230}
231
232#define PutRGBA(p,r,g,b) (((SkPMColor*) (p))[0] = SkPackARGB32(0xff,(r),(g),(b)))
233#define PutRGB565(p,r,g,b) (((SkPMColor16*) (p))[0] = SkPackRGB16((r)>>3,(g)>>2,(b)>>3))
234#define PutRGBA4444(p,r,g,b) (((SkPMColor16*) (p))[0] = SkPackARGB4444(0xf,(r)>>4,(g)>>4,(b)>>4))
235
236#define CRGBA(p,y,roff,goff,boff) PutRGBA(p,         \
237          VP8kClip[(y) + (roff) - YUV_RANGE_MIN],    \
238          VP8kClip[(y) + (goff) - YUV_RANGE_MIN],    \
239          VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
240#define CRGB565(p,y,roff,goff,boff) PutRGB565(p,     \
241          VP8kClip[(y) + (roff) - YUV_RANGE_MIN],    \
242          VP8kClip[(y) + (goff) - YUV_RANGE_MIN],    \
243          VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
244#define CRGBA4444(p,y,roff,goff,boff) PutRGBA4444(p, \
245          VP8kClip[(y) + (roff) - YUV_RANGE_MIN],    \
246          VP8kClip[(y) + (goff) - YUV_RANGE_MIN],    \
247          VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
248
249static void block_put(const VP8Io* io) {
250    WEBPImage *p = (WEBPImage*) io->opaque;
251    SkBitmap* decodedBitmap = p->image;
252
253    const int w = io->width;
254    const int mb_h = io->mb_h;
255
256    const uint8_t *y, *y2, *u, *v;
257    const uint8_t *py, *py2, *pu, *pv;
258
259    uint8_t* pout;
260    uint8_t* pout2;
261
262    int i, j;
263    const int ystride2 = io->y_stride * 2;
264    int bpp;
265    SkBitmap::Config config = decodedBitmap->config();
266
267    //SkASSERT(!(io->mb_y & 1));
268
269    y = io->y;
270    u = io->u;
271    v = io->v;
272
273    switch (config) {
274        case SkBitmap::kARGB_8888_Config:
275            bpp = 4;
276            break;
277        case SkBitmap::kRGB_565_Config:
278            bpp = 2;
279            break;
280        case SkBitmap::kARGB_4444_Config:
281            bpp = 2;
282            break;
283        default:
284            // Unsupported config
285            return;
286    }
287
288    for (j = 0; j < mb_h;) {
289        pout = decodedBitmap->getAddr8(0, io->mb_y + j);
290        if (j + 1 < mb_h) {
291            y2 = y + io->y_stride;
292            pout2 = decodedBitmap->getAddr8(0, io->mb_y + j + 1);
293        } else {
294            y2 = NULL;
295            pout2 = NULL;
296        }
297
298        // Copy YUV into target buffer
299        py = y;
300        pu = u;
301        pv = v;
302
303        py2 = y2;
304
305        // Leave test for config out of inner loop. This implies some redundancy in code,
306        // but help in supporting several configs without degrading performance.
307        // As a reminder, one must *NOT* put py increment into parameters (i.e. *py++) in the hope to
308        // improve performance or code readability. Since it is used as argument of a macro which uses it
309        // several times in its expression, so this would end up in having it too much incremented
310        switch (config) {
311            case SkBitmap::kARGB_8888_Config:
312                for (i = 0; i < w; i += 2) {
313                    // U and V are common for up to 4 pixels
314                    const int r_off = VP8kVToR[*pv];
315                    const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
316                    const int b_off = VP8kUToB[*pu];
317
318                    CRGBA(pout, *py, r_off, g_off, b_off);
319                    pout += bpp;
320                    py++;
321
322                    // Width shouldn't be odd, so this should always be true
323                    if (i + 1 < w) {
324                        CRGBA(pout, *py, r_off, g_off, b_off);
325                        pout += bpp;
326                        py++;
327                    }
328
329                    if (pout2) {
330                        CRGBA(pout2, *py2, r_off, g_off, b_off);
331                        pout2 += bpp;
332                        py2++;
333
334                        // Width shouldn't be odd, so this should always be true
335                        if (i + 1 < w) {
336                            CRGBA(pout2, *py2, r_off, g_off, b_off);
337                            pout2 += bpp;
338                            py2++;
339                        }
340                    }
341
342                    pu++;
343                    pv++;
344                }
345                break;
346            case SkBitmap::kRGB_565_Config:
347                for (i = 0; i < w; i += 2) {
348                    // U and V are common for up to 4 pixels
349                    const int r_off = VP8kVToR[*pv];
350                    const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
351                    const int b_off = VP8kUToB[*pu];
352
353                    CRGB565(pout, *py, r_off, g_off, b_off);
354                    pout += bpp;
355                    py++;
356
357                    // Width shouldn't be odd, so this should always be true
358                    if (i + 1 < w) {
359                        CRGB565(pout, *py, r_off, g_off, b_off);
360                        pout += bpp;
361                        py++;
362                    }
363
364                    if (pout2) {
365                        CRGB565(pout2, *py2, r_off, g_off, b_off);
366                        pout2 += bpp;
367                        py2++;
368
369                        // Width shouldn't be odd, so this should always be true
370                        if (i + 1 < w) {
371                            CRGB565(pout2, *py2, r_off, g_off, b_off);
372                            pout2 += bpp;
373                            py2++;
374                        }
375                    }
376
377                    pu++;
378                    pv++;
379                }
380                break;
381            case SkBitmap::kARGB_4444_Config:
382                for (i = 0; i < w; i += 2) {
383                    // U and V are common for up to 4 pixels
384                    const int r_off = VP8kVToR[*pv];
385                    const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
386                    const int b_off = VP8kUToB[*pu];
387
388                    CRGBA4444(pout, *py, r_off, g_off, b_off);
389                    pout += bpp;
390                    py++;
391
392                    // Width shouldn't be odd, so this should always be true
393                    if (i + 1 < w) {
394                        CRGBA4444(pout, *py, r_off, g_off, b_off);
395                        pout += bpp;
396                        py++;
397                    }
398
399                    if (pout2) {
400                        CRGBA4444(pout2, *py2, r_off, g_off, b_off);
401                        pout2 += bpp;
402                        py2++;
403
404                        // Width shouldn't be odd, so this should always be true
405                        if (i + 1 < w) {
406                            CRGBA4444(pout2, *py2, r_off, g_off, b_off);
407                            pout2 += bpp;
408                            py2++;
409                        }
410                    }
411
412                    pu++;
413                    pv++;
414                }
415                break;
416            default:
417                // Unsupported config (can't happen, but prevents compiler warning)
418                SkASSERT(0);
419                break;
420        }
421
422        if (y2) {
423            // Scanned and populated two rows
424            y += ystride2;
425            y2 += ystride2;
426            j += 2;
427        } else {
428            // Skip to next row
429            y += io->y_stride;
430            j++;
431        }
432
433        u += io->uv_stride;
434        v += io->uv_stride;
435    }
436
437    return;
438}
439
440static int block_setup(VP8Io* io) {
441    yuv_init();
442    return 1;
443}
444
445static void block_teardown(const VP8Io* io) {
446}
447
448bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap, Mode mode) {
449#ifdef TIME_DECODE
450    AutoTimeMillis atm("WEBP Decode");
451#endif
452
453    // libwebp doesn't provide a way to override all I/O with a custom
454    // implementation. For initial implementation, let's go the "dirty"
455    // way, by loading image file content in memory before decoding it
456    int origWidth, origHeight;
457    size_t len;
458
459    bool hasAlpha = false;
460
461    uint32_t contentSize;
462    unsigned char buffer[VP8_HEADER_SIZE];
463    unsigned char *input;
464
465    // Check header
466    contentSize = webp_parse_header(stream);
467    if (contentSize <= VP8_HEADER_SIZE) {
468        return false;
469    }
470
471    //* Extract information
472    len = stream->read(buffer, VP8_HEADER_SIZE);
473    if (len != VP8_HEADER_SIZE) {
474        return false;
475    }
476
477    // check signature
478    if (buffer[3] != 0x9d || buffer[4] != 0x01 || buffer[5] != 0x2a) {
479        return false;
480    }
481
482    const uint32_t bits = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16);
483    const int key_frame = !(bits & 1);
484
485    origWidth = ((buffer[7] << 8) | buffer[6]) & 0x3fff;
486    origHeight = ((buffer[9] << 8) | buffer[8]) & 0x3fff;
487
488    if (origWidth <= 0 || origHeight <= 0) {
489        return false;
490    }
491
492    if (!key_frame) {
493        // Not a keyframe
494        return false;
495    }
496
497    if (((bits >> 1) & 7) > 3) {
498        // unknown profile
499        return false;
500    }
501    if (!((bits >> 4) & 1)) {
502        // first frame is invisible
503        return false;
504    }
505    if (((bits >> 5)) >= contentSize) {
506        // partition_length inconsistent size information
507        return false;
508    }
509
510    SkBitmap::Config config;
511    config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
512
513    // only accept prefConfig if it makes sense for us. YUV converter
514    // supports output in RGB565, RGBA4444 and RGBA8888 formats.
515    if (hasAlpha) {
516        if (config != SkBitmap::kARGB_4444_Config) {
517            config = SkBitmap::kARGB_8888_Config;
518        }
519    } else {
520        if (config != SkBitmap::kRGB_565_Config && config != SkBitmap::kARGB_4444_Config) {
521            config = SkBitmap::kARGB_8888_Config;
522        }
523    }
524
525    // sanity check for size
526    {
527        Sk64 size;
528        size.setMul(origWidth, origHeight);
529        if (size.isNeg() || !size.is32()) {
530            return false;
531        }
532        // now check that if we are 4-bytes per pixel, we also don't overflow
533        if (size.get32() > (0x7FFFFFFF >> 2)) {
534            return false;
535        }
536    }
537
538    if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
539        return false;
540    }
541
542    // TODO: may add support for sampler, to load previeww/thumbnails faster
543    // Note that, as documented, an image decoder may decide to ignore sample hint from requested
544    // config, so this implementation is still valid and safe even without handling it at all. Several
545    // other Skia image decoders just ignore this optional feature as well.
546#if 0
547    SkScaledBitmapSampler sampler(origWidth, origHeight, getSampleSize());
548    decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0);
549#else
550    decodedBitmap->setConfig(config, origWidth, origHeight, 0);
551#endif
552
553    // If only bounds are requested, done
554    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
555        return true;
556    }
557
558    // Current WEBP specification has no support for alpha layer.
559    decodedBitmap->setIsOpaque(true);
560
561    if (!this->allocPixelRef(decodedBitmap, NULL)) {
562        return return_false(*decodedBitmap, "allocPixelRef");
563    }
564    SkAutoLockPixels alp(*decodedBitmap);
565
566    // libwebp doesn't provide a way to override all I/O with a custom
567    // implementation. For initial implementation, let's go the "dirty"
568    // way, by loading image file content (actually only VP8 chunk) into
569    // memory before decoding it */
570    SkAutoMalloc srcStorage(contentSize);
571    input = (uint8_t*) srcStorage.get();
572    if (input == NULL) {
573        return return_false(*decodedBitmap, "failed to allocate read buffer");
574    }
575
576    len = stream->read(input + VP8_HEADER_SIZE, contentSize - VP8_HEADER_SIZE);
577#ifdef WEBPCONV_MISSING_PADDING
578    // Some early (yet widely spread) version of webpconv utility
579    // had a bug causing mandatory padding byte to not be written to
580    // file when content size was odd, while total size was reporting
581    // actual file size correctly. Since many webp around may have been
582    // generated with this version of webpconv, work around this issue
583    // by adding padding here. */
584    // TODO: remove this whenever work-around may be considered obsolete
585    if (len == contentSize - VP8_HEADER_SIZE - 1) {
586        input[VP8_HEADER_SIZE + len] = 0;
587        len++;
588    }
589#endif
590    if (len != contentSize - VP8_HEADER_SIZE) {
591        return false;
592    }
593    memcpy(input, buffer, VP8_HEADER_SIZE);
594
595    WEBPImage pSrc;
596    VP8Decoder* dec;
597    VP8Io io;
598
599    // Custom Put callback need reference to target image
600    pSrc.image = decodedBitmap;
601
602    // Keep reference to input stream, in case we find a way to not preload stream
603    // content in memory. So far, stream content has already been consumed, and this
604    // won't be used, but this is left for future usage.
605    pSrc.stream = stream;
606
607    dec = VP8New();
608    if (dec == NULL) {
609        return false;
610    }
611
612    VP8InitIo(&io);
613    io.data = input;
614    io.data_size = contentSize;
615
616    io.opaque = (void*) &pSrc;
617    io.put = block_put;
618    io.setup = block_setup;
619    io.teardown = block_teardown;
620
621    if (!VP8GetHeaders(dec, &io)) {
622        VP8Delete(dec);
623        return false;
624    }
625
626    if (!VP8Decode(dec, &io)) {
627        VP8Delete(dec);
628        return false;
629    }
630
631    VP8Delete(dec);
632
633    // SkDebugf("------------------- bm2 size %d [%d %d] %d\n",
634    //          bm->getSize(), bm->width(), bm->height(), bm->config());
635    return true;
636}
637
638///////////////////////////////////////////////////////////////////////////////
639
640#include "SkTRegistry.h"
641
642static SkImageDecoder* DFactory(SkStream* stream) {
643    if (webp_parse_header(stream) <= 0) {
644        return NULL;
645    }
646
647    // Magic matches, call decoder
648    return SkNEW(SkWEBPImageDecoder);
649}
650
651SkImageDecoder* sk_libwebp_dfactory(SkStream* stream) {
652    return DFactory(stream);
653}
654
655static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
656