1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com> 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * Codebook Generator using the ELBG algorithm 24cabdff1aSopenharmony_ci */ 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include <string.h> 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 29cabdff1aSopenharmony_ci#include "libavutil/common.h" 30cabdff1aSopenharmony_ci#include "libavutil/lfg.h" 31cabdff1aSopenharmony_ci#include "elbg.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#define DELTA_ERR_MAX 0.1 ///< Precision of the ELBG algorithm (as percentage error) 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci/** 36cabdff1aSopenharmony_ci * In the ELBG jargon, a cell is the set of points that are closest to a 37cabdff1aSopenharmony_ci * codebook entry. Not to be confused with a RoQ Video cell. */ 38cabdff1aSopenharmony_citypedef struct cell_s { 39cabdff1aSopenharmony_ci int index; 40cabdff1aSopenharmony_ci struct cell_s *next; 41cabdff1aSopenharmony_ci} cell; 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci/** 44cabdff1aSopenharmony_ci * ELBG internal data 45cabdff1aSopenharmony_ci */ 46cabdff1aSopenharmony_citypedef struct ELBGContext { 47cabdff1aSopenharmony_ci int64_t error; 48cabdff1aSopenharmony_ci int dim; 49cabdff1aSopenharmony_ci int num_cb; 50cabdff1aSopenharmony_ci int *codebook; 51cabdff1aSopenharmony_ci cell **cells; 52cabdff1aSopenharmony_ci int64_t *utility; 53cabdff1aSopenharmony_ci int64_t *utility_inc; 54cabdff1aSopenharmony_ci int *nearest_cb; 55cabdff1aSopenharmony_ci int *points; 56cabdff1aSopenharmony_ci int *temp_points; 57cabdff1aSopenharmony_ci int *size_part; 58cabdff1aSopenharmony_ci AVLFG *rand_state; 59cabdff1aSopenharmony_ci int *scratchbuf; 60cabdff1aSopenharmony_ci cell *cell_buffer; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci /* Sizes for the buffers above. Pointers without such a field 63cabdff1aSopenharmony_ci * are not allocated by us and only valid for the duration 64cabdff1aSopenharmony_ci * of a single call to avpriv_elbg_do(). */ 65cabdff1aSopenharmony_ci unsigned utility_allocated; 66cabdff1aSopenharmony_ci unsigned utility_inc_allocated; 67cabdff1aSopenharmony_ci unsigned size_part_allocated; 68cabdff1aSopenharmony_ci unsigned cells_allocated; 69cabdff1aSopenharmony_ci unsigned scratchbuf_allocated; 70cabdff1aSopenharmony_ci unsigned cell_buffer_allocated; 71cabdff1aSopenharmony_ci unsigned temp_points_allocated; 72cabdff1aSopenharmony_ci} ELBGContext; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_cistatic inline int distance_limited(int *a, int *b, int dim, int limit) 75cabdff1aSopenharmony_ci{ 76cabdff1aSopenharmony_ci int i, dist=0; 77cabdff1aSopenharmony_ci for (i=0; i<dim; i++) { 78cabdff1aSopenharmony_ci dist += (a[i] - b[i])*(a[i] - b[i]); 79cabdff1aSopenharmony_ci if (dist > limit) 80cabdff1aSopenharmony_ci return INT_MAX; 81cabdff1aSopenharmony_ci } 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci return dist; 84cabdff1aSopenharmony_ci} 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_cistatic inline void vect_division(int *res, int *vect, int div, int dim) 87cabdff1aSopenharmony_ci{ 88cabdff1aSopenharmony_ci int i; 89cabdff1aSopenharmony_ci if (div > 1) 90cabdff1aSopenharmony_ci for (i=0; i<dim; i++) 91cabdff1aSopenharmony_ci res[i] = ROUNDED_DIV(vect[i],div); 92cabdff1aSopenharmony_ci else if (res != vect) 93cabdff1aSopenharmony_ci memcpy(res, vect, dim*sizeof(int)); 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci} 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_cistatic int eval_error_cell(ELBGContext *elbg, int *centroid, cell *cells) 98cabdff1aSopenharmony_ci{ 99cabdff1aSopenharmony_ci int error=0; 100cabdff1aSopenharmony_ci for (; cells; cells=cells->next) 101cabdff1aSopenharmony_ci error += distance_limited(centroid, elbg->points + cells->index*elbg->dim, elbg->dim, INT_MAX); 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci return error; 104cabdff1aSopenharmony_ci} 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_cistatic int get_closest_codebook(ELBGContext *elbg, int index) 107cabdff1aSopenharmony_ci{ 108cabdff1aSopenharmony_ci int pick = 0; 109cabdff1aSopenharmony_ci for (int i = 0, diff_min = INT_MAX; i < elbg->num_cb; i++) 110cabdff1aSopenharmony_ci if (i != index) { 111cabdff1aSopenharmony_ci int diff; 112cabdff1aSopenharmony_ci diff = distance_limited(elbg->codebook + i*elbg->dim, elbg->codebook + index*elbg->dim, elbg->dim, diff_min); 113cabdff1aSopenharmony_ci if (diff < diff_min) { 114cabdff1aSopenharmony_ci pick = i; 115cabdff1aSopenharmony_ci diff_min = diff; 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci } 118cabdff1aSopenharmony_ci return pick; 119cabdff1aSopenharmony_ci} 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_cistatic int get_high_utility_cell(ELBGContext *elbg) 122cabdff1aSopenharmony_ci{ 123cabdff1aSopenharmony_ci int i=0; 124cabdff1aSopenharmony_ci /* Using linear search, do binary if it ever turns to be speed critical */ 125cabdff1aSopenharmony_ci uint64_t r; 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_ci if (elbg->utility_inc[elbg->num_cb - 1] < INT_MAX) { 128cabdff1aSopenharmony_ci r = av_lfg_get(elbg->rand_state) % (unsigned int)elbg->utility_inc[elbg->num_cb - 1] + 1; 129cabdff1aSopenharmony_ci } else { 130cabdff1aSopenharmony_ci r = av_lfg_get(elbg->rand_state); 131cabdff1aSopenharmony_ci r = (av_lfg_get(elbg->rand_state) + (r<<32)) % elbg->utility_inc[elbg->num_cb - 1] + 1; 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci while (elbg->utility_inc[i] < r) { 135cabdff1aSopenharmony_ci i++; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci av_assert2(elbg->cells[i]); 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci return i; 141cabdff1aSopenharmony_ci} 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci/** 144cabdff1aSopenharmony_ci * Implementation of the simple LBG algorithm for just two codebooks 145cabdff1aSopenharmony_ci */ 146cabdff1aSopenharmony_cistatic int simple_lbg(ELBGContext *elbg, 147cabdff1aSopenharmony_ci int dim, 148cabdff1aSopenharmony_ci int *centroid[3], 149cabdff1aSopenharmony_ci int newutility[3], 150cabdff1aSopenharmony_ci int *points, 151cabdff1aSopenharmony_ci cell *cells) 152cabdff1aSopenharmony_ci{ 153cabdff1aSopenharmony_ci int i, idx; 154cabdff1aSopenharmony_ci int numpoints[2] = {0,0}; 155cabdff1aSopenharmony_ci int *newcentroid[2] = { 156cabdff1aSopenharmony_ci elbg->scratchbuf + 3*dim, 157cabdff1aSopenharmony_ci elbg->scratchbuf + 4*dim 158cabdff1aSopenharmony_ci }; 159cabdff1aSopenharmony_ci cell *tempcell; 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci memset(newcentroid[0], 0, 2 * dim * sizeof(*newcentroid[0])); 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci newutility[0] = 164cabdff1aSopenharmony_ci newutility[1] = 0; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci for (tempcell = cells; tempcell; tempcell=tempcell->next) { 167cabdff1aSopenharmony_ci idx = distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX)>= 168cabdff1aSopenharmony_ci distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX); 169cabdff1aSopenharmony_ci numpoints[idx]++; 170cabdff1aSopenharmony_ci for (i=0; i<dim; i++) 171cabdff1aSopenharmony_ci newcentroid[idx][i] += points[tempcell->index*dim + i]; 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci vect_division(centroid[0], newcentroid[0], numpoints[0], dim); 175cabdff1aSopenharmony_ci vect_division(centroid[1], newcentroid[1], numpoints[1], dim); 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci for (tempcell = cells; tempcell; tempcell=tempcell->next) { 178cabdff1aSopenharmony_ci int dist[2] = {distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX), 179cabdff1aSopenharmony_ci distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX)}; 180cabdff1aSopenharmony_ci int idx = dist[0] > dist[1]; 181cabdff1aSopenharmony_ci newutility[idx] += dist[idx]; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci return newutility[0] + newutility[1]; 185cabdff1aSopenharmony_ci} 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_cistatic void get_new_centroids(ELBGContext *elbg, int huc, int *newcentroid_i, 188cabdff1aSopenharmony_ci int *newcentroid_p) 189cabdff1aSopenharmony_ci{ 190cabdff1aSopenharmony_ci cell *tempcell; 191cabdff1aSopenharmony_ci int *min = newcentroid_i; 192cabdff1aSopenharmony_ci int *max = newcentroid_p; 193cabdff1aSopenharmony_ci int i; 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci for (i=0; i< elbg->dim; i++) { 196cabdff1aSopenharmony_ci min[i]=INT_MAX; 197cabdff1aSopenharmony_ci max[i]=0; 198cabdff1aSopenharmony_ci } 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci for (tempcell = elbg->cells[huc]; tempcell; tempcell = tempcell->next) 201cabdff1aSopenharmony_ci for(i=0; i<elbg->dim; i++) { 202cabdff1aSopenharmony_ci min[i]=FFMIN(min[i], elbg->points[tempcell->index*elbg->dim + i]); 203cabdff1aSopenharmony_ci max[i]=FFMAX(max[i], elbg->points[tempcell->index*elbg->dim + i]); 204cabdff1aSopenharmony_ci } 205cabdff1aSopenharmony_ci 206cabdff1aSopenharmony_ci for (i=0; i<elbg->dim; i++) { 207cabdff1aSopenharmony_ci int ni = min[i] + (max[i] - min[i])/3; 208cabdff1aSopenharmony_ci int np = min[i] + (2*(max[i] - min[i]))/3; 209cabdff1aSopenharmony_ci newcentroid_i[i] = ni; 210cabdff1aSopenharmony_ci newcentroid_p[i] = np; 211cabdff1aSopenharmony_ci } 212cabdff1aSopenharmony_ci} 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci/** 215cabdff1aSopenharmony_ci * Add the points in the low utility cell to its closest cell. Split the high 216cabdff1aSopenharmony_ci * utility cell, putting the separated points in the (now empty) low utility 217cabdff1aSopenharmony_ci * cell. 218cabdff1aSopenharmony_ci * 219cabdff1aSopenharmony_ci * @param elbg Internal elbg data 220cabdff1aSopenharmony_ci * @param indexes {luc, huc, cluc} 221cabdff1aSopenharmony_ci * @param newcentroid A vector with the position of the new centroids 222cabdff1aSopenharmony_ci */ 223cabdff1aSopenharmony_cistatic void shift_codebook(ELBGContext *elbg, int *indexes, 224cabdff1aSopenharmony_ci int *newcentroid[3]) 225cabdff1aSopenharmony_ci{ 226cabdff1aSopenharmony_ci cell *tempdata; 227cabdff1aSopenharmony_ci cell **pp = &elbg->cells[indexes[2]]; 228cabdff1aSopenharmony_ci 229cabdff1aSopenharmony_ci while(*pp) 230cabdff1aSopenharmony_ci pp= &(*pp)->next; 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci *pp = elbg->cells[indexes[0]]; 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci elbg->cells[indexes[0]] = NULL; 235cabdff1aSopenharmony_ci tempdata = elbg->cells[indexes[1]]; 236cabdff1aSopenharmony_ci elbg->cells[indexes[1]] = NULL; 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci while(tempdata) { 239cabdff1aSopenharmony_ci cell *tempcell2 = tempdata->next; 240cabdff1aSopenharmony_ci int idx = distance_limited(elbg->points + tempdata->index*elbg->dim, 241cabdff1aSopenharmony_ci newcentroid[0], elbg->dim, INT_MAX) > 242cabdff1aSopenharmony_ci distance_limited(elbg->points + tempdata->index*elbg->dim, 243cabdff1aSopenharmony_ci newcentroid[1], elbg->dim, INT_MAX); 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci tempdata->next = elbg->cells[indexes[idx]]; 246cabdff1aSopenharmony_ci elbg->cells[indexes[idx]] = tempdata; 247cabdff1aSopenharmony_ci tempdata = tempcell2; 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci} 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_cistatic void evaluate_utility_inc(ELBGContext *elbg) 252cabdff1aSopenharmony_ci{ 253cabdff1aSopenharmony_ci int64_t inc=0; 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci for (int i = 0; i < elbg->num_cb; i++) { 256cabdff1aSopenharmony_ci if (elbg->num_cb * elbg->utility[i] > elbg->error) 257cabdff1aSopenharmony_ci inc += elbg->utility[i]; 258cabdff1aSopenharmony_ci elbg->utility_inc[i] = inc; 259cabdff1aSopenharmony_ci } 260cabdff1aSopenharmony_ci} 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_cistatic void update_utility_and_n_cb(ELBGContext *elbg, int idx, int newutility) 264cabdff1aSopenharmony_ci{ 265cabdff1aSopenharmony_ci cell *tempcell; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci elbg->utility[idx] = newutility; 268cabdff1aSopenharmony_ci for (tempcell=elbg->cells[idx]; tempcell; tempcell=tempcell->next) 269cabdff1aSopenharmony_ci elbg->nearest_cb[tempcell->index] = idx; 270cabdff1aSopenharmony_ci} 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci/** 273cabdff1aSopenharmony_ci * Evaluate if a shift lower the error. If it does, call shift_codebooks 274cabdff1aSopenharmony_ci * and update elbg->error, elbg->utility and elbg->nearest_cb. 275cabdff1aSopenharmony_ci * 276cabdff1aSopenharmony_ci * @param elbg Internal elbg data 277cabdff1aSopenharmony_ci * @param idx {luc (low utility cell, huc (high utility cell), cluc (closest cell to low utility cell)} 278cabdff1aSopenharmony_ci */ 279cabdff1aSopenharmony_cistatic void try_shift_candidate(ELBGContext *elbg, int idx[3]) 280cabdff1aSopenharmony_ci{ 281cabdff1aSopenharmony_ci int j, k, cont=0; 282cabdff1aSopenharmony_ci int64_t olderror=0, newerror; 283cabdff1aSopenharmony_ci int newutility[3]; 284cabdff1aSopenharmony_ci int *newcentroid[3] = { 285cabdff1aSopenharmony_ci elbg->scratchbuf, 286cabdff1aSopenharmony_ci elbg->scratchbuf + elbg->dim, 287cabdff1aSopenharmony_ci elbg->scratchbuf + 2*elbg->dim 288cabdff1aSopenharmony_ci }; 289cabdff1aSopenharmony_ci cell *tempcell; 290cabdff1aSopenharmony_ci 291cabdff1aSopenharmony_ci for (j=0; j<3; j++) 292cabdff1aSopenharmony_ci olderror += elbg->utility[idx[j]]; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci memset(newcentroid[2], 0, elbg->dim*sizeof(int)); 295cabdff1aSopenharmony_ci 296cabdff1aSopenharmony_ci for (k=0; k<2; k++) 297cabdff1aSopenharmony_ci for (tempcell=elbg->cells[idx[2*k]]; tempcell; tempcell=tempcell->next) { 298cabdff1aSopenharmony_ci cont++; 299cabdff1aSopenharmony_ci for (j=0; j<elbg->dim; j++) 300cabdff1aSopenharmony_ci newcentroid[2][j] += elbg->points[tempcell->index*elbg->dim + j]; 301cabdff1aSopenharmony_ci } 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci vect_division(newcentroid[2], newcentroid[2], cont, elbg->dim); 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci get_new_centroids(elbg, idx[1], newcentroid[0], newcentroid[1]); 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci newutility[2] = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[0]]); 308cabdff1aSopenharmony_ci newutility[2] += eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[2]]); 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci newerror = newutility[2]; 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_ci newerror += simple_lbg(elbg, elbg->dim, newcentroid, newutility, elbg->points, 313cabdff1aSopenharmony_ci elbg->cells[idx[1]]); 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci if (olderror > newerror) { 316cabdff1aSopenharmony_ci shift_codebook(elbg, idx, newcentroid); 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci elbg->error += newerror - olderror; 319cabdff1aSopenharmony_ci 320cabdff1aSopenharmony_ci for (j=0; j<3; j++) 321cabdff1aSopenharmony_ci update_utility_and_n_cb(elbg, idx[j], newutility[j]); 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci evaluate_utility_inc(elbg); 324cabdff1aSopenharmony_ci } 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci 327cabdff1aSopenharmony_ci/** 328cabdff1aSopenharmony_ci * Implementation of the ELBG block 329cabdff1aSopenharmony_ci */ 330cabdff1aSopenharmony_cistatic void do_shiftings(ELBGContext *elbg) 331cabdff1aSopenharmony_ci{ 332cabdff1aSopenharmony_ci int idx[3]; 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci evaluate_utility_inc(elbg); 335cabdff1aSopenharmony_ci 336cabdff1aSopenharmony_ci for (idx[0]=0; idx[0] < elbg->num_cb; idx[0]++) 337cabdff1aSopenharmony_ci if (elbg->num_cb * elbg->utility[idx[0]] < elbg->error) { 338cabdff1aSopenharmony_ci if (elbg->utility_inc[elbg->num_cb - 1] == 0) 339cabdff1aSopenharmony_ci return; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci idx[1] = get_high_utility_cell(elbg); 342cabdff1aSopenharmony_ci idx[2] = get_closest_codebook(elbg, idx[0]); 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci if (idx[1] != idx[0] && idx[1] != idx[2]) 345cabdff1aSopenharmony_ci try_shift_candidate(elbg, idx); 346cabdff1aSopenharmony_ci } 347cabdff1aSopenharmony_ci} 348cabdff1aSopenharmony_ci 349cabdff1aSopenharmony_cistatic void do_elbg(ELBGContext *av_restrict elbg, int *points, int numpoints, 350cabdff1aSopenharmony_ci int max_steps) 351cabdff1aSopenharmony_ci{ 352cabdff1aSopenharmony_ci int *const size_part = elbg->size_part; 353cabdff1aSopenharmony_ci int i, j, steps = 0; 354cabdff1aSopenharmony_ci int best_idx = 0; 355cabdff1aSopenharmony_ci int64_t last_error; 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci elbg->error = INT64_MAX; 358cabdff1aSopenharmony_ci elbg->points = points; 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_ci do { 361cabdff1aSopenharmony_ci cell *free_cells = elbg->cell_buffer; 362cabdff1aSopenharmony_ci last_error = elbg->error; 363cabdff1aSopenharmony_ci steps++; 364cabdff1aSopenharmony_ci memset(elbg->utility, 0, elbg->num_cb * sizeof(*elbg->utility)); 365cabdff1aSopenharmony_ci memset(elbg->cells, 0, elbg->num_cb * sizeof(*elbg->cells)); 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci elbg->error = 0; 368cabdff1aSopenharmony_ci 369cabdff1aSopenharmony_ci /* This loop evaluate the actual Voronoi partition. It is the most 370cabdff1aSopenharmony_ci costly part of the algorithm. */ 371cabdff1aSopenharmony_ci for (i=0; i < numpoints; i++) { 372cabdff1aSopenharmony_ci int best_dist = distance_limited(elbg->points + i * elbg->dim, 373cabdff1aSopenharmony_ci elbg->codebook + best_idx * elbg->dim, 374cabdff1aSopenharmony_ci elbg->dim, INT_MAX); 375cabdff1aSopenharmony_ci for (int k = 0; k < elbg->num_cb; k++) { 376cabdff1aSopenharmony_ci int dist = distance_limited(elbg->points + i * elbg->dim, 377cabdff1aSopenharmony_ci elbg->codebook + k * elbg->dim, 378cabdff1aSopenharmony_ci elbg->dim, best_dist); 379cabdff1aSopenharmony_ci if (dist < best_dist) { 380cabdff1aSopenharmony_ci best_dist = dist; 381cabdff1aSopenharmony_ci best_idx = k; 382cabdff1aSopenharmony_ci } 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci elbg->nearest_cb[i] = best_idx; 385cabdff1aSopenharmony_ci elbg->error += best_dist; 386cabdff1aSopenharmony_ci elbg->utility[elbg->nearest_cb[i]] += best_dist; 387cabdff1aSopenharmony_ci free_cells->index = i; 388cabdff1aSopenharmony_ci free_cells->next = elbg->cells[elbg->nearest_cb[i]]; 389cabdff1aSopenharmony_ci elbg->cells[elbg->nearest_cb[i]] = free_cells; 390cabdff1aSopenharmony_ci free_cells++; 391cabdff1aSopenharmony_ci } 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_ci do_shiftings(elbg); 394cabdff1aSopenharmony_ci 395cabdff1aSopenharmony_ci memset(size_part, 0, elbg->num_cb * sizeof(*size_part)); 396cabdff1aSopenharmony_ci 397cabdff1aSopenharmony_ci memset(elbg->codebook, 0, elbg->num_cb * elbg->dim * sizeof(*elbg->codebook)); 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci for (i=0; i < numpoints; i++) { 400cabdff1aSopenharmony_ci size_part[elbg->nearest_cb[i]]++; 401cabdff1aSopenharmony_ci for (j=0; j < elbg->dim; j++) 402cabdff1aSopenharmony_ci elbg->codebook[elbg->nearest_cb[i]*elbg->dim + j] += 403cabdff1aSopenharmony_ci elbg->points[i*elbg->dim + j]; 404cabdff1aSopenharmony_ci } 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci for (int i = 0; i < elbg->num_cb; i++) 407cabdff1aSopenharmony_ci vect_division(elbg->codebook + i*elbg->dim, 408cabdff1aSopenharmony_ci elbg->codebook + i*elbg->dim, size_part[i], elbg->dim); 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci } while(((last_error - elbg->error) > DELTA_ERR_MAX*elbg->error) && 411cabdff1aSopenharmony_ci (steps < max_steps)); 412cabdff1aSopenharmony_ci} 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_ci#define BIG_PRIME 433494437LL 415cabdff1aSopenharmony_ci 416cabdff1aSopenharmony_ci/** 417cabdff1aSopenharmony_ci * Initialize the codebook vector for the elbg algorithm. 418cabdff1aSopenharmony_ci * If numpoints <= 24 * num_cb this function fills codebook with random numbers. 419cabdff1aSopenharmony_ci * If not, it calls do_elbg for a (smaller) random sample of the points in 420cabdff1aSopenharmony_ci * points. 421cabdff1aSopenharmony_ci */ 422cabdff1aSopenharmony_cistatic void init_elbg(ELBGContext *av_restrict elbg, int *points, int *temp_points, 423cabdff1aSopenharmony_ci int numpoints, int max_steps) 424cabdff1aSopenharmony_ci{ 425cabdff1aSopenharmony_ci int dim = elbg->dim; 426cabdff1aSopenharmony_ci 427cabdff1aSopenharmony_ci if (numpoints > 24LL * elbg->num_cb) { 428cabdff1aSopenharmony_ci /* ELBG is very costly for a big number of points. So if we have a lot 429cabdff1aSopenharmony_ci of them, get a good initial codebook to save on iterations */ 430cabdff1aSopenharmony_ci for (int i = 0; i < numpoints / 8; i++) { 431cabdff1aSopenharmony_ci int k = (i*BIG_PRIME) % numpoints; 432cabdff1aSopenharmony_ci memcpy(temp_points + i*dim, points + k*dim, dim * sizeof(*temp_points)); 433cabdff1aSopenharmony_ci } 434cabdff1aSopenharmony_ci 435cabdff1aSopenharmony_ci /* If anything is changed in the recursion parameters, 436cabdff1aSopenharmony_ci * the allocated size of temp_points will also need to be updated. */ 437cabdff1aSopenharmony_ci init_elbg(elbg, temp_points, temp_points + numpoints / 8 * dim, 438cabdff1aSopenharmony_ci numpoints / 8, 2 * max_steps); 439cabdff1aSopenharmony_ci do_elbg(elbg, temp_points, numpoints / 8, 2 * max_steps); 440cabdff1aSopenharmony_ci } else // If not, initialize the codebook with random positions 441cabdff1aSopenharmony_ci for (int i = 0; i < elbg->num_cb; i++) 442cabdff1aSopenharmony_ci memcpy(elbg->codebook + i * dim, points + ((i*BIG_PRIME)%numpoints)*dim, 443cabdff1aSopenharmony_ci dim * sizeof(*elbg->codebook)); 444cabdff1aSopenharmony_ci} 445cabdff1aSopenharmony_ci 446cabdff1aSopenharmony_ciint avpriv_elbg_do(ELBGContext **elbgp, int *points, int dim, int numpoints, 447cabdff1aSopenharmony_ci int *codebook, int num_cb, int max_steps, 448cabdff1aSopenharmony_ci int *closest_cb, AVLFG *rand_state, uintptr_t flags) 449cabdff1aSopenharmony_ci{ 450cabdff1aSopenharmony_ci ELBGContext *const av_restrict elbg = *elbgp ? *elbgp : av_mallocz(sizeof(*elbg)); 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ci if (!elbg) 453cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 454cabdff1aSopenharmony_ci *elbgp = elbg; 455cabdff1aSopenharmony_ci 456cabdff1aSopenharmony_ci elbg->nearest_cb = closest_cb; 457cabdff1aSopenharmony_ci elbg->rand_state = rand_state; 458cabdff1aSopenharmony_ci elbg->codebook = codebook; 459cabdff1aSopenharmony_ci elbg->num_cb = num_cb; 460cabdff1aSopenharmony_ci elbg->dim = dim; 461cabdff1aSopenharmony_ci 462cabdff1aSopenharmony_ci#define ALLOCATE_IF_NECESSARY(field, new_elements, multiplicator) \ 463cabdff1aSopenharmony_ci if (elbg->field ## _allocated < new_elements) { \ 464cabdff1aSopenharmony_ci av_freep(&elbg->field); \ 465cabdff1aSopenharmony_ci elbg->field = av_malloc_array(new_elements, \ 466cabdff1aSopenharmony_ci multiplicator * sizeof(*elbg->field)); \ 467cabdff1aSopenharmony_ci if (!elbg->field) { \ 468cabdff1aSopenharmony_ci elbg->field ## _allocated = 0; \ 469cabdff1aSopenharmony_ci return AVERROR(ENOMEM); \ 470cabdff1aSopenharmony_ci } \ 471cabdff1aSopenharmony_ci elbg->field ## _allocated = new_elements; \ 472cabdff1aSopenharmony_ci } 473cabdff1aSopenharmony_ci /* Allocating the buffers for do_elbg() here once relies 474cabdff1aSopenharmony_ci * on their size being always the same even when do_elbg() 475cabdff1aSopenharmony_ci * is called from init_elbg(). It also relies on do_elbg() 476cabdff1aSopenharmony_ci * never calling itself recursively. */ 477cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(cells, num_cb, 1) 478cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(utility, num_cb, 1) 479cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(utility_inc, num_cb, 1) 480cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(size_part, num_cb, 1) 481cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(cell_buffer, numpoints, 1) 482cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(scratchbuf, dim, 5) 483cabdff1aSopenharmony_ci if (numpoints > 24LL * elbg->num_cb) { 484cabdff1aSopenharmony_ci /* The first step in the recursion in init_elbg() needs a buffer with 485cabdff1aSopenharmony_ci * (numpoints / 8) * dim elements; the next step needs numpoints / 8 / 8 486cabdff1aSopenharmony_ci * * dim elements etc. The geometric series leads to an upper bound of 487cabdff1aSopenharmony_ci * numpoints / 8 * 8 / 7 * dim elements. */ 488cabdff1aSopenharmony_ci uint64_t prod = dim * (uint64_t)(numpoints / 7U); 489cabdff1aSopenharmony_ci if (prod > INT_MAX) 490cabdff1aSopenharmony_ci return AVERROR(ERANGE); 491cabdff1aSopenharmony_ci ALLOCATE_IF_NECESSARY(temp_points, prod, 1) 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci 494cabdff1aSopenharmony_ci init_elbg(elbg, points, elbg->temp_points, numpoints, max_steps); 495cabdff1aSopenharmony_ci do_elbg (elbg, points, numpoints, max_steps); 496cabdff1aSopenharmony_ci return 0; 497cabdff1aSopenharmony_ci} 498cabdff1aSopenharmony_ci 499cabdff1aSopenharmony_ciav_cold void avpriv_elbg_free(ELBGContext **elbgp) 500cabdff1aSopenharmony_ci{ 501cabdff1aSopenharmony_ci ELBGContext *elbg = *elbgp; 502cabdff1aSopenharmony_ci if (!elbg) 503cabdff1aSopenharmony_ci return; 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ci av_freep(&elbg->size_part); 506cabdff1aSopenharmony_ci av_freep(&elbg->utility); 507cabdff1aSopenharmony_ci av_freep(&elbg->cell_buffer); 508cabdff1aSopenharmony_ci av_freep(&elbg->cells); 509cabdff1aSopenharmony_ci av_freep(&elbg->utility_inc); 510cabdff1aSopenharmony_ci av_freep(&elbg->scratchbuf); 511cabdff1aSopenharmony_ci av_freep(&elbg->temp_points); 512cabdff1aSopenharmony_ci 513cabdff1aSopenharmony_ci av_freep(elbgp); 514cabdff1aSopenharmony_ci} 515