#include "extras/extras.h"
#include "webp/decode.h"
#include <math.h>
#define INVALID_BIT_POS (1ull << 63)
static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb,
uint64_t max_size, uint64_t* const bit_pos) {
uint32_t val = 0;
if (*bit_pos + nb <= 8 * max_size) {
while (nb-- > 0) {
const uint64_t p = (*bit_pos)++;
const int bit = !!(data[p >> 3] & (128 >> ((p & 7))));
val = (val << 1) | bit;
}
} else {
*bit_pos = INVALID_BIT_POS;
}
return val;
}
#define GET_BIT(n) GetBit(data, (n), size, &bit_pos)
#define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0)
int VP8EstimateQuality(const uint8_t* const data, size_t size) {
size_t pos = 0;
uint64_t bit_pos;
uint64_t sig = 0x00;
int ok = 0;
int Q = -1;
WebPBitstreamFeatures features;
if (data == NULL) return -1;
if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) {
return -1; }
if (features.format == 2) return 101; if (features.format == 0 || features.has_animation) return -1;
while (pos < size) {
sig = (sig >> 8) | ((uint64_t)data[pos++] << 40);
if ((sig >> 24) == 0x2a019dull) {
ok = 1;
break;
}
}
if (!ok) return -1;
if (pos + 4 > size) return -1;
pos += 4;
bit_pos = pos * 8;
GET_BIT(2);
if (GET_BIT(1)) { int s;
const int update_map = GET_BIT(1);
if (GET_BIT(1)) { const int absolute_delta = GET_BIT(1);
int q[4] = { 0, 0, 0, 0 };
for (s = 0; s < 4; ++s) {
if (GET_BIT(1)) {
q[s] = GET_BIT(7);
if (GET_BIT(1)) q[s] = -q[s]; }
}
if (absolute_delta) Q = q[0]; for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7); }
if (update_map) {
for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8);
}
}
GET_BIT(1 + 6 + 3); if (GET_BIT(1)) { if (GET_BIT(1)) { int n;
for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6);
}
}
GET_BIT(2);
{
const int base_q = GET_BIT(7);
CONDITIONAL_SKIP(5);
CONDITIONAL_SKIP(5);
CONDITIONAL_SKIP(5);
CONDITIONAL_SKIP(5);
CONDITIONAL_SKIP(5);
if (Q < 0) Q = base_q;
}
if (bit_pos == INVALID_BIT_POS) return -1;
Q = (127 - Q) * 100 / 127;
if (Q < 80) {
Q = (int)(pow(Q / 80., 1. / 0.38) * 80);
}
return Q;
}