go-libwebp

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

quality_estimate.c (3886B)


      1 // Copyright 2016 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 //  VP8EstimateQuality(): rough encoding quality estimate
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include <math.h>
     15 #include <stddef.h>
     16 
     17 #include "extras/extras.h"
     18 #include "src/webp/types.h"
     19 #include "webp/decode.h"
     20 
     21 //------------------------------------------------------------------------------
     22 
     23 #define INVALID_BIT_POS (1ull << 63)
     24 
     25 // In most cases, we don't need to use a full arithmetic decoder, since
     26 // all the header's bits are written using a uniform probability of 128.
     27 // We can just parse the header as if it was bits (works in 99.999% cases).
     28 static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb,
     29                                    uint64_t max_size, uint64_t* const bit_pos) {
     30   uint32_t val = 0;
     31   if (*bit_pos + nb <= 8 * max_size) {
     32     while (nb-- > 0) {
     33       const uint64_t p = (*bit_pos)++;
     34       const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
     35       val = (val << 1) | bit;
     36     }
     37   } else {
     38     *bit_pos = INVALID_BIT_POS;
     39   }
     40   return val;
     41 }
     42 
     43 #define GET_BIT(n) GetBit(data, (n), size, &bit_pos)
     44 #define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0)
     45 
     46 int VP8EstimateQuality(const uint8_t* const data, size_t size) {
     47   size_t pos = 0;
     48   uint64_t bit_pos;
     49   uint64_t sig = 0x00;
     50   int ok = 0;
     51   int Q = -1;
     52   WebPBitstreamFeatures features;
     53 
     54   if (data == NULL) return -1;
     55 
     56   if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) {
     57     return -1;   // invalid file
     58   }
     59   if (features.format == 2) return 101;  // lossless
     60   if (features.format == 0 || features.has_animation) return -1;   // mixed
     61 
     62   while (pos < size) {
     63     sig = (sig >> 8) | ((uint64_t)data[pos++] << 40);
     64     if ((sig >> 24) == 0x2a019dull) {
     65       ok = 1;
     66       break;
     67     }
     68   }
     69   if (!ok) return -1;
     70   if (pos + 4 > size) return -1;
     71 
     72   // Skip main Header
     73   // width  = (data[pos + 0] | (data[pos + 1] << 8)) & 0x3fff;
     74   // height = (data[pos + 2] | (data[pos + 3] << 8)) & 0x3fff;
     75   pos += 4;
     76   bit_pos = pos * 8;
     77 
     78   GET_BIT(2);  // colorspace + clamp type
     79 
     80   // Segment header
     81   if (GET_BIT(1)) {       // use_segment
     82     int s;
     83     const int update_map = GET_BIT(1);
     84     if (GET_BIT(1)) {     // update data
     85       const int absolute_delta = GET_BIT(1);
     86       int q[4]  = { 0, 0, 0, 0 };
     87       for (s = 0; s < 4; ++s) {
     88         if (GET_BIT(1)) {
     89           q[s] = GET_BIT(7);
     90           if (GET_BIT(1)) q[s] = -q[s];   // sign
     91         }
     92       }
     93       if (absolute_delta) Q = q[0];  // just use the first segment's quantizer
     94       for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7);   //  filter strength
     95     }
     96     if (update_map) {
     97       for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8);
     98     }
     99   }
    100   // Filter header
    101   GET_BIT(1 + 6 + 3);     // simple + level + sharpness
    102   if (GET_BIT(1)) {       // use_lf_delta
    103     if (GET_BIT(1)) {     // update lf_delta?
    104       int n;
    105       for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6);
    106     }
    107   }
    108   // num partitions
    109   GET_BIT(2);
    110 
    111   // ParseQuant
    112   {
    113     const int base_q = GET_BIT(7);
    114     /* dqy1_dc = */ CONDITIONAL_SKIP(5);
    115     /* dqy2_dc = */ CONDITIONAL_SKIP(5);
    116     /* dqy2_ac = */ CONDITIONAL_SKIP(5);
    117     /* dquv_dc = */ CONDITIONAL_SKIP(5);
    118     /* dquv_ac = */ CONDITIONAL_SKIP(5);
    119 
    120     if (Q < 0) Q = base_q;
    121   }
    122   if (bit_pos == INVALID_BIT_POS) return -1;
    123 
    124   // base mapping
    125   Q = (127 - Q) * 100 / 127;
    126   // correction for power-law behavior in low range
    127   if (Q < 80) {
    128     Q = (int)(pow(Q / 80., 1. / 0.38) * 80);
    129   }
    130   return Q;
    131 }