@@ -191,18 +191,11 @@ void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
191191 }
192192}
193193
194- // Removes the histogram 'i' from 'set' by setting it to NULL.
195- static void HistogramSetRemoveHistogram (VP8LHistogramSet * const set , int i ,
196- int * const num_used ) {
197- assert (set -> histograms [i ] != NULL );
198- set -> histograms [i ] = NULL ;
199- -- * num_used ;
200- // If we remove the last valid one, shrink until the next valid one.
201- if (i == set -> size - 1 ) {
202- while (set -> size >= 1 && set -> histograms [set -> size - 1 ] == NULL ) {
203- -- set -> size ;
204- }
205- }
194+ // Removes the histogram 'i' from 'set'.
195+ static void HistogramSetRemoveHistogram (VP8LHistogramSet * const set , int i ) {
196+ set -> histograms [i ] = set -> histograms [set -> size - 1 ];
197+ -- set -> size ;
198+ assert (set -> size > 0 );
206199}
207200
208201// -----------------------------------------------------------------------------
@@ -645,8 +638,7 @@ static void HistogramBuild(
645638
646639// Copies the histograms and computes its bit_cost.
647640static void HistogramCopyAndAnalyze (VP8LHistogramSet * const orig_histo ,
648- VP8LHistogramSet * const image_histo ,
649- int * const num_used ) {
641+ VP8LHistogramSet * const image_histo ) {
650642 int i ;
651643 VP8LHistogram * * const orig_histograms = orig_histo -> histograms ;
652644 VP8LHistogram * * const histograms = image_histo -> histograms ;
@@ -664,7 +656,6 @@ static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo,
664656 // The first histogram is always used.
665657 assert (i > 0 );
666658 orig_histograms [i ] = NULL ;
667- -- * num_used ;
668659 } else {
669660 // Copy histograms from orig_histo[] to image_histo[].
670661 HistogramCopy (histo , histograms [image_histo -> size ]);
@@ -700,8 +691,7 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
700691// Sets the remaining histograms to NULL.
701692// 'combine_cost_factor' has to be divided by 100.
702693static void HistogramCombineEntropyBin (VP8LHistogramSet * const image_histo ,
703- int * num_used , VP8LHistogram * cur_combo ,
704- int num_bins ,
694+ VP8LHistogram * cur_combo , int num_bins ,
705695 int32_t combine_cost_factor ,
706696 int low_effort ) {
707697 VP8LHistogram * * const histograms = image_histo -> histograms ;
@@ -718,14 +708,15 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
718708 bin_info [idx ].num_combine_failures = 0 ;
719709 }
720710
721- for (idx = 0 ; idx < image_histo -> size ; ++ idx ) {
711+ for (idx = 0 ; idx < image_histo -> size ;) {
722712 const int bin_id = histograms [idx ]-> bin_id ;
723713 const int first = bin_info [bin_id ].first ;
724714 if (first == -1 ) {
725715 bin_info [bin_id ].first = idx ;
716+ ++ idx ;
726717 } else if (low_effort ) {
727718 HistogramAdd (histograms [idx ], histograms [first ], histograms [first ]);
728- HistogramSetRemoveHistogram (image_histo , idx , num_used );
719+ HistogramSetRemoveHistogram (image_histo , idx );
729720 } else {
730721 // try to merge #idx into #first (both share the same bin_id)
731722 const uint64_t bit_cost = histograms [idx ]-> bit_cost ;
@@ -757,17 +748,19 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
757748 bin_info [bin_id ].num_combine_failures >= max_combine_failures ) {
758749 // move the (better) merged histogram to its final slot
759750 HistogramSwap (& cur_combo , & histograms [first ]);
760- HistogramSetRemoveHistogram (image_histo , idx , num_used );
751+ HistogramSetRemoveHistogram (image_histo , idx );
761752 } else {
762753 ++ bin_info [bin_id ].num_combine_failures ;
754+ ++ idx ;
763755 }
756+ } else {
757+ ++ idx ;
764758 }
765759 }
766760 }
767761 if (low_effort ) {
768762 // for low_effort case, update the final cost when everything is merged
769763 for (idx = 0 ; idx < image_histo -> size ; ++ idx ) {
770- if (histograms [idx ] == NULL ) continue ;
771764 ComputeHistogramCost (histograms [idx ]);
772765 }
773766 }
@@ -842,6 +835,18 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
842835 }
843836}
844837
838+ // Replaces the bad_id with good_id in the pair.
839+ static void HistoQueueFixPair (int bad_id , int good_id ,
840+ HistogramPair * const pair ) {
841+ if (pair -> idx1 == bad_id ) pair -> idx1 = good_id ;
842+ if (pair -> idx2 == bad_id ) pair -> idx2 = good_id ;
843+ if (pair -> idx1 > pair -> idx2 ) {
844+ const int tmp = pair -> idx1 ;
845+ pair -> idx1 = pair -> idx2 ;
846+ pair -> idx2 = tmp ;
847+ }
848+ }
849+
845850// Update the cost diff and combo of a pair of histograms. This needs to be
846851// called when the histograms have been merged with a third one.
847852// Returns 1 if the cost diff is less than the threshold.
@@ -896,8 +901,7 @@ static int64_t HistoQueuePush(HistoQueue* const histo_queue,
896901
897902// Combines histograms by continuously choosing the one with the highest cost
898903// reduction.
899- static int HistogramCombineGreedy (VP8LHistogramSet * const image_histo ,
900- int * const num_used ) {
904+ static int HistogramCombineGreedy (VP8LHistogramSet * const image_histo ) {
901905 int ok = 0 ;
902906 const int image_histo_size = image_histo -> size ;
903907 int i , j ;
@@ -916,11 +920,9 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
916920 goto End ;
917921 }
918922
923+ // Initialize the queue.
919924 for (i = 0 ; i < image_histo_size ; ++ i ) {
920- if (image_histo -> histograms [i ] == NULL ) continue ;
921925 for (j = i + 1 ; j < image_histo_size ; ++ j ) {
922- // Initialize queue.
923- if (image_histo -> histograms [j ] == NULL ) continue ;
924926 HistoQueuePush (& histo_queue , histograms , i , j , 0 );
925927 }
926928 }
@@ -933,7 +935,7 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
933935 histo_queue .queue [0 ].costs , histograms [idx1 ]);
934936
935937 // Remove merged histogram.
936- HistogramSetRemoveHistogram (image_histo , idx2 , num_used );
938+ HistogramSetRemoveHistogram (image_histo , idx2 );
937939
938940 // Remove pairs intersecting the just combined best pair.
939941 for (i = 0 ; i < histo_queue .size ;) {
@@ -942,14 +944,15 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
942944 p -> idx1 == idx2 || p -> idx2 == idx2 ) {
943945 HistoQueuePopPair (& histo_queue , p );
944946 } else {
947+ HistoQueueFixPair (image_histo -> size , idx2 , p );
945948 HistoQueueUpdateHead (& histo_queue , p );
946949 ++ i ;
947950 }
948951 }
949952
950953 // Push new pairs formed with combined histogram to the queue.
951954 for (i = 0 ; i < image_histo -> size ; ++ i ) {
952- if (i == idx1 || image_histo -> histograms [ i ] == NULL ) continue ;
955+ if (i == idx1 ) continue ;
953956 HistoQueuePush (& histo_queue , image_histo -> histograms , idx1 , i , 0 );
954957 }
955958 }
@@ -964,17 +967,13 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
964967// Perform histogram aggregation using a stochastic approach.
965968// 'do_greedy' is set to 1 if a greedy approach needs to be performed
966969// afterwards, 0 otherwise.
967- static int PairComparison (const void * idx1 , const void * idx2 ) {
968- // To be used with bsearch: <0 when *idx1<*idx2, >0 if >, 0 when ==.
969- return (* (int * ) idx1 - * (int * ) idx2 );
970- }
971970static int HistogramCombineStochastic (VP8LHistogramSet * const image_histo ,
972- int * const num_used , int min_cluster_size ,
971+ int min_cluster_size ,
973972 int * const do_greedy ) {
974973 int j , iter ;
975974 uint32_t seed = 1 ;
976975 int tries_with_no_success = 0 ;
977- const int outer_iters = * num_used ;
976+ const int outer_iters = image_histo -> size ;
978977 const int num_tries_no_success = outer_iters / 2 ;
979978 VP8LHistogram * * const histograms = image_histo -> histograms ;
980979 // Priority queue of histogram pairs. Its size of 'kHistoQueueSize'
@@ -983,49 +982,34 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
983982 HistoQueue histo_queue ;
984983 const int kHistoQueueSize = 9 ;
985984 int ok = 0 ;
986- // mapping from an index in image_histo with no NULL histogram to the full
987- // blown image_histo.
988- int * mappings ;
989985
990- if (* num_used < min_cluster_size ) {
986+ if (image_histo -> size < min_cluster_size ) {
991987 * do_greedy = 1 ;
992988 return 1 ;
993989 }
994990
995- mappings = (int * ) WebPSafeMalloc (* num_used , sizeof (* mappings ));
996- if (mappings == NULL ) return 0 ;
997991 if (!HistoQueueInit (& histo_queue , kHistoQueueSize )) goto End ;
998- // Fill the initial mapping.
999- for (j = 0 , iter = 0 ; iter < image_histo -> size ; ++ iter ) {
1000- if (histograms [iter ] == NULL ) continue ;
1001- mappings [j ++ ] = iter ;
1002- }
1003- assert (j == * num_used );
1004992
1005993 // Collapse similar histograms in 'image_histo'.
1006- for (iter = 0 ;
1007- iter < outer_iters && * num_used >= min_cluster_size &&
1008- ++ tries_with_no_success < num_tries_no_success ;
1009- ++ iter ) {
1010- int * mapping_index ;
994+ for (iter = 0 ; iter < outer_iters && image_histo -> size >= min_cluster_size &&
995+ ++ tries_with_no_success < num_tries_no_success ;
996+ ++ iter ) {
1011997 int64_t best_cost =
1012998 (histo_queue .size == 0 ) ? 0 : histo_queue .queue [0 ].cost_diff ;
1013999 int best_idx1 = -1 , best_idx2 = 1 ;
1014- const uint32_t rand_range = (* num_used - 1 ) * (* num_used );
1015- // (*num_used ) / 2 was chosen empirically. Less means faster but worse
1016- // compression.
1017- const int num_tries = (* num_used ) / 2 ;
1000+ const uint32_t rand_range = (image_histo -> size - 1 ) * (image_histo -> size );
1001+ // (image_histo->size ) / 2 was chosen empirically. Less means faster but
1002+ // worse compression.
1003+ const int num_tries = (image_histo -> size ) / 2 ;
10181004
10191005 // Pick random samples.
1020- for (j = 0 ; * num_used >= 2 && j < num_tries ; ++ j ) {
1006+ for (j = 0 ; image_histo -> size >= 2 && j < num_tries ; ++ j ) {
10211007 int64_t curr_cost ;
10221008 // Choose two different histograms at random and try to combine them.
10231009 const uint32_t tmp = MyRand (& seed ) % rand_range ;
1024- uint32_t idx1 = tmp / (* num_used - 1 );
1025- uint32_t idx2 = tmp % (* num_used - 1 );
1010+ uint32_t idx1 = tmp / (image_histo -> size - 1 );
1011+ uint32_t idx2 = tmp % (image_histo -> size - 1 );
10261012 if (idx2 >= idx1 ) ++ idx2 ;
1027- idx1 = mappings [idx1 ];
1028- idx2 = mappings [idx2 ];
10291013
10301014 // Calculate cost reduction on combination.
10311015 curr_cost =
@@ -1042,25 +1026,18 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
10421026 best_idx1 = histo_queue .queue [0 ].idx1 ;
10431027 best_idx2 = histo_queue .queue [0 ].idx2 ;
10441028 assert (best_idx1 < best_idx2 );
1045- // Pop best_idx2 from mappings.
1046- mapping_index = (int * ) bsearch (& best_idx2 , mappings , * num_used ,
1047- sizeof (best_idx2 ), & PairComparison );
1048- assert (mapping_index != NULL );
1049- memmove (mapping_index , mapping_index + 1 , sizeof (* mapping_index ) *
1050- ((* num_used ) - (mapping_index - mappings ) - 1 ));
10511029 // Merge the histograms and remove best_idx2 from the queue.
10521030 HistogramAdd (histograms [best_idx2 ], histograms [best_idx1 ],
10531031 histograms [best_idx1 ]);
10541032 UpdateHistogramCost (histo_queue .queue [0 ].cost_combo ,
10551033 histo_queue .queue [0 ].costs , histograms [best_idx1 ]);
1056- HistogramSetRemoveHistogram (image_histo , best_idx2 , num_used );
1034+ HistogramSetRemoveHistogram (image_histo , best_idx2 );
10571035 // Parse the queue and update each pair that deals with best_idx1,
10581036 // best_idx2 or image_histo_size.
10591037 for (j = 0 ; j < histo_queue .size ;) {
10601038 HistogramPair * const p = histo_queue .queue + j ;
10611039 const int is_idx1_best = p -> idx1 == best_idx1 || p -> idx1 == best_idx2 ;
10621040 const int is_idx2_best = p -> idx2 == best_idx1 || p -> idx2 == best_idx2 ;
1063- int do_eval = 0 ;
10641041 // The front pair could have been duplicated by a random pick so
10651042 // check for it all the time nevertheless.
10661043 if (is_idx1_best && is_idx2_best ) {
@@ -1069,38 +1046,26 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
10691046 }
10701047 // Any pair containing one of the two best indices should only refer to
10711048 // best_idx1. Its cost should also be updated.
1072- if (is_idx1_best ) {
1073- p -> idx1 = best_idx1 ;
1074- do_eval = 1 ;
1075- } else if (is_idx2_best ) {
1076- p -> idx2 = best_idx1 ;
1077- do_eval = 1 ;
1078- }
1079- // Make sure the index order is respected.
1080- if (p -> idx1 > p -> idx2 ) {
1081- const int tmp = p -> idx2 ;
1082- p -> idx2 = p -> idx1 ;
1083- p -> idx1 = tmp ;
1084- }
1085- if (do_eval ) {
1049+ if (is_idx1_best || is_idx2_best ) {
1050+ HistoQueueFixPair (best_idx2 , best_idx1 , p );
10861051 // Re-evaluate the cost of an updated pair.
10871052 if (!HistoQueueUpdatePair (histograms [p -> idx1 ], histograms [p -> idx2 ], 0 ,
10881053 p )) {
10891054 HistoQueuePopPair (& histo_queue , p );
10901055 continue ;
10911056 }
10921057 }
1058+ HistoQueueFixPair (image_histo -> size , best_idx2 , p );
10931059 HistoQueueUpdateHead (& histo_queue , p );
10941060 ++ j ;
10951061 }
10961062 tries_with_no_success = 0 ;
10971063 }
1098- * do_greedy = (* num_used <= min_cluster_size );
1064+ * do_greedy = (image_histo -> size <= min_cluster_size );
10991065 ok = 1 ;
11001066
11011067 End :
11021068 HistoQueueClear (& histo_queue );
1103- WebPSafeFree (mappings );
11041069 return ok ;
11051070}
11061071
@@ -1168,16 +1133,6 @@ static int32_t GetCombineCostFactor(int histo_size, int quality) {
11681133 return combine_cost_factor ;
11691134}
11701135
1171- static void RemoveEmptyHistograms (VP8LHistogramSet * const image_histo ) {
1172- uint32_t size ;
1173- int i ;
1174- for (i = 0 , size = 0 ; i < image_histo -> size ; ++ i ) {
1175- if (image_histo -> histograms [i ] == NULL ) continue ;
1176- image_histo -> histograms [size ++ ] = image_histo -> histograms [i ];
1177- }
1178- image_histo -> size = size ;
1179- }
1180-
11811136int VP8LGetHistoImageSymbols (int xsize , int ysize ,
11821137 const VP8LBackwardRefs * const refs , int quality ,
11831138 int low_effort , int histogram_bits , int cache_bits ,
@@ -1198,29 +1153,25 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
11981153 // maximum quality q==100 (to preserve the compression gains at that level).
11991154 const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE ;
12001155 int entropy_combine ;
1201- int num_used = image_histo_raw_size ;
12021156 if (orig_histo == NULL ) {
12031157 WebPEncodingSetError (pic , VP8_ENC_ERROR_OUT_OF_MEMORY );
12041158 goto Error ;
12051159 }
12061160
12071161 // Construct the histograms from backward references.
12081162 HistogramBuild (xsize , histogram_bits , refs , orig_histo );
1209- // Copies the histograms and computes its bit_cost.
1210- // histogram_symbols is optimized
1211- HistogramCopyAndAnalyze (orig_histo , image_histo , & num_used );
1163+ HistogramCopyAndAnalyze (orig_histo , image_histo );
12121164 entropy_combine =
1213- (num_used > entropy_combine_num_bins * 2 ) && (quality < 100 );
1165+ (image_histo -> size > entropy_combine_num_bins * 2 ) && (quality < 100 );
12141166
12151167 if (entropy_combine ) {
12161168 const int32_t combine_cost_factor =
12171169 GetCombineCostFactor (image_histo_raw_size , quality );
12181170
12191171 HistogramAnalyzeEntropyBin (image_histo , low_effort );
12201172 // Collapse histograms with similar entropy.
1221- HistogramCombineEntropyBin (image_histo , & num_used , tmp_histo ,
1222- entropy_combine_num_bins , combine_cost_factor ,
1223- low_effort );
1173+ HistogramCombineEntropyBin (image_histo , tmp_histo , entropy_combine_num_bins ,
1174+ combine_cost_factor , low_effort );
12241175 }
12251176
12261177 // Don't combine the histograms using stochastic and greedy heuristics for
@@ -1231,22 +1182,19 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
12311182 (int )(1 + DivRound (quality * quality * quality * (MAX_HISTO_GREEDY - 1 ),
12321183 100 * 100 * 100 ));
12331184 int do_greedy ;
1234- if (!HistogramCombineStochastic (image_histo , & num_used , threshold_size ,
1235- & do_greedy )) {
1185+ if (!HistogramCombineStochastic (image_histo , threshold_size , & do_greedy )) {
12361186 WebPEncodingSetError (pic , VP8_ENC_ERROR_OUT_OF_MEMORY );
12371187 goto Error ;
12381188 }
12391189 if (do_greedy ) {
1240- RemoveEmptyHistograms (image_histo );
1241- if (!HistogramCombineGreedy (image_histo , & num_used )) {
1190+ if (!HistogramCombineGreedy (image_histo )) {
12421191 WebPEncodingSetError (pic , VP8_ENC_ERROR_OUT_OF_MEMORY );
12431192 goto Error ;
12441193 }
12451194 }
12461195 }
12471196
12481197 // Find the optimal map from original histograms to the final ones.
1249- RemoveEmptyHistograms (image_histo );
12501198 HistogramRemap (orig_histo , image_histo , histogram_symbols );
12511199
12521200 if (!WebPReportProgress (pic , * percent + percent_range , percent )) {
0 commit comments