[FFmpeg-devel] [PATCH] Pictor/PC Paint PIC decoder

Reimar Döffinger Reimar.Doeffinger
Tue Jun 1 21:08:18 CEST 2010


On Tue, Jun 01, 2010 at 10:40:56PM +1000, Peter Ross wrote:
> +static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y, int *plane)

The idea was to get rid of the plane argument since it is not used..

> +static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane)
> +{
> +    uint8_t *d;
> +    int mask = (1 << bits_per_plane) - 1;
> +
> +    while (run > 0) {
> +        int j;
> +        for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
> +            d = s->frame.data[0] + *y * s->frame.linesize[0];
> +            d[*x] |= ((value >> j) & mask) << (*plane * bits_per_plane);

My brain hurts.
I think this would be simpler (well, and also faster) if you just shifted
value and mask outside the loop (and adjust them of course when you increment
*plane).

> +    s->nb_planes      = ((buf[10] >> 4) & 0xF) + 1;

The & 0x0f seems pointless.

> +    bpp               = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane;

The shift quoted above will give undefined behaviour if bits_per_plane*(s->nb_planes - 1) > 31.
And I think the code will already just not work if bpp > 8.

> +    nb_blocks = AV_RL16(buf);
> +    buf += 2;

Consider using bytestream_get_le16 etc., here and in a few other places.

> +        for (i = 0; i < nb_blocks && buf_end - buf >= 6; i++) {
> +            const uint8_t *buf_pend = FFMIN(buf + AV_RL16(buf), buf_end);

Calculating buf + AV_RL16(buf) can invoke undefined behaviour.
I also fail to see the point of the nb_blocks variable and caring about it...
In particular since you might end up leaving part of the frame uninitialized
due to it.

> +            while (plane < s->nb_planes && buf_pend - buf >= 1) {
> +                int run;
> +                if (*buf == marker) {
> +                    buf++;
> +                    if (buf_pend - buf < 2)
> +                        break;
> +                    run = *buf++;
> +                    if (run == 0) {
> +                        if (buf_pend - buf < 3)
> +                            break;
> +                        run = AV_RL16(buf);
> +                        buf += 2;
> +                    }
> +                } else {
> +                    run = 1;
> +                }
> +
> +                if (bits_per_plane == 8) {
> +                    picmemset_8bpp(s, *buf, run, &x, &y, &plane);
> +                    if (y < 0)
> +                        break;
> +                }else{
> +                    picmemset(s, *buf, run, &x, &y, &plane, bits_per_plane);
> +                }
> +                buf++;

This seems a bit round-about to me.
while (plane < s->nb_planes) {
    int run = 1;
    int val = *buf++;
    if (val == marker) {
        run = *buf++;
        if (run == 0)
            run = bytestream_get_le32(&buf);
        // TODO: what about run still == 0??
    }
    if (buf > buf_end)
        break;
    [the two picmemset cases]
}



More information about the ffmpeg-devel mailing list