Home | History | Annotate | Download | only in decoder
      1 /*
      2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
      3  *
      4  * This source code is subject to the terms of the BSD 2 Clause License and
      5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      6  * was not distributed with this source code in the LICENSE file, you can
      7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
      8  * Media Patent License 1.0 was not distributed with this source code in the
      9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     10  */
     11 
     12 #include <assert.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #include "aom/aom_integer.h"
     18 #include "av1/decoder/accounting.h"
     19 
     20 static int aom_accounting_hash(const char *str) {
     21   uint32_t val;
     22   const unsigned char *ustr;
     23   val = 0;
     24   ustr = (const unsigned char *)str;
     25   /* This is about the worst hash one can design, but it should be good enough
     26      here. */
     27   while (*ustr) val += *ustr++;
     28   return val % AOM_ACCOUNTING_HASH_SIZE;
     29 }
     30 
     31 /* Dictionary lookup based on an open-addressing hash table. */
     32 int aom_accounting_dictionary_lookup(Accounting *accounting, const char *str) {
     33   int hash;
     34   size_t len;
     35   AccountingDictionary *dictionary;
     36   dictionary = &accounting->syms.dictionary;
     37   hash = aom_accounting_hash(str);
     38   while (accounting->hash_dictionary[hash] != -1) {
     39     if (strcmp(dictionary->strs[accounting->hash_dictionary[hash]], str) == 0) {
     40       return accounting->hash_dictionary[hash];
     41     }
     42     hash++;
     43     if (hash == AOM_ACCOUNTING_HASH_SIZE) hash = 0;
     44   }
     45   /* No match found. */
     46   assert(dictionary->num_strs + 1 < MAX_SYMBOL_TYPES);
     47   accounting->hash_dictionary[hash] = dictionary->num_strs;
     48   len = strlen(str);
     49   dictionary->strs[dictionary->num_strs] = malloc(len + 1);
     50   snprintf(dictionary->strs[dictionary->num_strs], len + 1, "%s", str);
     51   dictionary->num_strs++;
     52   return dictionary->num_strs - 1;
     53 }
     54 
     55 void aom_accounting_init(Accounting *accounting) {
     56   int i;
     57   accounting->num_syms_allocated = 1000;
     58   accounting->syms.syms =
     59       malloc(sizeof(AccountingSymbol) * accounting->num_syms_allocated);
     60   accounting->syms.dictionary.num_strs = 0;
     61   assert(AOM_ACCOUNTING_HASH_SIZE > 2 * MAX_SYMBOL_TYPES);
     62   for (i = 0; i < AOM_ACCOUNTING_HASH_SIZE; i++)
     63     accounting->hash_dictionary[i] = -1;
     64   aom_accounting_reset(accounting);
     65 }
     66 
     67 void aom_accounting_reset(Accounting *accounting) {
     68   accounting->syms.num_syms = 0;
     69   accounting->syms.num_binary_syms = 0;
     70   accounting->syms.num_multi_syms = 0;
     71   accounting->context.x = -1;
     72   accounting->context.y = -1;
     73   accounting->last_tell_frac = 0;
     74 }
     75 
     76 void aom_accounting_clear(Accounting *accounting) {
     77   int i;
     78   AccountingDictionary *dictionary;
     79   free(accounting->syms.syms);
     80   dictionary = &accounting->syms.dictionary;
     81   for (i = 0; i < dictionary->num_strs; i++) {
     82     free(dictionary->strs[i]);
     83   }
     84 }
     85 
     86 void aom_accounting_set_context(Accounting *accounting, int16_t x, int16_t y) {
     87   accounting->context.x = x;
     88   accounting->context.y = y;
     89 }
     90 
     91 void aom_accounting_record(Accounting *accounting, const char *str,
     92                            uint32_t bits) {
     93   AccountingSymbol sym;
     94   // Reuse previous symbol if it has the same context and symbol id.
     95   if (accounting->syms.num_syms) {
     96     AccountingSymbol *last_sym;
     97     last_sym = &accounting->syms.syms[accounting->syms.num_syms - 1];
     98     if (memcmp(&last_sym->context, &accounting->context,
     99                sizeof(AccountingSymbolContext)) == 0) {
    100       uint32_t id;
    101       id = aom_accounting_dictionary_lookup(accounting, str);
    102       if (id == last_sym->id) {
    103         last_sym->bits += bits;
    104         last_sym->samples++;
    105         return;
    106       }
    107     }
    108   }
    109   sym.context = accounting->context;
    110   sym.samples = 1;
    111   sym.bits = bits;
    112   sym.id = aom_accounting_dictionary_lookup(accounting, str);
    113   assert(sym.id <= 255);
    114   if (accounting->syms.num_syms == accounting->num_syms_allocated) {
    115     accounting->num_syms_allocated *= 2;
    116     accounting->syms.syms =
    117         realloc(accounting->syms.syms,
    118                 sizeof(AccountingSymbol) * accounting->num_syms_allocated);
    119     assert(accounting->syms.syms != NULL);
    120   }
    121   accounting->syms.syms[accounting->syms.num_syms++] = sym;
    122 }
    123 
    124 void aom_accounting_dump(Accounting *accounting) {
    125   int i;
    126   AccountingSymbol *sym;
    127   printf("\n----- Number of recorded syntax elements = %d -----\n",
    128          accounting->syms.num_syms);
    129   printf("----- Total number of symbol calls = %d (%d binary) -----\n",
    130          accounting->syms.num_multi_syms + accounting->syms.num_binary_syms,
    131          accounting->syms.num_binary_syms);
    132   for (i = 0; i < accounting->syms.num_syms; i++) {
    133     sym = &accounting->syms.syms[i];
    134     printf("%s x: %d, y: %d bits: %f samples: %d\n",
    135            accounting->syms.dictionary.strs[sym->id], sym->context.x,
    136            sym->context.y, (float)sym->bits / 8.0, sym->samples);
    137   }
    138 }
    139