Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/huffman.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2006 Konstantin Shishkov
3
 * Copyright (c) 2007 Loren Merritt
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
/**
23
 * @file
24
 * huffman tree builder and VLC generator
25
 */
26
27
#include <stdint.h>
28
29
#include "libavutil/error.h"
30
#include "libavutil/log.h"
31
#include "libavutil/macros.h"
32
#include "libavutil/mem.h"
33
#include "libavutil/qsort.h"
34
35
#include "huffman.h"
36
#include "vlc.h"
37
38
/* symbol for Huffman tree node */
39
155M
#define HNODE -1
40
41
typedef struct HeapElem {
42
    union {
43
        uint64_t val;
44
        uint16_t dummy; // exists solely to ensure alignof(HeapElem) >= alignof(uint16_t)
45
    };
46
    int name;
47
} HeapElem;
48
49
static void heap_sift(HeapElem *h, int root, int size)
50
13.1M
{
51
119M
    while (root * 2 + 1 < size) {
52
114M
        int child = root * 2 + 1;
53
114M
        if (child < size - 1 && h[child].val > h[child+1].val)
54
53.7M
            child++;
55
114M
        if (h[root].val > h[child].val) {
56
106M
            FFSWAP(HeapElem, h[root], h[child]);
57
106M
            root = child;
58
106M
        } else
59
8.46M
            break;
60
114M
    }
61
13.1M
}
62
63
int ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats, int stats_size, int skip0)
64
27.2k
{
65
27.2k
    int *up;
66
27.2k
    uint16_t *map;
67
27.2k
    uint8_t *len;
68
27.2k
    HeapElem *h = av_malloc_array(stats_size,
69
27.2k
                                  sizeof(*h) + 2 * sizeof(up) + 2 * sizeof(len) + sizeof(map));
70
27.2k
    if (!h)
71
0
        return AVERROR(ENOMEM);
72
27.2k
    up  = (int*)(h + stats_size);
73
    // map is suitably aligned because up uses an even number of elements
74
    // and alignof(uint16_t) is either 1 or 2.
75
27.2k
    map = (uint16_t*)(up + 2 * stats_size);
76
27.2k
    len = (uint8_t*)(map + stats_size);
77
78
27.2k
    int offset, i, next;
79
27.2k
    int size = 0;
80
27.2k
    int ret = 0;
81
82
10.9M
    for (i = 0; i<stats_size; i++) {
83
10.9M
        dst[i] = 255;
84
10.9M
        if (stats[i] || !skip0)
85
5.27M
            map[size++] = i;
86
10.9M
    }
87
88
27.2k
    for (offset = 1; ; offset <<= 1) {
89
5.30M
        for (i=0; i < size; i++) {
90
5.27M
            h[i].name = i;
91
5.27M
            h[i].val = (stats[map[i]] << 14) + offset;
92
5.27M
        }
93
2.66M
        for (i = size / 2 - 1; i >= 0; i--)
94
2.63M
            heap_sift(h, i, size);
95
96
5.27M
        for (next = size; next < size * 2 - 1; next++) {
97
            // merge the two smallest entries, and put it back in the heap
98
5.25M
            uint64_t min1v = h[0].val;
99
5.25M
            up[h[0].name] = next;
100
5.25M
            h[0].val = INT64_MAX;
101
5.25M
            heap_sift(h, 0, size);
102
5.25M
            up[h[0].name] = next;
103
5.25M
            h[0].name = next;
104
5.25M
            h[0].val += min1v;
105
5.25M
            heap_sift(h, 0, size);
106
5.25M
        }
107
108
27.2k
        len[2 * size - 2] = 0;
109
5.25M
        for (i = 2 * size - 3; i >= size; i--)
110
5.22M
            len[i] = len[up[i]] + 1;
111
5.30M
        for (i = 0; i < size; i++) {
112
5.27M
            dst[map[i]] = len[up[i]] + 1;
113
5.27M
            if (dst[map[i]] >= 32) break;
114
5.27M
        }
115
27.2k
        if (i==size) break;
116
27.2k
    }
117
27.2k
    av_free(h);
118
27.2k
    return ret;
119
27.2k
}
120
121
static void get_tree_codes(int8_t *lens, uint8_t *xlat,
122
                           Node *nodes, int node, int pl, int *pos, int no_zero_count)
