int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
                       const void *bits, int bits_wrap, int bits_size,
                       const void *codes, int codes_wrap, int codes_size,
                       const void *symbols, int symbols_wrap, int symbols_size,
                       int flags)
{
    VLCcode *buf;
    int i, j, ret;

    vlc->bits = nb_bits;
    if (flags & INIT_VLC_USE_NEW_STATIC) {
        VLC dyn_vlc = *vlc;

        if (vlc->table_size)
            return 0;

        ret = ff_init_vlc_sparse(&dyn_vlc, nb_bits, nb_codes,
                                 bits, bits_wrap, bits_size,
                                 codes, codes_wrap, codes_size,
                                 symbols, symbols_wrap, symbols_size,
                                 flags & ~INIT_VLC_USE_NEW_STATIC);
        av_assert0(ret >= 0);
        av_assert0(dyn_vlc.table_size <= vlc->table_allocated);
        if (dyn_vlc.table_size < vlc->table_allocated)
            av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n", dyn_vlc.table_size, vlc->table_allocated);
        memcpy(vlc->table, dyn_vlc.table, dyn_vlc.table_size * sizeof(*vlc->table));
        vlc->table_size = dyn_vlc.table_size;
        ff_free_vlc(&dyn_vlc);
        return 0;
    } else {
        vlc->table           = NULL;
        vlc->table_allocated = 0;
        vlc->table_size      = 0;
    }

    av_dlog(NULL, "build table nb_codes=%d\n", nb_codes);

    buf = av_malloc((nb_codes + 1) * sizeof(VLCcode));
    if (!buf)
        return AVERROR(ENOMEM);

    av_assert0(symbols_size <= 2 || !symbols);
    j = 0;
#define COPY(condition)\
    for (i = 0; i < nb_codes; i++) {                                        \
        GET_DATA(buf[j].bits, bits, i, bits_wrap, bits_size);               \
        if (!(condition))                                                   \
            continue;                                                       \
        if (buf[j].bits > 3*nb_bits || buf[j].bits>32) {                    \
            av_log(NULL, AV_LOG_ERROR, "Too long VLC (%d) in init_vlc\n", buf[j].bits);\
            av_free(buf);                                                   \
            return -1;                                                      \
        }                                                                   \
        GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size);            \
        if (buf[j].code >= (1LL<<buf[j].bits)) {                            \
            av_log(NULL, AV_LOG_ERROR, "Invalid code in init_vlc\n");       \
            av_free(buf);                                                   \
            return -1;                                                      \
        }                                                                   \
        if (flags & INIT_VLC_LE)                                            \
            buf[j].code = bitswap_32(buf[j].code);                          \
        else                                                                \
            buf[j].code <<= 32 - buf[j].bits;                               \
        if (symbols)                                                        \
            GET_DATA(buf[j].symbol, symbols, i, symbols_wrap, symbols_size) \
        else                                                                \
            buf[j].symbol = i;                                              \
        j++;                                                                \
    }
    COPY(buf[j].bits > nb_bits);
    // qsort is the slowest part of init_vlc, and could probably be improved or avoided
    qsort(buf, j, sizeof(VLCcode), compare_vlcspec);
    COPY(buf[j].bits && buf[j].bits <= nb_bits);
    nb_codes = j;

    ret = build_table(vlc, nb_bits, nb_codes, buf, flags);

    av_free(buf);
    if (ret < 0) {
        av_freep(&vlc->table);
        return ret;
    }
    return 0;
}