tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
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 //------------------------------------------------------------------------------