FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
mjpegenc_huffman.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 William Ma, Sofia Kim, Dustin Woo
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Optimal Huffman Encoding tests.
24  */
25 
26 #include <stdio.h>
27 
28 #include "libavutil/avassert.h"
29 #include "libavutil/macros.h"
30 
32 
33 // Validate the computed lengths satisfy the JPEG restrictions and is optimal.
34 static int check_lengths(int L, const int *probs, int nprobs,
35  int expected_length, const uint8_t expected_len_counts[/* L + 1 */])
36 {
37  PTable val_counts[256];
38  uint8_t len_counts[17];
39  int actual_length = 0, i;
40  int ret = 0;
41  av_assert0(nprobs <= 256);
42  av_assert0(L < FF_ARRAY_ELEMS(len_counts));
43 
44  for (i = 0; i < nprobs; i++) {
45  val_counts[i] = (PTable){.value = i, .prob = probs[i]};
46  }
47 
48  mjpegenc_huffman_compute_bits(val_counts, len_counts, nprobs, L);
49 
50  // Test that the lengths can be made part of a complete, prefix-free tree:
51  unsigned code = 0, count = 0;
52  for (int i = 1; i <= L; ++i) {
53  count += len_counts[i];
54  code <<= 1;
55  code += len_counts[i];
56  }
57  if (code > 1U << L) {
58  fprintf(stderr, "Huffman tree overdetermined/invalid\n");
59  ret = 1;
60  }
61  if (count != nprobs) {
62  fprintf(stderr, "Total count %u does not match expected value %d\n",
63  count, nprobs);
64  ret = 1;
65  }
66  // Test that the input values have been properly ordered.
67  for (unsigned i = 0; i < count; ++i) {
68  if (val_counts[i].prob != probs[val_counts[i].value]) {
69  fprintf(stderr, "PTable not properly reordered\n");
70  ret = 1;
71  }
72  if (i && val_counts[i - 1].prob > val_counts[i].prob) {
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;
84  }
85  }
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;
91  }
92  // Check that the total length is optimal
93  if (actual_length != expected_length) ret = 1;
94 
95  if (ret == 1) {
96  fprintf(stderr,
97  "Actual length: %d\n"
98  "Expected length: %d\n",
99  actual_length, expected_length);
100  }
101 
102  return ret;
103 }
104 
105 static const int probs_zeroes[] = {
106  6, 6, 0, 0, 0
107 };
108 static const uint8_t len_counts_zeroes[] = {
109  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
110 };
111 
112 static const int probs_skewed[] = {
113  2, 0, 0, 0, 0, 1, 0, 0, 20, 0, 2, 0, 10, 5, 1, 1, 9, 1, 1, 6, 0, 5, 0, 1, 0, 7, 6,
114  1, 1, 5, 0, 0, 0, 0, 11, 0, 0, 0, 51, 1, 0, 20, 0, 1, 0, 0, 0, 0, 6, 106, 1, 0, 1,
115  0, 2, 1, 16, 0, 0, 5, 0, 0, 0, 4, 3, 15, 4, 4, 0, 0, 0, 3, 0, 0, 1, 0, 3, 0, 3, 2,
116  2, 0, 0, 4, 3, 40, 1, 2, 0, 22, 0, 0, 0, 9, 0, 0, 0, 0, 1, 1, 0, 1, 6, 11, 4, 10,
117  28, 6, 1, 0, 0, 9, 9, 4, 0, 0, 0, 0, 8, 33844, 2, 0, 2, 1, 1, 5, 0, 0, 1, 9, 1, 0,
118  4, 14, 4, 0, 0, 3, 8, 0, 51, 9, 6, 1, 1, 2, 2, 3, 1, 5, 5, 29, 0, 0, 0, 0, 14, 29,
119  6, 4, 13, 12, 2, 3, 1, 0, 5, 4, 1, 1, 0, 0, 29, 1, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1,
120  7, 0, 42, 0, 0, 0, 0, 0, 2, 0, 3, 9, 0, 0, 0, 2, 1, 0, 0, 6, 5, 6, 1, 2, 3, 0, 0,
121  0, 3, 0, 0, 28, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 23, 0, 0, 0, 0,
122  0, 21, 1, 0, 3, 24, 2, 0, 0, 7, 0, 0, 1, 5, 1, 2, 0, 5
123 };
124 static const uint8_t len_counts_skewed[] = {
125  0, 1, 0, 0, 1, 2, 7, 11, 18, 31, 28, 40, 0, 1, 0, 0, 116,
126 };
127 
128 static const int probs_sat[] = {
129  74, 8, 14, 7, 9345, 40, 0, 2014, 2, 1, 115, 0, 2, 1, 194, 388, 20, 0, 0, 2, 1, 121,
130  1, 1583, 0, 16, 21, 2, 132, 2, 15, 9, 13, 1, 0, 2293, 2, 8, 5, 2, 30, 0, 0, 4, 54,
131  783, 4, 1, 2, 4, 0, 22, 93, 1, 143, 19, 0, 36, 32, 4, 6, 33, 3, 45, 0, 8, 1, 0, 18,
132  17, 1, 0, 1, 0, 0, 1, 1004, 38, 3, 8, 90, 23, 0, 2819, 3, 0, 970, 158, 9, 6, 4, 48,
133  4, 0, 1, 0, 0, 60, 3, 62, 0, 2, 2, 2, 279, 66, 16, 1, 20, 0, 7, 9, 32, 1411, 6, 3,
134  27, 1, 5, 49, 0, 0, 0, 0, 0, 2, 10, 1, 1, 2, 3, 801, 3, 25, 5, 1, 1, 0, 632, 0, 14,
135  18, 5, 8, 200, 4, 4, 22, 12, 0, 4, 1, 0, 2, 4, 9, 3, 16, 7, 2, 2, 213, 0, 2, 620,
136  39303, 0, 1, 0, 2, 1, 183781, 1, 0, 0, 0, 94, 7, 3, 4, 0, 4, 306, 43, 352, 76, 34,
137  13, 11, 0, 51, 1, 13, 19, 0, 26, 0, 7276, 4, 207, 31, 1, 2, 4, 6, 19, 8, 17, 4, 6,
138  0, 1085, 0, 0, 0, 3, 489, 36, 1, 0, 1, 9420, 294, 28, 0, 57, 5, 0, 9, 2, 0, 1, 2,
139  2, 0, 0, 9, 2, 29, 2, 2, 7, 0, 5, 490, 0, 7, 5, 0, 1, 8, 0, 0, 23255, 0, 1
140 };
141 static const uint8_t len_counts_sat[] = {
142  0, 1, 0, 2, 1, 2, 2, 5, 5, 7, 7, 8, 17, 23, 16, 24, 136,
143 };
144 
145 // Test the example given on @see
146 // http://guru.multimedia.cx/small-tasks-for-ffmpeg/
147 int main(int argc, char **argv)
148 {
149  enum {
150  MAX_LEN = 3,
151  };
152  int ret = 0;
153  // Probabilities of symbols 0..4
154  PTable val_counts[] = {
155  {.value = 0, .prob = 1},
156  {.value = 1, .prob = 2},
157  {.value = 2, .prob = 5},
158  {.value = 3, .prob = 10},
159  {.value = 4, .prob = 21},
160  };
161  // Expected code lengths for each symbol
162  static const uint8_t expected[MAX_LEN + 1] = {
163  [1] = 1, [3] = 4,
164  };
165  // Actual code lengths
166  uint8_t len_counts[MAX_LEN + 1];
167 
168  // Build optimal huffman tree using an internal function, to allow for
169  // smaller-than-normal test cases. This mutates val_counts by sorting.
170  mjpegenc_huffman_compute_bits(val_counts, len_counts,
171  FF_ARRAY_ELEMS(val_counts), MAX_LEN);
172 
173  for (unsigned i = 1; i < FF_ARRAY_ELEMS(len_counts); i++) {
174  if (len_counts[i] != expected[i]) {
175  fprintf(stderr,
176  "Built huffman does not equal expectations. "
177  "Expected: %d codes of length %u, "
178  "Actual: %d codes of length %u\n",
179  (int)expected[i], i,
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);
189  ret = 1;
190  }
191  }
192 
193  // Check handling of zero probabilities
195  ret = 1;
196  // Check skewed distribution over 256 without saturated lengths
198  ret = 1;
199  // Check skewed distribution over 256 with saturated lengths
201  ret = 1;
202 
203  return ret;
204 }
len_counts_zeroes
static const uint8_t len_counts_zeroes[]
Definition: mjpegenc_huffman.c:108
main
int main(int argc, char **argv)
Definition: mjpegenc_huffman.c:147
macros.h
avassert.h
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
len_counts_sat
static const uint8_t len_counts_sat[]
Definition: mjpegenc_huffman.c:141
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
PTable
Used to assign a occurrence count or "probability" to an input value.
Definition: magicyuvenc.c:51
mjpegenc_huffman.c
PTable::value
int value
input value
Definition: magicyuvenc.c:52
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
code
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
Definition: filter_design.txt:178
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
len
int len
Definition: vorbis_enc_data.h:426
probs_zeroes
static const int probs_zeroes[]
Definition: mjpegenc_huffman.c:105
len_counts_skewed
static const uint8_t len_counts_skewed[]
Definition: mjpegenc_huffman.c:124
ret
ret
Definition: filter_design.txt:187
prob
#define prob(name, subs,...)
Definition: cbs_vp9.c:325
U
#define U(x)
Definition: vpx_arith.h:37
mjpegenc_huffman_compute_bits
static void mjpegenc_huffman_compute_bits(PTable *prob_table, uint8_t counts[], int size, int max_length)
Computes the length of the Huffman encoding for each distinct input value.
Definition: mjpegenc_huffman.c:81
L
#define L(x)
Definition: vpx_arith.h:36
probs_sat
static const int probs_sat[]
Definition: mjpegenc_huffman.c:128
check_lengths
static int check_lengths(int L, const int *probs, int nprobs, int expected_length, const uint8_t expected_len_counts[])
Definition: mjpegenc_huffman.c:34
probs_skewed
static const int probs_skewed[]
Definition: mjpegenc_huffman.c:112