static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,

                        uint8_t *decoded, int stride, int level,

                        int threshold, int lambda, int intra)

{

    int count, y, x, i, j, split, best_mean, best_score, best_count;

    int best_vector[6];

    int block_sum[7] = { 0, 0, 0, 0, 0, 0 };

    int w            = 2 << (level + 2 >> 1);

    int h            = 2 << (level + 1 >> 1);

    int size         = w * h;

    int16_t (*block)[256] = s->encoded_block_levels[level];

    const int8_t *codebook_sum, *codebook;

    const uint16_t(*mean_vlc)[2];

    const uint8_t(*multistage_vlc)[2];



    best_score = 0;

    // FIXME: Optimize, this does not need to be done multiple times.

    if (intra) {

        codebook_sum   = svq1_intra_codebook_sum[level];

        codebook       = ff_svq1_intra_codebooks[level];

        mean_vlc       = ff_svq1_intra_mean_vlc;

        multistage_vlc = ff_svq1_intra_multistage_vlc[level];

        for (y = 0; y < h; y++) {

            for (x = 0; x < w; x++) {

                int v = src[x + y * stride];

                block[0][x + w * y] = v;

                best_score         += v * v;

                block_sum[0]       += v;

            }

        }

    } else {

        codebook_sum   = svq1_inter_codebook_sum[level];

        codebook       = ff_svq1_inter_codebooks[level];

        mean_vlc       = ff_svq1_inter_mean_vlc + 256;

        multistage_vlc = ff_svq1_inter_multistage_vlc[level];

        for (y = 0; y < h; y++) {

            for (x = 0; x < w; x++) {

                int v = src[x + y * stride] - ref[x + y * stride];

                block[0][x + w * y] = v;

                best_score         += v * v;

                block_sum[0]       += v;

            }

        }

    }



    best_count  = 0;

    best_score -= (int)((unsigned)block_sum[0] * block_sum[0] >> (level + 3));

    best_mean   = block_sum[0] + (size >> 1) >> (level + 3);



    if (level < 4) {

        for (count = 1; count < 7; count++) {

            int best_vector_score = INT_MAX;

            int best_vector_sum   = -999, best_vector_mean = -999;

            const int stage       = count - 1;

            const int8_t *vector;



            for (i = 0; i < 16; i++) {

                int sum = codebook_sum[stage * 16 + i];

                int sqr, diff, score;



                vector = codebook + stage * size * 16 + i * size;

                sqr    = s->ssd_int8_vs_int16(vector, block[stage], size);

                diff   = block_sum[stage] - sum;

                score  = sqr - (diff * (int64_t)diff >> (level + 3)); // FIXME: 64bit slooow

                if (score < best_vector_score) {

                    int mean = diff + (size >> 1) >> (level + 3);

                    av_assert2(mean > -300 && mean < 300);

                    mean               = av_clip(mean, intra ? 0 : -256, 255);

                    best_vector_score  = score;

                    best_vector[stage] = i;

                    best_vector_sum    = sum;

                    best_vector_mean   = mean;

                }

            }

            av_assert0(best_vector_mean != -999);

            vector = codebook + stage * size * 16 + best_vector[stage] * size;

            for (j = 0; j < size; j++)

                block[stage + 1][j] = block[stage][j] - vector[j];

            block_sum[stage + 1] = block_sum[stage] - best_vector_sum;

            best_vector_score   += lambda *

                                   (+1 + 4 * count +

                                    multistage_vlc[1 + count][1]

                                    + mean_vlc[best_vector_mean][1]);



            if (best_vector_score < best_score) {

                best_score = best_vector_score;

                best_count = count;

                best_mean  = best_vector_mean;

            }

        }

    }



    split = 0;

    if (best_score > threshold && level) {

        int score  = 0;

        int offset = level & 1 ? stride * h / 2 : w / 2;

        PutBitContext backup[6];



        for (i = level - 1; i >= 0; i--)

            backup[i] = s->reorder_pb[i];

        score += encode_block(s, src, ref, decoded, stride, level - 1,

                              threshold >> 1, lambda, intra);

        score += encode_block(s, src + offset, ref + offset, decoded + offset,

                              stride, level - 1, threshold >> 1, lambda, intra);

        score += lambda;



        if (score < best_score) {

            best_score = score;

            split      = 1;

        } else {

            for (i = level - 1; i >= 0; i--)

                s->reorder_pb[i] = backup[i];

        }

    }

    if (level > 0)

        put_bits(&s->reorder_pb[level], 1, split);



    if (!split) {

        av_assert1(best_mean >= 0 && best_mean < 256 || !intra);

        av_assert1(best_mean >= -256 && best_mean < 256);

        av_assert1(best_count >= 0 && best_count < 7);

        av_assert1(level < 4 || best_count == 0);



        /* output the encoding */

        put_bits(&s->reorder_pb[level],

                 multistage_vlc[1 + best_count][1],

                 multistage_vlc[1 + best_count][0]);

        put_bits(&s->reorder_pb[level], mean_vlc[best_mean][1],

                 mean_vlc[best_mean][0]);



        for (i = 0; i < best_count; i++) {

            av_assert2(best_vector[i] >= 0 && best_vector[i] < 16);

            put_bits(&s->reorder_pb[level], 4, best_vector[i]);

        }



        for (y = 0; y < h; y++)

            for (x = 0; x < w; x++)

                decoded[x + y * stride] = src[x + y * stride] -

                                          block[best_count][x + w * y] +

                                          best_mean;

    }



    return best_score;

}