123
61.8M
{
124
61.8M
    int s;
125
126
61.8M
    s = nodes[node].sym;
127
61.8M
    if (s != HNODE || (no_zero_count && !nodes[node].count)) {
128
32.2M
        lens[*pos] = pl;
129
32.2M
        xlat[*pos] = s;
130
32.2M
        (*pos)++;
131
32.2M
    } else {
132
29.6M
        pl++;
133
29.6M
        get_tree_codes(lens, xlat, nodes, nodes[node].n0, pl,
134
29.6M
                       pos, no_zero_count);
135
29.6M
        get_tree_codes(lens, xlat, nodes, nodes[node].n0 + 1, pl,
136
29.6M
                       pos, no_zero_count);
137
29.6M
    }
138
61.8M
}
139
140
static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags, int nb_bits, void *logctx)
141
2.58M
{
142
2.58M
    int no_zero_count = !(flags & FF_HUFFMAN_FLAG_ZERO_COUNT);
143
2.58M
    int8_t lens[256];
144
2.58M
    uint8_t xlat[256];
145
2.58M
    int pos = 0;
146
147
2.58M
    get_tree_codes(lens, xlat, nodes, head, 0,
148
2.58M
                   &pos, no_zero_count);
149
2.58M
    return ff_vlc_init_from_lengths(vlc, nb_bits, pos, lens, 1,
150
2.58M
                                    xlat, 1, 1, 0, 0, logctx);
151
2.58M
}
152
153
154
/**
155
 * nodes size must be 2*nb_codes
156
 * first nb_codes nodes.count must be set
157
 */
158
int ff_huff_build_tree(void *logctx, VLC *vlc, int nb_codes, int nb_bits,
159
                       Node *nodes, HuffCmp cmp, int flags)
160
2.59M
{
161
2.59M
    int i, j;
162
2.59M
    int cur_node;
163
2.59M
    int64_t sum = 0;
164
165
35.1M
    for (i = 0; i < nb_codes; i++) {
166
32.5M
        nodes[i].sym = i;
167
32.5M
        nodes[i].n0 = -2;
168
32.5M
        sum += nodes[i].count;
169
32.5M
    }
170
171
2.59M
    if (sum >> 31) {
172
1.23k
        av_log(logctx, AV_LOG_ERROR,
173
1.23k
               "Too high symbol frequencies. "
174
1.23k
               "Tree construction is not possible\n");
175
1.23k
        return -1;
176
1.23k
    }
177
2.58M
    AV_QSORT(nodes, nb_codes, Node, cmp);
178
2.58M
    cur_node = nb_codes;
179
2.58M
    nodes[nb_codes*2-1].count = 0;
180
34.8M
    for (i = 0; i < nb_codes * 2 - 1; i += 2) {
181
32.2M
        uint32_t cur_count = nodes[i].count + nodes[i+1].count;
182
        // find correct place to insert new node, and
183
        // make space for the new node while at it
184
143M
        for(j = cur_node; j > i + 2; j--){
185
133M
            if(cur_count > nodes[j-1].count ||
186
112M
               (cur_count == nodes[j-1].count &&
187
18.7M
                !(flags & FF_HUFFMAN_FLAG_HNODE_FIRST)))
188
23.1M
                break;
189
110M
            nodes[j] = nodes[j - 1];
190
110M
        }
191
32.2M
        nodes[j].sym = HNODE;
192
32.2M
        nodes[j].count = cur_count;
193
32.2M
        nodes[j].n0 = i;
194
32.2M
        cur_node++;
195
32.2M
    }
196
2.58M
    if (build_huff_tree(vlc, nodes, nb_codes * 2 - 2, flags, nb_bits, logctx) < 0) {
197
251
        av_log(logctx, AV_LOG_ERROR, "Error building tree\n");
198
251
        return -1;
199
251
    }
200
2.58M
    return 0;
201
2.58M
}