Home | History | Annotate | Download | only in enc
      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 (at) 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 
     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 
     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 
     47 static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
     48   picture->memory_argb_ = NULL;
     49   picture->argb = NULL;
     50   picture->argb_stride = 0;
     51 }
     52 
     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 
     60 void WebPPictureResetBuffers(WebPPicture* const picture) {
     61   WebPPictureResetBufferARGB(picture);
     62   WebPPictureResetBufferYUVA(picture);
     63 }
     64 
     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 
     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 
    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 
    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 
    179 void WebPMemoryWriterInit(WebPMemoryWriter* writer) {
    180   writer->mem = NULL;
    181   writer->size = 0;
    182   writer->max_size = 0;
    183 }
    184 
    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 
    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 
    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