go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

picture_enc.c (9365B)


      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 <limits.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #include "src/enc/vp8i_enc.h"
     20 #include "src/utils/utils.h"
     21 #include "src/webp/encode.h"
     22 #include "src/webp/types.h"
     23 
     24 //------------------------------------------------------------------------------
     25 // WebPPicture
     26 //------------------------------------------------------------------------------
     27 
     28 static int DummyWriter(const uint8_t* data, size_t data_size,
     29                        const WebPPicture* const picture) {
     30   // The following are to prevent 'unused variable' error message.
     31   (void)data;
     32   (void)data_size;
     33   (void)picture;
     34   return 1;
     35 }
     36 
     37 int WebPPictureInitInternal(WebPPicture* picture, int version) {
     38   if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
     39     return 0;   // caller/system version mismatch!
     40   }
     41   if (picture != NULL) {
     42     memset(picture, 0, sizeof(*picture));
     43     picture->writer = DummyWriter;
     44     WebPEncodingSetError(picture, VP8_ENC_OK);
     45   }
     46   return 1;
     47 }
     48 
     49 //------------------------------------------------------------------------------
     50 
     51 int WebPValidatePicture(const WebPPicture* const picture) {
     52   if (picture == NULL) return 0;
     53   if (picture->width <= 0 || picture->height <= 0) {
     54     return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
     55   }
     56   if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||
     57       picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {
     58     return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
     59   }
     60   if (picture->colorspace != WEBP_YUV420 &&
     61       picture->colorspace != WEBP_YUV420A) {
     62     return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
     63   }
     64   return 1;
     65 }
     66 
     67 static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
     68   picture->memory_argb_ = NULL;
     69   picture->argb = NULL;
     70   picture->argb_stride = 0;
     71 }
     72 
     73 static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {
     74   picture->memory_ = NULL;
     75   picture->y = picture->u = picture->v = picture->a = NULL;
     76   picture->y_stride = picture->uv_stride = 0;
     77   picture->a_stride = 0;
     78 }
     79 
     80 void WebPPictureResetBuffers(WebPPicture* const picture) {
     81   WebPPictureResetBufferARGB(picture);
     82   WebPPictureResetBufferYUVA(picture);
     83 }
     84 
     85 int WebPPictureAllocARGB(WebPPicture* const picture) {
     86   void* memory;
     87   const int width = picture->width;
     88   const int height = picture->height;
     89   const uint64_t argb_size = (uint64_t)width * height;
     90 
     91   if (!WebPValidatePicture(picture)) return 0;
     92 
     93   WebPSafeFree(picture->memory_argb_);
     94   WebPPictureResetBufferARGB(picture);
     95 
     96   // allocate a new buffer.
     97   memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));
     98   if (memory == NULL) {
     99     return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
    100   }
    101   picture->memory_argb_ = memory;
    102   picture->argb = (uint32_t*)WEBP_ALIGN(memory);
    103   picture->argb_stride = width;
    104   return 1;
    105 }
    106 
    107 int WebPPictureAllocYUVA(WebPPicture* const picture) {
    108   const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;
    109   const int width = picture->width;
    110   const int height = picture->height;
    111   const int y_stride = width;
    112   const int uv_width = (int)(((int64_t)width + 1) >> 1);
    113   const int uv_height = (int)(((int64_t)height + 1) >> 1);
    114   const int uv_stride = uv_width;
    115   int a_width, a_stride;
    116   uint64_t y_size, uv_size, a_size, total_size;
    117   uint8_t* mem;
    118 
    119   if (!WebPValidatePicture(picture)) return 0;
    120 
    121   WebPSafeFree(picture->memory_);
    122   WebPPictureResetBufferYUVA(picture);
    123 
    124   // alpha
    125   a_width = has_alpha ? width : 0;
    126   a_stride = a_width;
    127   y_size = (uint64_t)y_stride * height;
    128   uv_size = (uint64_t)uv_stride * uv_height;
    129   a_size =  (uint64_t)a_stride * height;
    130 
    131   total_size = y_size + a_size + 2 * uv_size;
    132 
    133   // Security and validation checks
    134   if (width <= 0 || height <= 0 ||           // luma/alpha param error
    135       uv_width <= 0 || uv_height <= 0) {     // u/v param error
    136     return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
    137   }
    138   // allocate a new buffer.
    139   mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
    140   if (mem == NULL) {
    141     return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
    142   }
    143 
    144   // From now on, we're in the clear, we can no longer fail...
    145   picture->memory_ = (void*)mem;
    146   picture->y_stride  = y_stride;
    147   picture->uv_stride = uv_stride;
    148   picture->a_stride  = a_stride;
    149 
    150   // TODO(skal): we could align the y/u/v planes and adjust stride.
    151   picture->y = mem;
    152   mem += y_size;
    153 
    154   picture->u = mem;
    155   mem += uv_size;
    156   picture->v = mem;
    157   mem += uv_size;
    158 
    159   if (a_size > 0) {
    160     picture->a = mem;
    161     mem += a_size;
    162   }
    163   (void)mem;  // makes the static analyzer happy
    164   return 1;
    165 }
    166 
    167 int WebPPictureAlloc(WebPPicture* picture) {
    168   if (picture != NULL) {
    169     WebPPictureFree(picture);   // erase previous buffer
    170 
    171     if (!picture->use_argb) {
    172       return WebPPictureAllocYUVA(picture);
    173     } else {
    174       return WebPPictureAllocARGB(picture);
    175     }
    176   }
    177   return 1;
    178 }
    179 
    180 void WebPPictureFree(WebPPicture* picture) {
    181   if (picture != NULL) {
    182     WebPSafeFree(picture->memory_);
    183     WebPSafeFree(picture->memory_argb_);
    184     WebPPictureResetBuffers(picture);
    185   }
    186 }
    187 
    188 //------------------------------------------------------------------------------
    189 // WebPMemoryWriter: Write-to-memory
    190 
    191 void WebPMemoryWriterInit(WebPMemoryWriter* writer) {
    192   writer->mem = NULL;
    193   writer->size = 0;
    194   writer->max_size = 0;
    195 }
    196 
    197 int WebPMemoryWrite(const uint8_t* data, size_t data_size,
    198                     const WebPPicture* picture) {
    199   WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;
    200   uint64_t next_size;
    201   if (w == NULL) {
    202     return 1;
    203   }
    204   next_size = (uint64_t)w->size + data_size;
    205   if (next_size > w->max_size) {
    206     uint8_t* new_mem;
    207     uint64_t next_max_size = 2ULL * w->max_size;
    208     if (next_max_size < next_size) next_max_size = next_size;
    209     if (next_max_size < 8192ULL) next_max_size = 8192ULL;
    210     new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);
    211     if (new_mem == NULL) {
    212       return 0;
    213     }
    214     if (w->size > 0) {
    215       memcpy(new_mem, w->mem, w->size);
    216     }
    217     WebPSafeFree(w->mem);
    218     w->mem = new_mem;
    219     // down-cast is ok, thanks to WebPSafeMalloc
    220     w->max_size = (size_t)next_max_size;
    221   }
    222   if (data_size > 0) {
    223     memcpy(w->mem + w->size, data, data_size);
    224     w->size += data_size;
    225   }
    226   return 1;
    227 }
    228 
    229 void WebPMemoryWriterClear(WebPMemoryWriter* writer) {
    230   if (writer != NULL) {
    231     WebPSafeFree(writer->mem);
    232     WebPMemoryWriterInit(writer);
    233   }
    234 }
    235 
    236 //------------------------------------------------------------------------------
    237 // Simplest high-level calls:
    238 
    239 typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
    240 
    241 static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
    242                      Importer import, float quality_factor, int lossless,
    243                      uint8_t** output) {
    244   WebPPicture pic;
    245   WebPConfig config;
    246   WebPMemoryWriter wrt;
    247   int ok;
    248 
    249   if (output == NULL) return 0;
    250 
    251   if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||
    252       !WebPPictureInit(&pic)) {
    253     return 0;  // shouldn't happen, except if system installation is broken
    254   }
    255 
    256   config.lossless = !!lossless;
    257   pic.use_argb = !!lossless;
    258   pic.width = width;
    259   pic.height = height;
    260   pic.writer = WebPMemoryWrite;
    261   pic.custom_ptr = &wrt;
    262   WebPMemoryWriterInit(&wrt);
    263 
    264   ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
    265   WebPPictureFree(&pic);
    266   if (!ok) {
    267     WebPMemoryWriterClear(&wrt);
    268     *output = NULL;
    269     return 0;
    270   }
    271   *output = wrt.mem;
    272   return wrt.size;
    273 }
    274 
    275 #define ENCODE_FUNC(NAME, IMPORTER)                                     \
    276 size_t NAME(const uint8_t* in, int w, int h, int bps, float q,          \
    277             uint8_t** out) {                                            \
    278   return Encode(in, w, h, bps, IMPORTER, q, 0, out);                    \
    279 }
    280 
    281 ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)
    282 ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)
    283 #if !defined(WEBP_REDUCE_CSP)
    284 ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)
    285 ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)
    286 #endif  // WEBP_REDUCE_CSP
    287 
    288 #undef ENCODE_FUNC
    289 
    290 #define LOSSLESS_DEFAULT_QUALITY 70.
    291 #define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER)                                 \
    292 size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) {       \
    293   return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out);  \
    294 }
    295 
    296 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)
    297 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)
    298 #if !defined(WEBP_REDUCE_CSP)
    299 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)
    300 LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
    301 #endif  // WEBP_REDUCE_CSP
    302 
    303 #undef LOSSLESS_ENCODE_FUNC
    304 
    305 //------------------------------------------------------------------------------