static int quantize(CinepakEncContext *s, int h, AVPicture *pict,
                    int v1mode, strip_info *info,
                    mb_encoding encoding)
{
    int x, y, i, j, k, x2, y2, x3, y3, plane, shift, mbn;
    int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
    int *codebook = v1mode ? info->v1_codebook : info->v4_codebook;
    int size = v1mode ? info->v1_size : info->v4_size;
    int64_t total_error = 0;
    uint8_t vq_pict_buf[(MB_AREA*3)/2];
    AVPicture sub_pict, vq_pict;

    for(mbn = i = y = 0; y < h; y += MB_SIZE) {
        for(x = 0; x < s->w; x += MB_SIZE, ++mbn) {
            int *base;

            if(CERTAIN(encoding)) {
// use for the training only the blocks known to be to be encoded [sic:-]
               if(s->mb[mbn].best_encoding != encoding) continue;
            }

            base = s->codebook_input + i*entry_size;
            if(v1mode) {
                //subsample
                for(j = y2 = 0; y2 < entry_size; y2 += 2) {
                    for(x2 = 0; x2 < 4; x2 += 2, j++) {
                        plane = y2 < 4 ? 0 : 1 + (x2 >> 1);
                        shift = y2 < 4 ? 0 : 1;
                        x3 = shift ? 0 : x2;
                        y3 = shift ? 0 : y2;
                        base[j] = (pict->data[plane][((x+x3) >> shift) +      ((y+y3) >> shift)      * pict->linesize[plane]] +
                                   pict->data[plane][((x+x3) >> shift) + 1 +  ((y+y3) >> shift)      * pict->linesize[plane]] +
                                   pict->data[plane][((x+x3) >> shift) +     (((y+y3) >> shift) + 1) * pict->linesize[plane]] +
                                   pict->data[plane][((x+x3) >> shift) + 1 + (((y+y3) >> shift) + 1) * pict->linesize[plane]]) >> 2;
                    }
                }
            } else {
                //copy
                for(j = y2 = 0; y2 < MB_SIZE; y2 += 2) {
                    for(x2 = 0; x2 < MB_SIZE; x2 += 2) {
                        for(k = 0; k < entry_size; k++, j++) {
                            plane = k >= 4 ? k - 3 : 0;

                            if(k >= 4) {
                                x3 = (x+x2) >> 1;
                                y3 = (y+y2) >> 1;
                            } else {
                                x3 = x + x2 + (k & 1);
                                y3 = y + y2 + (k >> 1);
                            }

                            base[j] = pict->data[plane][x3 + y3*pict->linesize[plane]];
                        }
                    }
                }
            }
            i += v1mode ? 1 : 4;
        }
    }
//    if(i < mbn*(v1mode ? 1 : 4)) {
//        av_log(s->avctx, AV_LOG_INFO, "reducing training set for %s from %i to %i (encoding %i)\n", v1mode?"v1":"v4", mbn*(v1mode ? 1 : 4), i, encoding);
//    }

    if(i == 0) // empty training set, nothing to do
        return 0;
    if(i < size) {
        //av_log(s->avctx, (CERTAIN(encoding) ? AV_LOG_ERROR : AV_LOG_INFO), "WOULD WASTE: %s cbsize %i bigger than training set size %i (encoding %i)\n", v1mode?"v1":"v4", size, i, encoding);
        size = i;
    }

    ff_init_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx);
    ff_do_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx);

    //setup vq_pict, which contains a single MB
    vq_pict.data[0] = vq_pict_buf;
    vq_pict.linesize[0] = MB_SIZE;
    vq_pict.data[1] = &vq_pict_buf[MB_AREA];
    vq_pict.data[2] = vq_pict.data[1] + (MB_AREA >> 2);
    vq_pict.linesize[1] = vq_pict.linesize[2] = MB_SIZE >> 1;

    //copy indices
    for(i = j = y = 0; y < h; y += MB_SIZE) {
        for(x = 0; x < s->w; x += MB_SIZE, j++) {
            mb_info *mb = &s->mb[j];
// skip uninteresting blocks if we know their preferred encoding
            if(CERTAIN(encoding) && mb->best_encoding != encoding)
                continue;

            //point sub_pict to current MB
            get_sub_picture(s, x, y, pict, &sub_pict);

            if(v1mode) {
                mb->v1_vector = s->codebook_closest[i];

                //fill in vq_pict with V1 data
                decode_v1_vector(s, &vq_pict, mb->v1_vector, info);

                mb->v1_error = compute_mb_distortion(s, &sub_pict, &vq_pict);
                total_error += mb->v1_error;
            } else {
                for(k = 0; k < 4; k++)
                    mb->v4_vector[k] = s->codebook_closest[i+k];

                //fill in vq_pict with V4 data
                decode_v4_vector(s, &vq_pict, mb->v4_vector, info);

                mb->v4_error = compute_mb_distortion(s, &sub_pict, &vq_pict);
                total_error += mb->v4_error;
            }
            i += v1mode ? 1 : 4;
        }
    }
// check that we did it right in the beginning of the function
    av_assert0(i >= size); // training set is no smaller than the codebook

    //av_log(s->avctx, AV_LOG_INFO, "isv1 %i size= %i i= %i error %lli\n", v1mode, size, i, (long long int)total_error);

    return size;
}