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