History

avcodec/mjpegenc_huffman: Avoid AV_QSORT to sort entries by length

It is unnecessary, as we already have the entries sorted by probability and therefore implicitly by length. All we need on top of that to build the tree is the number of entries of a given length. Doing so gives a 3.6% speedup of ff_mjpeg_encode_huffman_close() here; it also saves about 640B of .text here. The new code puts values with higher probability to the left of the tree. The old code did not and therefore the FATE checksums needed to be updated. Due to MJPEG's 0xFF unescaping file sizes as well as file checksums needed to be updated; the decoded picture hashes stayed the same. Given that codes on the left of the tree have on average fewer bits set than codes on the right, the file sizes mostly improve (all except vsynth3-mjpeg-444).

Andreas Rheinhardt committed 1 year ago

Commit ff9f3fb1 parent c8ce9de22 files · +118 −133Browse files

Showing the changes to libavcodec/tests (1 of 22 files). Show all

Unified · Split

libavcodec/tests/mjpegenc_huffman.c+57−46
@@ -34,10 +34,9 @@ · 33 unmodified lines
34static int check_lengths(int L, const int *probs, int nprobs,34static int check_lengths(int L, const int *probs, int nprobs,
35 int expected_length, const uint8_t expected_len_counts[/* L + 1 */])35 int expected_length, const uint8_t expected_len_counts[/* L + 1 */])
36{36{
37 HuffTable lengths[256];
38 PTable val_counts[256];37 PTable val_counts[256];
39 uint8_t len_counts[17] = { 0 };38 uint8_t len_counts[17];
40 int actual_length = 0, i, j, k, prob, length;39 int actual_length = 0, i;
41 int ret = 0;40 int ret = 0;
42 av_assert0(nprobs <= 256);41 av_assert0(nprobs <= 256);
43 av_assert0(L < FF_ARRAY_ELEMS(len_counts));42 av_assert0(L < FF_ARRAY_ELEMS(len_counts));
@@ -46,20 +45,12 @@ static int check_lengths(int L, const int *probs, int nprobs, · 2 unmodified lines
46 val_counts[i] = (PTable){.value = i, .prob = probs[i]};45 val_counts[i] = (PTable){.value = i, .prob = probs[i]};
47 }46 }
48 47
49 mjpegenc_huffman_compute_bits(val_counts, lengths, nprobs, L);48 mjpegenc_huffman_compute_bits(val_counts, len_counts, nprobs, L);
50 49
51 for (int i = 0; i < nprobs; ++i) {
52 if (lengths[i].length > L) {
53 fprintf(stderr,
54 "Len %d of element %d of Huffman table with %d elements exceeds max length %d\n",
55 lengths[i].length, i, nprobs, L);
56 return 1;
57 }
58 len_counts[lengths[i].length]++;
59 }
60 // Test that the lengths can be made part of a complete, prefix-free tree:50 // Test that the lengths can be made part of a complete, prefix-free tree:
61 unsigned code = 0;51 unsigned code = 0, count = 0;
62 for (int i = 1; i <= L; ++i) {52 for (int i = 1; i <= L; ++i) {
53 count += len_counts[i];
63 code <<= 1;54 code <<= 1;
64 code += len_counts[i];55 code += len_counts[i];
65 }56 }
@@ -67,22 +58,36 @@ static int check_lengths(int L, const int *probs, int nprobs, · 1 unmodified line
67 fprintf(stderr, "Huffman tree overdetermined/invalid\n");58 fprintf(stderr, "Huffman tree overdetermined/invalid\n");
68 ret = 1;59 ret = 1;
69 }60 }
70 61 if (count != nprobs) {
71 for (i = 0; i < nprobs; i++) {62 fprintf(stderr, "Total count %u does not match expected value %d\n",
72 // Find the value's prob and length63 count, nprobs);
73 for (j = 0; j < nprobs; j++)64 ret = 1;
74 if (val_counts[j].value == i) break;65 }
75 for (k = 0; k < nprobs; k++)66 // Test that the input values have been properly ordered.
76 if (lengths[k].code == i) break;67 for (unsigned i = 0; i < count; ++i) {
77 if (!(j < nprobs && k < nprobs)) return 1;68 if (val_counts[i].prob != probs[val_counts[i].value]) {
78 prob = val_counts[j].prob;69 fprintf(stderr, "PTable not properly reordered\n");
79 length = lengths[k].length;70 ret = 1;
80 71 }
81 if (prob) {72 if (i && val_counts[i - 1].prob > val_counts[i].prob) {
82 actual_length += prob * length;73 fprintf(stderr, "PTable not order ascendingly: [%u] = %d > [%u] = %d\n",
74 i - 1, val_counts[i - 1].prob, i, val_counts[i].prob);
75 ret = 1;
76 }
77 unsigned j;
78 for (j = 0; j < count; ++j)
79 if (val_counts[j].value == i)
80 break;
81 if (j >= count) {
82 fprintf(stderr, "Element %u missing after sorting\n", i);
83 ret = 1;
83 }84 }
84 85 }
85 if (length > L || length < 1) return 1;86 for (int len = L, j = 0; len; --len) {
87 int prob = 0;
88 for (int end = j + len_counts[len]; j < end; ++j)
89 prob += val_counts[j].prob;
90 actual_length += prob * len;
86 }91 }
87 // Check that the total length is optimal92 // Check that the total length is optimal
88 if (actual_length != expected_length) ret = 1;93 if (actual_length != expected_length) ret = 1;
@@ -141,7 +146,10 @@ static const uint8_t len_counts_sat[] = { · 52 unmodified lines
141// http://guru.multimedia.cx/small-tasks-for-ffmpeg/146// http://guru.multimedia.cx/small-tasks-for-ffmpeg/
142int main(int argc, char **argv)147int main(int argc, char **argv)
143{148{
144 int i, ret = 0;149 enum {
150 MAX_LEN = 3,
151 };
152 int ret = 0;
145 // Probabilities of symbols 0..4153 // Probabilities of symbols 0..4
146 PTable val_counts[] = {154 PTable val_counts[] = {
147 {.value = 0, .prob = 1},155 {.value = 0, .prob = 1},
@@ -151,30 +159,33 @@ int main(int argc, char **argv) · 3 unmodified lines
151 {.value = 4, .prob = 21},159 {.value = 4, .prob = 21},
152 };160 };
153 // Expected code lengths for each symbol161 // Expected code lengths for each symbol
154 static const HuffTable expected[] = {162 static const uint8_t expected[MAX_LEN + 1] = {
155 {.code = 0, .length = 3},163 [1] = 1, [3] = 4,
156 {.code = 1, .length = 3},
157 {.code = 2, .length = 3},
158 {.code = 3, .length = 3},
159 {.code = 4, .length = 1},
160 };164 };
161 // Actual code lengths165 // Actual code lengths
162 HuffTable distincts[5];166 uint8_t len_counts[MAX_LEN + 1];
163 167
164 // Build optimal huffman tree using an internal function, to allow for168 // Build optimal huffman tree using an internal function, to allow for
165 // smaller-than-normal test cases. This mutates val_counts by sorting.169 // smaller-than-normal test cases. This mutates val_counts by sorting.
166 mjpegenc_huffman_compute_bits(val_counts, distincts,170 mjpegenc_huffman_compute_bits(val_counts, len_counts,
167 FF_ARRAY_ELEMS(distincts), 3);171 FF_ARRAY_ELEMS(val_counts), MAX_LEN);
168 172
169 for (i = 0; i < FF_ARRAY_ELEMS(distincts); i++) {173 for (unsigned i = 1; i < FF_ARRAY_ELEMS(len_counts); i++) {
170 if (distincts[i].code != expected[i].code ||174 if (len_counts[i] != expected[i]) {
171 distincts[i].length != expected[i].length) {
172 fprintf(stderr,175 fprintf(stderr,
173 "Built huffman does not equal expectations. "176 "Built huffman does not equal expectations. "
174 "Expected: code %d probability %d, "177 "Expected: %d codes of length %u, "
175 "Actual: code %d probability %d\n",178 "Actual: %d codes of length %u\n",
176 expected[i].code, expected[i].length,179 (int)expected[i], i,
177 distincts[i].code, distincts[i].length);180 (int)len_counts[i], i);
181 ret = 1;
182 }
183 }
184 for (unsigned i = 1; i < FF_ARRAY_ELEMS(val_counts); ++i) {
185 if (val_counts[i - 1].prob > val_counts[i].prob) {
186 fprintf(stderr, "Probability table not ordered ascendingly. "
187 "val_counts[%u] == %d, val_counts[%u] == %d\n",
188 i - 1, val_counts[i - 1].prob, i, val_counts[i].prob);
178 ret = 1;189 ret = 1;
179 }190 }
180 }191 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t