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 }