[FFmpeg-devel] [PATCH] Kega Game Video (KGV1) decoder

Michael Niedermayer michaelni
Tue Mar 2 23:37:05 CET 2010


On Tue, Mar 02, 2010 at 11:46:38AM -0600, Daniel Verkamp wrote:
> On Wed, Feb 3, 2010 at 9:02 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
> > On Wed, Feb 03, 2010 at 11:49:32AM -0600, Daniel Verkamp wrote:
> >> On Wed, Feb 3, 2010 at 10:41 AM, Daniel Verkamp <daniel at drv.nu> wrote:
> >> > Hi,
> >> >
> >> > This is a video capture codec used by the Kega emulator.
> >> >
> >> > See http://wiki.multimedia.cx/index.php?title=Kega_Video for more information.
> >> >
> >> > Thanks,
> >> > -- Daniel Verkamp
> >> >
> >>
> >> Slightly changed version which (hopefully) fixes endianness issues;
> >> still only tested on LE.
> >>
> > [...]
> > are you missing checks for the outpt array size, if so please double
> > check your code that there are no further such issues and also try a
> > fuzzer
> >
> 
> Previous version was relying on padded output buffers for this
> purpose, but on closer investigation, this was insufficient anyway.
> New version has checks for every array/pointer dereference based on
> input data.
> 
> > [...]
> >> + ? ?dst = c->pic.data[0];
> >> + ? ?stride = c->pic.linesize[0];
> >> + ? ?for (i = 0; i < h; i++)
> >> + ? ? ? ?memcpy(dst + i * stride, c->cur + i * w, w * 2);
> >
> > return your internal buffer dont copy and disable CODEC_CAP_DR1
> >
> 
> I have attempted to do this, and it seems to work with ffmpeg and
> ffplay, but I couldn't find any other codecs that work this way, so it
> is mostly trial and error - please double check! Am I correct in
> assuming I can just set the output AVFrame's data[0] and linesize[0]
> (no get_buffer() use at all), or are there additional required fields?



>  The doxygen for AVCodec.decode is nonexistent, so it is not
> particularly clear.

improcing the dox is welcoeme


[...]
> +
> +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt)
> +{
> +    const uint8_t *buf = avpkt->data;
> +    const uint8_t *buf_end = buf + avpkt->size;
> +    KgvContext * const c = avctx->priv_data;
> +    int offsets[7];
> +    uint16_t *out, *prev;
> +    int outcnt = 0, maxcnt;
> +    int w, h, i;
> +
> +    if (avpkt->size < 2)
> +        return -1;
> +
> +    w = (buf[0] + 1) * 8;
> +    h = (buf[1] + 1) * 8;
> +    buf += 2;
> +
> +    if (avcodec_check_dimensions(avctx, w, h))
> +        return -1;
> +
> +    if (w != avctx->width || h != avctx->height)
> +        avcodec_set_dimensions(avctx, w, h);
> +
> +    maxcnt = w * h;
> +

> +    c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE
> +                        | FF_BUFFER_HINTS_REUSABLE;

that should have no effect if you dont use *get_buffer()


> +
> +    out = av_realloc(c->cur, w * h * 2);
> +    if (!out)
> +        return -1;
> +    c->cur = out;
> +
> +    prev = av_realloc(c->prev, w * h * 2);
> +    if (!prev)
> +        return -1;
> +    c->prev = prev;
> +
> +    for (i = 0; i < 7; i++)
> +        offsets[i] = -1;
> +
> +    while (outcnt < maxcnt && buf_end - 2 > buf) {
> +        int code = AV_RL16(buf);
> +        buf += 2;
> +        if (!(code & 0x8000)) {
> +            out[outcnt++] = code; // rgb555 pixel coded directly
> +        } else {
> +            if ((code & 0x6000) == 0x6000) {
> +                // copy from previous frame
> +                int count = (code & 0x3FF) + 3;
> +                int oidx  = (code >>   10) & 7;
> +                int start;
> +
> +                if (offsets[oidx] == -1) {
> +                    if (buf_end - 3 < buf)
> +                        break;

> +                    offsets[oidx] = AV_RL24(buf);
> +                    if (offsets[oidx] < 0) {

how can a 24bit number produce a negative int ?


> +                        av_log(avctx, AV_LOG_ERROR, "negative offset\n");
> +                        offsets[oidx] = 0;
> +                        break;
> +                    }
> +                    buf += 3;
> +                }
> +
> +                start = (outcnt + offsets[oidx]) % maxcnt;
> +
> +                if (maxcnt - outcnt < count || maxcnt - start < count)
> +                    break;
> +
> +                for (i = 0; i < count; i++)
> +                    out[outcnt++] = prev[start + i];
> +
> +            } else {
> +                // copy from earlier in this frame
> +                int count;
> +                int offset = (code & 0x1FFF) + 1;
> +                uint16_t *inp;
> +                if (!(code & 0x6000)) {
> +                    count = 2;
> +                } else if ((code & 0x6000) == 0x2000) {
> +                    count = 3;
> +                } else {
> +                    if (buf_end - 1 < buf)
> +                        break;
> +                    count = *buf++ + 4;
> +                }
> +
> +                if (outcnt - offset < 0 || maxcnt - outcnt < count)
> +                    break;
> +
> +                inp = out + outcnt - offset;
> +                for (i = 0; i < count; i++)
> +                    out[outcnt++] = inp[i];
> +            }

these 2 look quite similar, i suspect they can be simplified by merging
them

[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Everything should be made as simple as possible, but not simpler.
-- Albert Einstein
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20100302/80f2d585/attachment.pgp>



More information about the ffmpeg-devel mailing list