Exemple #1
0
static void pred4x4_vertical_vp8_c(uint8_t *src, const uint8_t *topright, int stride){
    const unsigned lt = src[-1-1*stride];
    LOAD_TOP_EDGE
    LOAD_TOP_RIGHT_EDGE
    uint32_t v = PACK_4U8((lt + 2*t0 + t1 + 2) >> 2,
                          (t0 + 2*t1 + t2 + 2) >> 2,
                          (t1 + 2*t2 + t3 + 2) >> 2,
                          (t2 + 2*t3 + t4 + 2) >> 2);

    AV_WN32A(src+0*stride, v);
    AV_WN32A(src+1*stride, v);
    AV_WN32A(src+2*stride, v);
    AV_WN32A(src+3*stride, v);
}
Exemple #2
0
static void dca_qmf_32_subbands(float samples_in[32][8], int sb_act,
                                SynthFilterContext *synth, FFTContext *imdct,
                                float synth_buf_ptr[512],
                                int *synth_buf_offset, float synth_buf2[32],
                                const float window[512], float *samples_out,
                                float raXin[32], float scale)
{
    int i;
    int subindex;

    for (i = sb_act; i < 32; i++)
        raXin[i] = 0.0;

    /* Reconstructed channel sample index */
    for (subindex = 0; subindex < 8; subindex++) {
        /* Load in one sample from each subband and clear inactive subbands */
        for (i = 0; i < sb_act; i++) {
            unsigned sign = (i - 1) & 2;
            uint32_t v    = AV_RN32A(&samples_in[i][subindex]) ^ sign << 30;
            AV_WN32A(&raXin[i], v);
        }

        synth->synth_filter_float(imdct, synth_buf_ptr, synth_buf_offset,
                                  synth_buf2, window, samples_out, raXin,
                                  scale);
        samples_out += 32;
    }
}
Exemple #3
0
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
{
    AVFilterContext *ctx = inlink->dst;
    AVFilterLink *outlink = ctx->outputs[0];
    ShowVolumeContext *s = ctx->priv;
    int c, i, j, k;
    double values[VAR_VARS_NB];

    if (!s->out || s->out->width  != outlink->w ||
                   s->out->height != outlink->h) {
        av_frame_free(&s->out);
        s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
        if (!s->out) {
            av_frame_free(&insamples);
            return AVERROR(ENOMEM);
        }

        for (i = 0; i < outlink->h; i++)
            memset(s->out->data[0] + i * s->out->linesize[0], 0, outlink->w * 4);
    }
    s->out->pts = insamples->pts;

    for (j = 0; j < outlink->h; j++) {
        uint8_t *dst = s->out->data[0] + j * s->out->linesize[0];
        for (k = 0; k < s->w; k++) {
            dst[k * 4 + 0] = FFMAX(dst[k * 4 + 0] - s->f, 0);
            dst[k * 4 + 1] = FFMAX(dst[k * 4 + 1] - s->f, 0);
            dst[k * 4 + 2] = FFMAX(dst[k * 4 + 2] - s->f, 0);
            dst[k * 4 + 3] = FFMAX(dst[k * 4 + 3] - s->f, 0);
        }
    }

    for (c = 0; c < inlink->channels; c++) {
        float *src = (float *)insamples->extended_data[c];
        float max = 0;
        int color;

        for (i = 0; i < insamples->nb_samples; i++)
            max = FFMAX(max, src[i]);

        max = av_clipf(max, 0, 1);
        values[VAR_VOLUME] = 20.0 * log(max) / M_LN10;
        color = av_expr_eval(s->c_expr, values, NULL);

        for (j = 0; j < s->h; j++) {
            uint8_t *dst = s->out->data[0] + (c * s->h + c * s->b + j) * s->out->linesize[0];

            for (k = 0; k < s->w * max; k++)
                AV_WN32A(dst + k * 4, color);
        }

        if (s->h >= 8 && s->draw_text)
            drawtext(s->out, 2, c * (s->h + s->b) + (s->h - 8) / 2,
                     av_get_channel_name(av_channel_layout_extract_channel(insamples->channel_layout, c)));
    }

    av_frame_free(&insamples);

    return ff_filter_frame(outlink, av_frame_clone(s->out));
}
Exemple #4
0
static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                            AVPacket *avpkt) {
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
    PCXContext * const s = avctx->priv_data;
    AVFrame *picture = data;
    AVFrame * const p = &s->picture;
    int compressed, xmin, ymin, xmax, ymax;
    unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
                 bytes_per_scanline;
    uint8_t *ptr;
    uint8_t const *bufstart = buf;
    uint8_t *scanline;
    int ret = -1;

    if (buf[0] != 0x0a || buf[1] > 5) {
        av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
        return -1;
    }

    compressed = buf[2];
    xmin = AV_RL16(buf+ 4);
    ymin = AV_RL16(buf+ 6);
    xmax = AV_RL16(buf+ 8);
    ymax = AV_RL16(buf+10);

    if (xmax < xmin || ymax < ymin) {
        av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
        return -1;
    }

    w = xmax - xmin + 1;
    h = ymax - ymin + 1;

    bits_per_pixel     = buf[3];
    bytes_per_line     = AV_RL16(buf+66);
    nplanes            = buf[65];
    bytes_per_scanline = nplanes * bytes_per_line;

    if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) {
        av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
        return -1;
    }

    switch ((nplanes<<8) + bits_per_pixel) {
        case 0x0308:
            avctx->pix_fmt = PIX_FMT_RGB24;
            break;
        case 0x0108:
        case 0x0104:
        case 0x0102:
        case 0x0101:
        case 0x0401:
        case 0x0301:
        case 0x0201:
            avctx->pix_fmt = PIX_FMT_PAL8;
            break;
        default:
            av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n");
            return -1;
    }

    buf += 128;

    if (p->data[0])
        avctx->release_buffer(avctx, p);

    if (av_image_check_size(w, h, 0, avctx))
        return -1;
    if (w != avctx->width || h != avctx->height)
        avcodec_set_dimensions(avctx, w, h);
    if (avctx->get_buffer(avctx, p) < 0) {
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return -1;
    }

    p->pict_type = AV_PICTURE_TYPE_I;

    ptr    = p->data[0];
    stride = p->linesize[0];

    scanline = av_malloc(bytes_per_scanline);
    if (!scanline)
        return AVERROR(ENOMEM);

    if (nplanes == 3 && bits_per_pixel == 8) {
        for (y=0; y<h; y++) {
            buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++) {
                ptr[3*x  ] = scanline[x                    ];
                ptr[3*x+1] = scanline[x+ bytes_per_line    ];
                ptr[3*x+2] = scanline[x+(bytes_per_line<<1)];
            }

            ptr += stride;
        }

    } else if (nplanes == 1 && bits_per_pixel == 8) {
        const uint8_t *palstart = bufstart + buf_size - 769;

        for (y=0; y<h; y++, ptr+=stride) {
            buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed);
            memcpy(ptr, scanline, w);
        }

        if (buf != palstart) {
            av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
            buf = palstart;
        }
        if (*buf++ != 12) {
            av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
            goto end;
        }

    } else if (nplanes == 1) {   /* all packed formats, max. 16 colors */
        GetBitContext s;

        for (y=0; y<h; y++) {
            init_get_bits(&s, scanline, bytes_per_scanline<<3);

            buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++)
                ptr[x] = get_bits(&s, bits_per_pixel);
            ptr += stride;
        }

    } else {    /* planar, 4, 8 or 16 colors */
        int i;

        for (y=0; y<h; y++) {
            buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++) {
                int m = 0x80 >> (x&7), v = 0;
                for (i=nplanes - 1; i>=0; i--) {
                    v <<= 1;
                    v  += !!(scanline[i*bytes_per_line + (x>>3)] & m);
                }
                ptr[x] = v;
            }
            ptr += stride;
        }
    }

    if (nplanes == 1 && bits_per_pixel == 8) {
        pcx_palette(&buf, (uint32_t *) p->data[1], 256);
    } else if (bits_per_pixel * nplanes == 1) {
        AV_WN32A(p->data[1]  , 0xFF000000);
        AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
    } else if (bits_per_pixel < 8) {
        const uint8_t *palette = bufstart+16;
        pcx_palette(&palette, (uint32_t *) p->data[1], 16);
    }

    *picture = s->picture;
    *data_size = sizeof(AVFrame);

    ret = buf - bufstart;
