Home | History | Annotate | Download | only in dec
      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 // Alpha-plane decompression.
     11 //
     12 // Author: Skal (pascal.massimino (at) gmail.com)
     13 
     14 #include <stdlib.h>
     15 #include "./alphai_dec.h"
     16 #include "./vp8i_dec.h"
     17 #include "./vp8li_dec.h"
     18 #include "../dsp/dsp.h"
     19 #include "../utils/quant_levels_dec_utils.h"
     20 #include "../utils/utils.h"
     21 #include "../webp/format_constants.h"
     22 
     23 //------------------------------------------------------------------------------
     24 // ALPHDecoder object.
     25 
     26 // Allocates a new alpha decoder instance.
     27 static ALPHDecoder* ALPHNew(void) {
     28   ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
     29   return dec;
     30 }
     31 
     32 // Clears and deallocates an alpha decoder instance.
     33 static void ALPHDelete(ALPHDecoder* const dec) {
     34   if (dec != NULL) {
     35     VP8LDelete(dec->vp8l_dec_);
     36     dec->vp8l_dec_ = NULL;
     37     WebPSafeFree(dec);
     38   }
     39 }
     40 
     41 //------------------------------------------------------------------------------
     42 // Decoding.
     43 
     44 // Initialize alpha decoding by parsing the alpha header and decoding the image
     45 // header for alpha data stored using lossless compression.
     46 // Returns false in case of error in alpha header (data too short, invalid
     47 // compression method or filter, error in lossless header data etc).
     48 static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
     49                     size_t data_size, const VP8Io* const src_io,
     50                     uint8_t* output) {
     51   int ok = 0;
     52   const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
     53   const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
     54   int rsrv;
     55   VP8Io* const io = &dec->io_;
     56 
     57   assert(data != NULL && output != NULL && src_io != NULL);
     58 
     59   VP8FiltersInit();
     60   dec->output_ = output;
     61   dec->width_ = src_io->width;
     62   dec->height_ = src_io->height;
     63   assert(dec->width_ > 0 && dec->height_ > 0);
     64 
     65   if (data_size <= ALPHA_HEADER_LEN) {
     66     return 0;
     67   }
     68 
     69   dec->method_ = (data[0] >> 0) & 0x03;
     70   dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
     71   dec->pre_processing_ = (data[0] >> 4) & 0x03;
     72   rsrv = (data[0] >> 6) & 0x03;
     73   if (dec->method_ < ALPHA_NO_COMPRESSION ||
     74       dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
     75       dec->filter_ >= WEBP_FILTER_LAST ||
     76       dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
     77       rsrv != 0) {
     78     return 0;
     79   }
     80 
     81   // Copy the necessary parameters from src_io to io
     82   VP8InitIo(io);
     83   WebPInitCustomIo(NULL, io);
     84   io->opaque = dec;
     85   io->width = src_io->width;
     86   io->height = src_io->height;
     87 
     88   io->use_cropping = src_io->use_cropping;
     89   io->crop_left = src_io->crop_left;
     90   io->crop_right = src_io->crop_right;
     91   io->crop_top = src_io->crop_top;
     92   io->crop_bottom = src_io->crop_bottom;
     93   // No need to copy the scaling parameters.
     94 
     95   if (dec->method_ == ALPHA_NO_COMPRESSION) {
     96     const size_t alpha_decoded_size = dec->width_ * dec->height_;
     97     ok = (alpha_data_size >= alpha_decoded_size);
     98   } else {
     99     assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
    100     ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
    101   }
    102 
    103   return ok;
    104 }
    105 
    106 // Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
    107 // starting from row number 'row'. It assumes that rows up to (row - 1) have
    108 // already been decoded.
    109 // Returns false in case of bitstream error.
    110 static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
    111   ALPHDecoder* const alph_dec = dec->alph_dec_;
    112   const int width = alph_dec->width_;
    113   const int height = alph_dec->io_.crop_bottom;
    114   if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
    115     int y;
    116     const uint8_t* prev_line = dec->alpha_prev_line_;
    117     const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
    118     uint8_t* dst = dec->alpha_plane_ + row * width;
    119     assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
    120     if (alph_dec->filter_ != WEBP_FILTER_NONE) {
    121       assert(WebPUnfilters[alph_dec->filter_] != NULL);
    122       for (y = 0; y < num_rows; ++y) {
    123         WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
    124         prev_line = dst;
    125         dst += width;
    126         deltas += width;
    127       }
    128     } else {
    129       for (y = 0; y < num_rows; ++y) {
    130         memcpy(dst, deltas, width * sizeof(*dst));
    131         prev_line = dst;
    132         dst += width;
    133         deltas += width;
    134       }
    135     }
    136     dec->alpha_prev_line_ = prev_line;
    137   } else {  // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
    138     assert(alph_dec->vp8l_dec_ != NULL);
    139     if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
    140       return 0;
    141     }
    142   }
    143 
    144   if (row + num_rows >= height) {
    145     dec->is_alpha_decoded_ = 1;
    146   }
    147   return 1;
    148 }
    149 
    150 static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
    151   const int stride = io->width;
    152   const int height = io->crop_bottom;
    153   const uint64_t alpha_size = (uint64_t)stride * height;
    154   assert(dec->alpha_plane_mem_ == NULL);
    155   dec->alpha_plane_mem_ =
    156       (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
    157   if (dec->alpha_plane_mem_ == NULL) {
    158     return 0;
    159   }
    160   dec->alpha_plane_ = dec->alpha_plane_mem_;
    161   dec->alpha_prev_line_ = NULL;
    162   return 1;
    163 }
    164 
    165 void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
    166   assert(dec != NULL);
    167   WebPSafeFree(dec->alpha_plane_mem_);
    168   dec->alpha_plane_mem_ = NULL;
    169   dec->alpha_plane_ = NULL;
    170   ALPHDelete(dec->alph_dec_);
    171   dec->alph_dec_ = NULL;
    172 }
    173 
    174 //------------------------------------------------------------------------------
    175 // Main entry point.
    176 
    177 const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
    178                                       const VP8Io* const io,
    179                                       int row, int num_rows) {
    180   const int width = io->width;
    181   const int height = io->crop_bottom;
    182 
    183   assert(dec != NULL && io != NULL);
    184 
    185   if (row < 0 || num_rows <= 0 || row + num_rows > height) {
    186     return NULL;    // sanity check.
    187   }
    188 
    189   if (!dec->is_alpha_decoded_) {
    190     if (dec->alph_dec_ == NULL) {    // Initialize decoder.
    191       dec->alph_dec_ = ALPHNew();
    192       if (dec->alph_dec_ == NULL) return NULL;
    193       if (!AllocateAlphaPlane(dec, io)) goto Error;
    194       if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
    195                     io, dec->alpha_plane_)) {
    196         goto Error;
    197       }
    198       // if we allowed use of alpha dithering, check whether it's needed at all
    199       if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
    200         dec->alpha_dithering_ = 0;   // disable dithering
    201       } else {
    202         num_rows = height - row;     // decode everything in one pass
    203       }
    204     }
    205 
    206     assert(dec->alph_dec_ != NULL);
    207     assert(row + num_rows <= height);
    208     if (!ALPHDecode(dec, row, num_rows)) goto Error;
    209 
    210     if (dec->is_alpha_decoded_) {   // finished?
    211       ALPHDelete(dec->alph_dec_);
    212       dec->alph_dec_ = NULL;
    213       if (dec->alpha_dithering_ > 0) {
    214         uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width
    215                              + io->crop_left;
    216         if (!WebPDequantizeLevels(alpha,
    217                                   io->crop_right - io->crop_left,
    218                                   io->crop_bottom - io->crop_top,
    219                                   width, dec->alpha_dithering_)) {
    220           goto Error;
    221         }
    222       }
    223     }
    224   }
    225 
    226   // Return a pointer to the current decoded row.
    227   return dec->alpha_plane_ + row * width;
    228 
    229  Error:
    230   WebPDeallocateAlphaMemory(dec);
    231   return NULL;
    232 }
    233