| /* |
| * Copyright (c) 2021, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 3-Clause Clear License |
| * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
| * License was not distributed with this source code in the LICENSE file, you |
| * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the |
| * Alliance for Open Media Patent License 1.0 was not distributed with this |
| * source code in the PATENTS file, you can obtain it at |
| * aomedia.org/license/patent-license/. |
| */ |
| |
| #include "third_party/googletest/src/googletest/include/gtest/gtest.h" |
| |
| #include <cstdlib> |
| |
| #include "aom_dsp/entenc.h" |
| #include "aom_dsp/entdec.h" |
| |
| TEST(EC_TEST, random_ec_test_Large) { |
| od_ec_enc enc; |
| od_ec_dec dec; |
| int sz; |
| int i; |
| int ret; |
| unsigned int seed; |
| unsigned char *ptr; |
| uint32_t ptr_sz; |
| char *seed_str; |
| ret = 0; |
| seed_str = getenv("EC_TEST_SEED"); |
| if (seed_str) { |
| seed = atoi(seed_str); |
| } else { |
| seed = 0xdaa1a; |
| } |
| srand(seed); |
| od_ec_enc_init(&enc, 1); |
| /*Test compatibility between multiple different encode/decode routines.*/ |
| for (i = 0; i < 409600; i++) { |
| unsigned *fz; |
| unsigned *fts; |
| unsigned *data; |
| #if CONFIG_BYPASS_IMPROVEMENT |
| unsigned *mode; |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| unsigned *tell; |
| unsigned *enc_method; |
| int j; |
| sz = rand() / ((RAND_MAX >> (rand() % 9U)) + 1U); |
| fz = (unsigned *)malloc(sz * sizeof(*fz)); |
| fts = (unsigned *)malloc(sz * sizeof(*fts)); |
| data = (unsigned *)malloc(sz * sizeof(*data)); |
| #if CONFIG_BYPASS_IMPROVEMENT |
| mode = (unsigned *)malloc(sz * sizeof(*mode)); |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| tell = (unsigned *)malloc((sz + 1) * sizeof(*tell)); |
| enc_method = (unsigned *)malloc(sz * sizeof(*enc_method)); |
| od_ec_enc_reset(&enc); |
| tell[0] = od_ec_enc_tell_frac(&enc); |
| for (j = 0; j < sz; j++) { |
| #if CONFIG_BYPASS_IMPROVEMENT |
| data[j] = rand(); |
| mode[j] = rand(); |
| #else |
| data[j] = rand() / ((RAND_MAX >> 1) + 1); |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| |
| fts[j] = CDF_PROB_BITS; |
| fz[j] = (rand() % (CDF_PROB_TOP - 2)) >> (CDF_PROB_BITS - fts[j]); |
| #if CONFIG_BYPASS_IMPROVEMENT |
| fz[j] = OD_MAXI(fz[j] & ~1, 2); |
| enc_method[j] = 1 + (rand() & 3); |
| #else |
| fz[j] = OD_MAXI(fz[j], 1); |
| enc_method[j] = 3 + (rand() & 1); |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| switch (enc_method[j]) { |
| #if CONFIG_BYPASS_IMPROVEMENT |
| case 1: { |
| // Write literal in smaller pieces; read back in single call. |
| int bits = (mode[j] & 7) + 1; |
| data[j] &= ((1 << bits) - 1); |
| int chunk = ((mode[j] >> 4) & 7) + 1; |
| int d = data[j]; |
| while (bits > 0) { |
| int n = bits > chunk ? chunk : bits; |
| od_ec_encode_literal_bypass(&enc, (d >> (bits - n)), n); |
| bits -= n; |
| d &= ((1 << bits) - 1); |
| } |
| break; |
| } |
| case 2: { |
| // Write literal in single call; read back in smaller pieces. |
| int bits = (mode[j] & 7) + 1; |
| data[j] &= ((1 << bits) - 1); |
| od_ec_encode_literal_bypass(&enc, data[j], bits); |
| break; |
| } |
| case 3: { |
| data[j] &= 1; |
| od_ec_encode_bool_bypass(&enc, data[j]); |
| break; |
| } |
| case 4: { |
| data[j] &= 1; |
| uint16_t cdf[2]; |
| cdf[0] = OD_ICDF(fz[j]); |
| cdf[1] = OD_ICDF(1U << fts[j]); |
| od_ec_encode_cdf_q15(&enc, data[j], cdf, 2); |
| break; |
| } |
| #else |
| case 3: { |
| od_ec_encode_bool_q15(&enc, data[j], |
| OD_ICDF(fz[j] << (CDF_PROB_BITS - fts[j]))); |
| break; |
| } |
| case 4: { |
| uint16_t cdf[2]; |
| cdf[0] = OD_ICDF(fz[j]); |
| cdf[1] = OD_ICDF(1U << fts[j]); |
| od_ec_encode_cdf_q15(&enc, data[j], cdf, 2); |
| break; |
| } |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| } |
| |
| tell[j + 1] = od_ec_enc_tell_frac(&enc); |
| } |
| ptr = od_ec_enc_done(&enc, &ptr_sz); |
| EXPECT_GE(((od_ec_enc_tell(&enc) + 7U) >> 3), ptr_sz) |
| << "od_ec_enc_tell() lied: " |
| "there's " |
| << ptr_sz << " bytes instead of " << ((od_ec_enc_tell(&enc) + 7) >> 3) |
| << " (Random seed: " << seed << ")\n"; |
| od_ec_dec_init(&dec, ptr, ptr_sz); |
| EXPECT_EQ(od_ec_dec_tell_frac(&dec), tell[0]) |
| << "od_ec_dec_tell() mismatch between encoder and decoder " |
| "at symbol 0: " |
| << (unsigned)od_ec_dec_tell_frac(&dec) << " instead of " << tell[0] |
| << " (Random seed: " << seed << ").\n"; |
| for (j = 0; j < sz; j++) { |
| int dec_method; |
| unsigned int sym = data[j] + 1; // Initialize sym to an invalid value. |
| |
| #if CONFIG_BYPASS_IMPROVEMENT |
| dec_method = enc_method[j]; |
| switch (dec_method) { |
| case 1: { |
| int bits = (mode[j] & 7) + 1; |
| sym = od_ec_decode_literal_bypass(&dec, bits); |
| break; |
| } |
| case 2: { |
| int bits = (mode[j] & 7) + 1; |
| int chunk = ((mode[j] >> 4) & 7) + 1; |
| sym = 0; |
| while (bits > 0) { |
| int n = bits > chunk ? chunk : bits; |
| sym <<= n; |
| sym += od_ec_decode_literal_bypass(&dec, n); |
| bits -= n; |
| } |
| break; |
| } |
| case 3: { |
| sym = od_ec_decode_bool_bypass(&dec); |
| break; |
| } |
| case 4: { |
| uint16_t cdf[2]; |
| cdf[0] = OD_ICDF(fz[j]); |
| cdf[1] = OD_ICDF(1U << fts[j]); |
| sym = od_ec_decode_cdf_q15(&dec, cdf, 2); |
| break; |
| } |
| } |
| #else |
| if (CDF_SHIFT == 0) { |
| dec_method = 3 + (rand() & 1); |
| } else { |
| dec_method = enc_method[j]; |
| } |
| switch (dec_method) { |
| case 3: { |
| sym = od_ec_decode_bool_q15( |
| &dec, OD_ICDF(fz[j] << (CDF_PROB_BITS - fts[j]))); |
| break; |
| } |
| case 4: { |
| uint16_t cdf[2]; |
| cdf[0] = OD_ICDF(fz[j]); |
| cdf[1] = OD_ICDF(1U << fts[j]); |
| sym = od_ec_decode_cdf_q15(&dec, cdf, 2); |
| break; |
| } |
| } |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| |
| EXPECT_EQ(sym, data[j]) |
| << "Decoded " << sym << " instead of " << data[j] |
| << " with fz=" << fz[j] << " and ftb=" << fts[j] << "at position " |
| << j << " of " << sz << " (Random seed: " << seed << ").\n" |
| << "Encoding method: " << enc_method[j] |
| << " decoding method: " << dec_method << "\n"; |
| EXPECT_EQ(od_ec_dec_tell_frac(&dec), tell[j + 1]) |
| << "od_ec_dec_tell() mismatch between encoder and " |
| "decoder at symbol " |
| << j + 1 << ": " << (unsigned)od_ec_dec_tell_frac(&dec) |
| << " instead of " << tell[j + 1] << " (Random seed: " << seed |
| << ").\n"; |
| } |
| free(enc_method); |
| free(tell); |
| #if CONFIG_BYPASS_IMPROVEMENT |
| free(mode); |
| #endif // CONFIG_BYPASS_IMPROVEMENT |
| free(data); |
| free(fts); |
| free(fz); |
| } |
| od_ec_enc_reset(&enc); |
| if (CDF_SHIFT == 0) { |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(24576)); |
| od_ec_enc_patch_initial_bits(&enc, 3, 2); |
| EXPECT_FALSE(enc.error) << "od_ec_enc_patch_initial_bits() failed.\n"; |
| od_ec_enc_patch_initial_bits(&enc, 0, 5); |
| EXPECT_TRUE(enc.error) |
| << "od_ec_enc_patch_initial_bits() didn't fail when it should have.\n"; |
| od_ec_enc_reset(&enc); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384)); |
| od_ec_encode_bool_q15(&enc, 1, OD_ICDF(32256)); |
| od_ec_encode_bool_q15(&enc, 0, OD_ICDF(24576)); |
| od_ec_enc_patch_initial_bits(&enc, 0, 2); |
| EXPECT_FALSE(enc.error) << "od_ec_enc_patch_initial_bits() failed.\n"; |
| ptr = od_ec_enc_done(&enc, &ptr_sz); |
| EXPECT_EQ(ptr_sz, 2u); |
| EXPECT_EQ(ptr[0], 63) |
| << "Got " << ptr[0] |
| << " when expecting 63 for od_ec_enc_patch_initial_bits().\n"; |
| } |
| od_ec_enc_clear(&enc); |
| EXPECT_EQ(ret, 0); |
| } |