end:
    av_free(scanline);
    return ret;
}
Exemple #5
0
static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                            AVPacket *avpkt) {
    GetByteContext gb;
    AVFrame * const p = data;
    int compressed, xmin, ymin, xmax, ymax, ret;
    unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
                 bytes_per_scanline;
    uint8_t *ptr, *scanline;

    if (avpkt->size < 128)
        return AVERROR_INVALIDDATA;

    bytestream2_init(&gb, avpkt->data, avpkt->size);

    if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) {
        av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
        return AVERROR_INVALIDDATA;
    }

    compressed = bytestream2_get_byteu(&gb);
    bits_per_pixel = bytestream2_get_byteu(&gb);
    xmin = bytestream2_get_le16u(&gb);
    ymin = bytestream2_get_le16u(&gb);
    xmax = bytestream2_get_le16u(&gb);
    ymax = bytestream2_get_le16u(&gb);
    avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb);
    avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb);

    if (xmax < xmin || ymax < ymin) {
        av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
        return AVERROR_INVALIDDATA;
    }

    w = xmax - xmin + 1;
    h = ymax - ymin + 1;

    bytestream2_skipu(&gb, 49);
    nplanes            = bytestream2_get_byteu(&gb);
    bytes_per_line     = bytestream2_get_le16u(&gb);
    bytes_per_scanline = nplanes * bytes_per_line;

    if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8) {
        av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
        return AVERROR_INVALIDDATA;
    }

    switch ((nplanes<<8) + bits_per_pixel) {
        case 0x0308:
            avctx->pix_fmt = AV_PIX_FMT_RGB24;
            break;
        case 0x0108:
        case 0x0104:
        case 0x0102:
        case 0x0101:
        case 0x0401:
        case 0x0301:
        case 0x0201:
            avctx->pix_fmt = AV_PIX_FMT_PAL8;
            break;
        default:
            av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n");
            return AVERROR_INVALIDDATA;
    }

    bytestream2_skipu(&gb, 60);

    if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
        return ret;
    if (w != avctx->width || h != avctx->height)
        avcodec_set_dimensions(avctx, w, h);
    if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return ret;
    }

    p->pict_type = AV_PICTURE_TYPE_I;

    ptr    = p->data[0];
    stride = p->linesize[0];

    scanline = av_malloc(bytes_per_scanline + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!scanline)
        return AVERROR(ENOMEM);

    if (nplanes == 3 && bits_per_pixel == 8) {
        for (y=0; y<h; y++) {
            pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++) {
                ptr[3*x  ] = scanline[x                    ];
                ptr[3*x+1] = scanline[x+ bytes_per_line    ];
                ptr[3*x+2] = scanline[x+(bytes_per_line<<1)];
            }

            ptr += stride;
        }

    } else if (nplanes == 1 && bits_per_pixel == 8) {
        int palstart = avpkt->size - 769;

        for (y=0; y<h; y++, ptr+=stride) {
            pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
            memcpy(ptr, scanline, w);
        }

        if (bytestream2_tell(&gb) != palstart) {
            av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
            bytestream2_seek(&gb, palstart, SEEK_SET);
        }
        if (bytestream2_get_byte(&gb) != 12) {
            av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
            ret = AVERROR_INVALIDDATA;
            goto end;
        }

    } else if (nplanes == 1) {   /* all packed formats, max. 16 colors */
        GetBitContext s;

        for (y=0; y<h; y++) {
            init_get_bits8(&s, scanline, bytes_per_scanline);

            pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++)
                ptr[x] = get_bits(&s, bits_per_pixel);
            ptr += stride;
        }

    } else {    /* planar, 4, 8 or 16 colors */
        int i;

        for (y=0; y<h; y++) {
            pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);

            for (x=0; x<w; x++) {
                int m = 0x80 >> (x&7), v = 0;
                for (i=nplanes - 1; i>=0; i--) {
                    v <<= 1;
                    v  += !!(scanline[i*bytes_per_line + (x>>3)] & m);
                }
                ptr[x] = v;
            }
            ptr += stride;
        }
    }

    ret = bytestream2_tell(&gb);
    if (nplanes == 1 && bits_per_pixel == 8) {
        pcx_palette(&gb, (uint32_t *) p->data[1], 256);
        ret += 256 * 3;
    } else if (bits_per_pixel * nplanes == 1) {
        AV_WN32A(p->data[1]  , 0xFF000000);
        AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
    } else if (bits_per_pixel < 8) {
        bytestream2_seek(&gb, 16, SEEK_SET);
        pcx_palette(&gb, (uint32_t *) p->data[1], 16);
    }

    *got_frame = 1;

