[FFmpeg-devel] [PATCH] avcodec: add Amuse Graphics decoder

Paul B Mahol onemda at gmail.com
Sat Oct 13 18:19:55 EEST 2018


On 10/13/18, Michael Niedermayer <michael at niedermayer.cc> wrote:
> On Wed, Oct 10, 2018 at 01:22:24PM +0200, Paul B Mahol wrote:
>> This work is partially sponsored by VideoLAN.
>>
>> Signed-off-by: Paul B Mahol <onemda at gmail.com>
>> ---
>>
>
>> The AGM3 variant decodes with some artifacts.
>
> I looked a bit as you asked on IRC but wasnt able to really fix it in
> the time i had available
>
> The following patch avoids the green blocks but it does not feel correct
>
> diff --git a/libavcodec/agm.c b/libavcodec/agm.c
> index 424b906eac..a6d9a9a7a6 100644
> --- a/libavcodec/agm.c
> +++ b/libavcodec/agm.c
> @@ -358,10 +358,12 @@ static int decode_inter_plane(AGMContext *s,
> GetBitContext *gb, int size,
>                  if (ret < 0)
>                      return ret;
>
> -                if (mv_x < min) {
> +                if (mv_x < min && s->block[0] > 512) {
>                      s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1
> - y) * 8 * frame->linesize[plane] + x * 8,
>                                       frame->linesize[plane], s->block);
>                  } else {
> +                    if (mv_x < min)
> +                        mv_x = 0;
>                      if (y * 8 + mv_y < 0 || y * 8 + mv_y >= h ||
>                          x * 8 + mv_x < 0 || x * 8 + mv_x >= w)
>                          return AVERROR_INVALIDDATA;
> [...]
>
>> +
>> +static int read_code2(GetBitContext *gb, int *oskip, int *level)
>> +{
>> +    int max, len = 0, skip = 0;
>> +
>> +    if (show_bits(gb, 2)) {
>> +        switch (show_bits(gb, 4)) {
>> +        case 1:
>> +        case 9:
>> +            len = 1;
>> +            skip = 3;
>> +            break;
>> +        case 2:
>> +            len = 3;
>> +            skip = 4;
>> +            break;
>> +        case 3:
>> +            len = 7;
>> +            skip = 4;
>> +            break;
>> +        case 5:
>> +        case 0xD:
>> +            len = 2;
>> +            skip = 3;
>> +            break;
>> +        case 6:
>> +            len = 4;
>> +            skip = 4;
>> +            break;
>> +        case 7:
>> +            len = 8;
>> +            skip = 4;
>> +            break;
>> +        case 0xA:
>> +            len = 5;
>> +            skip = 4;
>> +            break;
>> +        case 0xB:
>> +            len = 9;
>> +            skip = 4;
>> +            break;
>> +        case 0xE:
>> +            len = 6;
>> +            skip = 4;
>> +            break;
>> +        case 0xF:
>> +            len = ((show_bits(gb, 5) & 0x10) | 0xA0) >> 4;
>> +            skip = 5;
>> +            break;
>> +        default:
>> +            return AVERROR_INVALIDDATA;
>> +        }
>> +        skip_bits(gb, skip);
>> +        *level = get_bits(gb, len);
>> +        *oskip = 0;
>> +        max = 1 << (len - 1);
>> +        if (*level < max)
>> +            *level = -(max + *level);
>> +    } else if (show_bits(gb, 3) & 4) {
>> +        skip_bits(gb, 3);
>
>> +        if (show_bits(gb, 4)) {
>> +            if (show_bits(gb, 4) == 1) {
>> +                skip_bits(gb, 4);
>> +                *oskip = get_bits(gb, 16);
>> +                *level = 0;
>> +            } else {
>> +                *oskip = get_bits(gb, 4);
>> +                *level = 0;
>> +            }
>> +        } else {
>> +            skip_bits(gb, 4);
>> +            *oskip = get_bits(gb, 10);
>> +            *level = 0;
>> +        }
>
> The oskip values which can be represented as shorter codes here (if they
> occur) likely are errors, this could be checked for. Not sure its useful
>
>
> [...]
>
>> +
>> +static int decode_frame(AVCodecContext *avctx, void *data,
>> +                        int *got_frame, AVPacket *avpkt)
>> +{
>> +    AGMContext *s = avctx->priv_data;
>> +    GetBitContext *gb = &s->gb;
>> +    GetByteContext *gbyte = &s->gbyte;
>> +    AVFrame *frame = data;
>> +    int w, h, header;
>> +    int ret;
>> +
>> +    if (!avpkt->size)
>> +        return 0;
>> +
>> +    bytestream2_init(gbyte, avpkt->data, avpkt->size);
>> +
>> +    header = bytestream2_get_le32(gbyte);
>> +    if (header)
>> +        avpriv_request_sample(avctx, "header %X", header);
>> +    s->bitstream_size = bytestream2_get_le24(gbyte);
>> +    if (avpkt->size < s->bitstream_size + 8)
>> +        return AVERROR_INVALIDDATA;
>> +
>> +    s->key_frame = bytestream2_get_byte(gbyte) == 32;
>> +    frame->key_frame = s->key_frame;
>> +    frame->pict_type = s->key_frame ? AV_PICTURE_TYPE_I :
>> AV_PICTURE_TYPE_P;
>> +
>> +    s->flags = 0;
>> +    w = bytestream2_get_le32(gbyte);
>> +    if (w < 0) {
>> +        w = -w;
>> +        s->flags |= 2;
>> +    }
>> +    h = bytestream2_get_le32(gbyte);
>> +    if (h < 0) {
>> +        avpriv_request_sample(avctx, "negative height");
>> +        h = -h;
>> +        s->flags |= 1;
>> +    }
>> +
>> +    ret = ff_set_dimensions(avctx, w, h);
>> +    if (ret < 0)
>> +        return ret;
>
> i suspect this has issues with odd width / height
> the motion vectors, and luma and chroma plane sizes probably wont align and
> then
> likely not work as intended as each rounds differently

width/height & 7 is not supported, dimensions are simply extended and
unused/padded
pixels are black.

>
>
> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Old school: Use the lowest level language in which you can solve the
> problem
>             conveniently.
> New school: Use the highest level language in which the latest
> supercomputer
>             can solve the problem without the user falling asleep waiting.
>


More information about the ffmpeg-devel mailing list