tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

grain_table.c (13253B)


      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 /*!\file
     13 * \brief This file has the implementation details of the grain table.
     14 *
     15 * The file format is an ascii representation for readability and
     16 * editability. Array parameters are separated from the non-array
     17 * parameters and prefixed with a few characters to make for easy
     18 * localization with a parameter set. Each entry is prefixed with "E"
     19 * and the other parameters are only specified if "update-parms" is
     20 * non-zero.
     21 *
     22 * filmgrn1
     23 * E <start-time> <end-time> <apply-grain> <random-seed> <update-parms>
     24 *  p <ar_coeff_lag> <ar_coeff_shift> <grain_scale_shift> ...
     25 *  sY <num_y_points> <point_0_x> <point_0_y> ...
     26 *  sCb <num_cb_points> <point_0_x> <point_0_y> ...
     27 *  sCr <num_cr_points> <point_0_x> <point_0_y> ...
     28 *  cY <ar_coeff_y_0> ....
     29 *  cCb <ar_coeff_cb_0> ....
     30 *  cCr <ar_coeff_cr_0> ....
     31 * E <start-time> ...
     32 */
     33 #include <string.h>
     34 #include <stdio.h>
     35 #include "aom_dsp/aom_dsp_common.h"
     36 #include "aom_dsp/grain_table.h"
     37 #include "aom_mem/aom_mem.h"
     38 
     39 static const char kFileMagic[8] = { 'f', 'i', 'l', 'm', 'g', 'r', 'n', '1' };
     40 
     41 static void grain_table_entry_read(FILE *file,
     42                                   struct aom_internal_error_info *error_info,
     43                                   aom_film_grain_table_entry_t *entry) {
     44  aom_film_grain_t *pars = &entry->params;
     45  int num_read =
     46      fscanf(file, "E %" PRId64 " %" PRId64 " %d %hd %d\n", &entry->start_time,
     47             &entry->end_time, &pars->apply_grain, &pars->random_seed,
     48             &pars->update_parameters);
     49  if (num_read == 0 && feof(file)) return;
     50  if (num_read != 5) {
     51    aom_internal_error(error_info, AOM_CODEC_ERROR,
     52                       "Unable to read entry header. Read %d != 5", num_read);
     53    return;
     54  }
     55  if (pars->update_parameters) {
     56    num_read = fscanf(file, "p %d %d %d %d %d %d %d %d %d %d %d %d\n",
     57                      &pars->ar_coeff_lag, &pars->ar_coeff_shift,
     58                      &pars->grain_scale_shift, &pars->scaling_shift,
     59                      &pars->chroma_scaling_from_luma, &pars->overlap_flag,
     60                      &pars->cb_mult, &pars->cb_luma_mult, &pars->cb_offset,
     61                      &pars->cr_mult, &pars->cr_luma_mult, &pars->cr_offset);
     62    if (num_read != 12) {
     63      aom_internal_error(error_info, AOM_CODEC_ERROR,
     64                         "Unable to read entry params. Read %d != 12",
     65                         num_read);
     66      return;
     67    }
     68    if (!fscanf(file, "\tsY %d ", &pars->num_y_points)) {
     69      aom_internal_error(error_info, AOM_CODEC_ERROR,
     70                         "Unable to read num y points");
     71      return;
     72    }
     73    for (int i = 0; i < pars->num_y_points; ++i) {
     74      if (2 != fscanf(file, "%d %d", &pars->scaling_points_y[i][0],
     75                      &pars->scaling_points_y[i][1])) {
     76        aom_internal_error(error_info, AOM_CODEC_ERROR,
     77                           "Unable to read y scaling points");
     78        return;
     79      }
     80    }
     81    if (!fscanf(file, "\n\tsCb %d", &pars->num_cb_points)) {
     82      aom_internal_error(error_info, AOM_CODEC_ERROR,
     83                         "Unable to read num cb points");
     84      return;
     85    }
     86    for (int i = 0; i < pars->num_cb_points; ++i) {
     87      if (2 != fscanf(file, "%d %d", &pars->scaling_points_cb[i][0],
     88                      &pars->scaling_points_cb[i][1])) {
     89        aom_internal_error(error_info, AOM_CODEC_ERROR,
     90                           "Unable to read cb scaling points");
     91        return;
     92      }
     93    }
     94    if (!fscanf(file, "\n\tsCr %d", &pars->num_cr_points)) {
     95      aom_internal_error(error_info, AOM_CODEC_ERROR,
     96                         "Unable to read num cr points");
     97      return;
     98    }
     99    for (int i = 0; i < pars->num_cr_points; ++i) {
    100      if (2 != fscanf(file, "%d %d", &pars->scaling_points_cr[i][0],
    101                      &pars->scaling_points_cr[i][1])) {
    102        aom_internal_error(error_info, AOM_CODEC_ERROR,
    103                           "Unable to read cr scaling points");
    104        return;
    105      }
    106    }
    107 
    108    if (fscanf(file, "\n\tcY")) {
    109      aom_internal_error(error_info, AOM_CODEC_ERROR,
    110                         "Unable to read Y coeffs header (cY)");
    111      return;
    112    }
    113    const int n = 2 * pars->ar_coeff_lag * (pars->ar_coeff_lag + 1);
    114    for (int i = 0; i < n; ++i) {
    115      if (1 != fscanf(file, "%d", &pars->ar_coeffs_y[i])) {
    116        aom_internal_error(error_info, AOM_CODEC_ERROR,
    117                           "Unable to read Y coeffs");
    118        return;
    119      }
    120    }
    121    if (fscanf(file, "\n\tcCb")) {
    122      aom_internal_error(error_info, AOM_CODEC_ERROR,
    123                         "Unable to read Cb coeffs header (cCb)");
    124      return;
    125    }
    126    for (int i = 0; i <= n; ++i) {
    127      if (1 != fscanf(file, "%d", &pars->ar_coeffs_cb[i])) {
    128        aom_internal_error(error_info, AOM_CODEC_ERROR,
    129                           "Unable to read Cb coeffs");
    130        return;
    131      }
    132    }
    133    if (fscanf(file, "\n\tcCr")) {
    134      aom_internal_error(error_info, AOM_CODEC_ERROR,
    135                         "Unable read to Cr coeffs header (cCr)");
    136      return;
    137    }
    138    for (int i = 0; i <= n; ++i) {
    139      if (1 != fscanf(file, "%d", &pars->ar_coeffs_cr[i])) {
    140        aom_internal_error(error_info, AOM_CODEC_ERROR,
    141                           "Unable to read Cr coeffs");
    142        return;
    143      }
    144    }
    145    (void)fscanf(file, "\n");
    146  }
    147 }
    148 
    149 static void grain_table_entry_write(FILE *file,
    150                                    aom_film_grain_table_entry_t *entry) {
    151  const aom_film_grain_t *pars = &entry->params;
    152  fprintf(file, "E %" PRId64 " %" PRId64 " %d %d %d\n", entry->start_time,
    153          entry->end_time, pars->apply_grain, pars->random_seed,
    154          pars->update_parameters);
    155  if (pars->update_parameters) {
    156    fprintf(file, "\tp %d %d %d %d %d %d %d %d %d %d %d %d\n",
    157            pars->ar_coeff_lag, pars->ar_coeff_shift, pars->grain_scale_shift,
    158            pars->scaling_shift, pars->chroma_scaling_from_luma,
    159            pars->overlap_flag, pars->cb_mult, pars->cb_luma_mult,
    160            pars->cb_offset, pars->cr_mult, pars->cr_luma_mult,
    161            pars->cr_offset);
    162    fprintf(file, "\tsY %d ", pars->num_y_points);
    163    for (int i = 0; i < pars->num_y_points; ++i) {
    164      fprintf(file, " %d %d", pars->scaling_points_y[i][0],
    165              pars->scaling_points_y[i][1]);
    166    }
    167    fprintf(file, "\n\tsCb %d", pars->num_cb_points);
    168    for (int i = 0; i < pars->num_cb_points; ++i) {
    169      fprintf(file, " %d %d", pars->scaling_points_cb[i][0],
    170              pars->scaling_points_cb[i][1]);
    171    }
    172    fprintf(file, "\n\tsCr %d", pars->num_cr_points);
    173    for (int i = 0; i < pars->num_cr_points; ++i) {
    174      fprintf(file, " %d %d", pars->scaling_points_cr[i][0],
    175              pars->scaling_points_cr[i][1]);
    176    }
    177    fprintf(file, "\n\tcY");
    178    const int n = 2 * pars->ar_coeff_lag * (pars->ar_coeff_lag + 1);
    179    for (int i = 0; i < n; ++i) {
    180      fprintf(file, " %d", pars->ar_coeffs_y[i]);
    181    }
    182    fprintf(file, "\n\tcCb");
    183    for (int i = 0; i <= n; ++i) {
    184      fprintf(file, " %d", pars->ar_coeffs_cb[i]);
    185    }
    186    fprintf(file, "\n\tcCr");
    187    for (int i = 0; i <= n; ++i) {
    188      fprintf(file, " %d", pars->ar_coeffs_cr[i]);
    189    }
    190    fprintf(file, "\n");
    191  }
    192 }
    193 
    194 // TODO(https://crbug.com/aomedia/3228): Update this function to return an
    195 // integer status.
    196 void aom_film_grain_table_append(aom_film_grain_table_t *t, int64_t time_stamp,
    197                                 int64_t end_time,
    198                                 const aom_film_grain_t *grain) {
    199  if (!t->tail || memcmp(grain, &t->tail->params, sizeof(*grain))) {
    200    aom_film_grain_table_entry_t *new_tail = aom_malloc(sizeof(*new_tail));
    201    if (!new_tail) return;
    202    memset(new_tail, 0, sizeof(*new_tail));
    203    if (t->tail) t->tail->next = new_tail;
    204    if (!t->head) t->head = new_tail;
    205    t->tail = new_tail;
    206 
    207    new_tail->start_time = time_stamp;
    208    new_tail->end_time = end_time;
    209    new_tail->params = *grain;
    210  } else {
    211    t->tail->end_time = AOMMAX(t->tail->end_time, end_time);
    212    t->tail->start_time = AOMMIN(t->tail->start_time, time_stamp);
    213  }
    214 }
    215 
    216 int aom_film_grain_table_lookup(aom_film_grain_table_t *t, int64_t time_stamp,
    217                                int64_t end_time, int erase,
    218                                aom_film_grain_t *grain) {
    219  aom_film_grain_table_entry_t *entry = t->head;
    220  aom_film_grain_table_entry_t *prev_entry = NULL;
    221  uint16_t random_seed = grain ? grain->random_seed : 0;
    222  if (grain) memset(grain, 0, sizeof(*grain));
    223 
    224  while (entry) {
    225    aom_film_grain_table_entry_t *next = entry->next;
    226    if (time_stamp >= entry->start_time && time_stamp < entry->end_time) {
    227      if (grain) {
    228        *grain = entry->params;
    229        if (time_stamp != 0) grain->random_seed = random_seed;
    230      }
    231      if (!erase) return 1;
    232 
    233      const int64_t entry_end_time = entry->end_time;
    234      if (time_stamp <= entry->start_time && end_time >= entry->end_time) {
    235        if (t->tail == entry) t->tail = prev_entry;
    236        if (prev_entry) {
    237          prev_entry->next = entry->next;
    238        } else {
    239          t->head = entry->next;
    240        }
    241        aom_free(entry);
    242      } else if (time_stamp <= entry->start_time &&
    243                 end_time < entry->end_time) {
    244        entry->start_time = end_time;
    245      } else if (time_stamp > entry->start_time &&
    246                 end_time >= entry->end_time) {
    247        entry->end_time = time_stamp;
    248      } else {
    249        aom_film_grain_table_entry_t *new_entry =
    250            aom_malloc(sizeof(*new_entry));
    251        if (!new_entry) return 0;
    252        new_entry->next = entry->next;
    253        new_entry->start_time = end_time;
    254        new_entry->end_time = entry->end_time;
    255        new_entry->params = entry->params;
    256        entry->next = new_entry;
    257        entry->end_time = time_stamp;
    258        if (t->tail == entry) t->tail = new_entry;
    259      }
    260      // If segments aren't aligned, delete from the beginning of subsequent
    261      // segments
    262      if (end_time > entry_end_time) {
    263        // Ignoring the return value here is safe since we're erasing from the
    264        // beginning of subsequent entries.
    265        aom_film_grain_table_lookup(t, entry_end_time, end_time, /*erase=*/1,
    266                                    NULL);
    267      }
    268      return 1;
    269    }
    270    prev_entry = entry;
    271    entry = next;
    272  }
    273  return 0;
    274 }
    275 
    276 aom_codec_err_t aom_film_grain_table_read(
    277    aom_film_grain_table_t *t, const char *filename,
    278    struct aom_internal_error_info *error_info) {
    279  FILE *file = fopen(filename, "rb");
    280  if (!file) {
    281    aom_internal_error(error_info, AOM_CODEC_ERROR, "Unable to open %s",
    282                       filename);
    283    return error_info->error_code;
    284  }
    285  error_info->error_code = AOM_CODEC_OK;
    286 
    287  // Read in one extra character as there should be white space after
    288  // the header.
    289  char magic[9];
    290  if (!fread(magic, 9, 1, file) || memcmp(magic, kFileMagic, 8)) {
    291    aom_internal_error(error_info, AOM_CODEC_ERROR,
    292                       "Unable to read (or invalid) file magic");
    293    fclose(file);
    294    return error_info->error_code;
    295  }
    296 
    297  aom_film_grain_table_entry_t *prev_entry = NULL;
    298  while (!feof(file)) {
    299    aom_film_grain_table_entry_t *entry = aom_malloc(sizeof(*entry));
    300    if (!entry) {
    301      aom_internal_error(error_info, AOM_CODEC_MEM_ERROR,
    302                         "Unable to allocate grain table entry");
    303      break;
    304    }
    305    memset(entry, 0, sizeof(*entry));
    306    grain_table_entry_read(file, error_info, entry);
    307    entry->next = NULL;
    308 
    309    if (prev_entry) prev_entry->next = entry;
    310    if (!t->head) t->head = entry;
    311    t->tail = entry;
    312    prev_entry = entry;
    313 
    314    if (error_info->error_code != AOM_CODEC_OK) break;
    315  }
    316 
    317  fclose(file);
    318  return error_info->error_code;
    319 }
    320 
    321 aom_codec_err_t aom_film_grain_table_write(
    322    const aom_film_grain_table_t *t, const char *filename,
    323    struct aom_internal_error_info *error_info) {
    324  error_info->error_code = AOM_CODEC_OK;
    325 
    326  FILE *file = fopen(filename, "wb");
    327  if (!file) {
    328    aom_internal_error(error_info, AOM_CODEC_ERROR, "Unable to open file %s",
    329                       filename);
    330    return error_info->error_code;
    331  }
    332 
    333  if (!fwrite(kFileMagic, 8, 1, file)) {
    334    aom_internal_error(error_info, AOM_CODEC_ERROR,
    335                       "Unable to write file magic");
    336    fclose(file);
    337    return error_info->error_code;
    338  }
    339 
    340  fprintf(file, "\n");
    341  aom_film_grain_table_entry_t *entry = t->head;
    342  while (entry) {
    343    grain_table_entry_write(file, entry);
    344    entry = entry->next;
    345  }
    346  fclose(file);
    347  return error_info->error_code;
    348 }
    349 
    350 void aom_film_grain_table_free(aom_film_grain_table_t *t) {
    351  aom_film_grain_table_entry_t *entry = t->head;
    352  while (entry) {
    353    aom_film_grain_table_entry_t *next = entry->next;
    354    aom_free(entry);
    355    entry = next;
    356  }
    357  memset(t, 0, sizeof(*t));
    358 }