end:
    av_free(scanline);
    return ret;
}
static void super2xsai(AVFilterContext *ctx,
                       uint8_t *src, int src_linesize,
                       uint8_t *dst, int dst_linesize,
                       int width, int height)
{
    Super2xSaIContext *sai = ctx->priv;
    unsigned int x, y;
    uint32_t color[4][4];
    unsigned char *src_line[4];
    const int bpp = sai->bpp;
    const uint32_t hi_pixel_mask = sai->hi_pixel_mask;
    const uint32_t lo_pixel_mask = sai->lo_pixel_mask;
    const uint32_t q_hi_pixel_mask = sai->q_hi_pixel_mask;
    const uint32_t q_lo_pixel_mask = sai->q_lo_pixel_mask;

    /* Point to the first 4 lines, first line is duplicated */
    src_line[0] = src;
    src_line[1] = src;
    src_line[2] = src + src_linesize*FFMIN(1, height-1);
    src_line[3] = src + src_linesize*FFMIN(2, height-1);

#define READ_COLOR4(dst, src_line, off) dst = *((const uint32_t *)src_line + off)
#define READ_COLOR3(dst, src_line, off) dst = AV_RL24 (src_line + 3*off)
#define READ_COLOR2(dst, src_line, off) dst = sai->is_be ? AV_RB16(src_line + 2 * off) : AV_RL16(src_line + 2 * off)

    for (y = 0; y < height; y++) {
        uint8_t *dst_line[2];

        dst_line[0] = dst + dst_linesize*2*y;
        dst_line[1] = dst + dst_linesize*(2*y+1);

        switch (bpp) {
        case 4:
            READ_COLOR4(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR4(color[0][2], src_line[0], 1); READ_COLOR4(color[0][3], src_line[0], 2);
            READ_COLOR4(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR4(color[1][2], src_line[1], 1); READ_COLOR4(color[1][3], src_line[1], 2);
            READ_COLOR4(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR4(color[2][2], src_line[2], 1); READ_COLOR4(color[2][3], src_line[2], 2);
            READ_COLOR4(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR4(color[3][2], src_line[3], 1); READ_COLOR4(color[3][3], src_line[3], 2);
            break;
        case 3:
            READ_COLOR3(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR3(color[0][2], src_line[0], 1); READ_COLOR3(color[0][3], src_line[0], 2);
            READ_COLOR3(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR3(color[1][2], src_line[1], 1); READ_COLOR3(color[1][3], src_line[1], 2);
            READ_COLOR3(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR3(color[2][2], src_line[2], 1); READ_COLOR3(color[2][3], src_line[2], 2);
            READ_COLOR3(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR3(color[3][2], src_line[3], 1); READ_COLOR3(color[3][3], src_line[3], 2);
            break;
        default:
            READ_COLOR2(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR2(color[0][2], src_line[0], 1); READ_COLOR2(color[0][3], src_line[0], 2);
            READ_COLOR2(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR2(color[1][2], src_line[1], 1); READ_COLOR2(color[1][3], src_line[1], 2);
            READ_COLOR2(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR2(color[2][2], src_line[2], 1); READ_COLOR2(color[2][3], src_line[2], 2);
            READ_COLOR2(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR2(color[3][2], src_line[3], 1); READ_COLOR2(color[3][3], src_line[3], 2);
        }

        for (x = 0; x < width; x++) {
            uint32_t product1a, product1b, product2a, product2b;

//---------------------------------------  B0 B1 B2 B3    0  1  2  3
//                                         4  5* 6  S2 -> 4  5* 6  7
//                                         1  2  3  S1    8  9 10 11
//                                         A0 A1 A2 A3   12 13 14 15
//--------------------------------------
            if (color[2][1] == color[1][2] && color[1][1] != color[2][2]) {
                product2b = color[2][1];
                product1b = product2b;
            } else if (color[1][1] == color[2][2] && color[2][1] != color[1][2]) {
                product2b = color[1][1];
                product1b = product2b;
            } else if (color[1][1] == color[2][2] && color[2][1] == color[1][2]) {
                int r = 0;

                r += GET_RESULT(color[1][2], color[1][1], color[1][0], color[3][1]);
                r += GET_RESULT(color[1][2], color[1][1], color[2][0], color[0][1]);
                r += GET_RESULT(color[1][2], color[1][1], color[3][2], color[2][3]);
                r += GET_RESULT(color[1][2], color[1][1], color[0][2], color[1][3]);

                if (r > 0)
                    product1b = color[1][2];
                else if (r < 0)
                    product1b = color[1][1];
                else
                    product1b = INTERPOLATE(color[1][1], color[1][2]);

                product2b = product1b;
            } else {
                if (color[1][2] == color[2][2] && color[2][2] == color[3][1] && color[2][1] != color[3][2] && color[2][2] != color[3][0])
                    product2b = Q_INTERPOLATE(color[2][2], color[2][2], color[2][2], color[2][1]);
                else if (color[1][1] == color[2][1] && color[2][1] == color[3][2] && color[3][1] != color[2][2] && color[2][1] != color[3][3])
                    product2b = Q_INTERPOLATE(color[2][1], color[2][1], color[2][1], color[2][2]);
                else
                    product2b = INTERPOLATE(color[2][1], color[2][2]);

                if (color[1][2] == color[2][2] && color[1][2] == color[0][1] && color[1][1] != color[0][2] && color[1][2] != color[0][0])
                    product1b = Q_INTERPOLATE(color[1][2], color[1][2], color[1][2], color[1][1]);
                else if (color[1][1] == color[2][1] && color[1][1] == color[0][2] && color[0][1] != color[1][2] && color[1][1] != color[0][3])
                    product1b = Q_INTERPOLATE(color[1][2], color[1][1], color[1][1], color[1][1]);
                else
                    product1b = INTERPOLATE(color[1][1], color[1][2]);
            }

            if (color[1][1] == color[2][2] && color[2][1] != color[1][2] && color[1][0] == color[1][1] && color[1][1] != color[3][2])
                product2a = INTERPOLATE(color[2][1], color[1][1]);
            else if (color[1][1] == color[2][0] && color[1][2] == color[1][1] && color[1][0] != color[2][1] && color[1][1] != color[3][0])
                product2a = INTERPOLATE(color[2][1], color[1][1]);
            else
                product2a = color[2][1];

            if (color[2][1] == color[1][2] && color[1][1] != color[2][2] && color[2][0] == color[2][1] && color[2][1] != color[0][2])
                product1a = INTERPOLATE(color[2][1], color[1][1]);
            else if (color[1][0] == color[2][1] && color[2][2] == color[2][1] && color[2][0] != color[1][1] && color[2][1] != color[0][0])
                product1a = INTERPOLATE(color[2][1], color[1][1]);
            else
                product1a = color[1][1];

            /* Set the calculated pixels */
            switch (bpp) {
            case 4:
                AV_WN32A(dst_line[0] + x * 8,     product1a);
                AV_WN32A(dst_line[0] + x * 8 + 4, product1b);
                AV_WN32A(dst_line[1] + x * 8,     product2a);
                AV_WN32A(dst_line[1] + x * 8 + 4, product2b);
                break;
            case 3:
                AV_WL24(dst_line[0] + x * 6,     product1a);
                AV_WL24(dst_line[0] + x * 6 + 3, product1b);
                AV_WL24(dst_line[1] + x * 6,     product2a);
                AV_WL24(dst_line[1] + x * 6 + 3, product2b);
                break;
            default: // bpp = 2
                if (sai->is_be) {
                    AV_WB32(dst_line[0] + x * 4, product1a | (product1b << 16));
                    AV_WB32(dst_line[1] + x * 4, product2a | (product2b << 16));
                } else {
                    AV_WL32(dst_line[0] + x * 4, product1a | (product1b << 16));
                    AV_WL32(dst_line[1] + x * 4, product2a | (product2b << 16));
                }
            }

            /* Move color matrix forward */
            color[0][0] = color[0][1]; color[0][1] = color[0][2]; color[0][2] = color[0][3];
            color[1][0] = color[1][1]; color[1][1] = color[1][2]; color[1][2] = color[1][3];
            color[2][0] = color[2][1]; color[2][1] = color[2][2]; color[2][2] = color[2][3];
            color[3][0] = color[3][1]; color[3][1] = color[3][2]; color[3][2] = color[3][3];

            if (x < width - 3) {
                x += 3;
                switch (bpp) {
                case 4:
                    READ_COLOR4(color[0][3], src_line[0], x);
                    READ_COLOR4(color[1][3], src_line[1], x);
                    READ_COLOR4(color[2][3], src_line[2], x);
                    READ_COLOR4(color[3][3], src_line[3], x);
                    break;
                case 3:
                    READ_COLOR3(color[0][3], src_line[0], x);
                    READ_COLOR3(color[1][3], src_line[1], x);
                    READ_COLOR3(color[2][3], src_line[2], x);
                    READ_COLOR3(color[3][3], src_line[3], x);
                    break;
                default:        /* case 2 */
                    READ_COLOR2(color[0][3], src_line[0], x);
                    READ_COLOR2(color[1][3], src_line[1], x);
                    READ_COLOR2(color[2][3], src_line[2], x);
                    READ_COLOR2(color[3][3], src_line[3], x);
                }
                x -= 3;
            }
        }

        /* We're done with one line, so we shift the source lines up */
        src_line[0] = src_line[1];
        src_line[1] = src_line[2];
        src_line[2] = src_line[3];

        /* Read next line */
        src_line[3] = src_line[2];
        if (y < height - 3)
            src_line[3] += src_linesize;
    } // y loop
}