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

James Almer jamrial at gmail.com
Sun Mar 31 07:09:52 EEST 2019


On 3/28/2019 6:12 PM, Paul B Mahol wrote:
> This work is sponsored by VideoLAN.
> 
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  libavcodec/Makefile     |   1 +
>  libavcodec/agm.c        | 701 ++++++++++++++++++++++++++++++++++++++++
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 +
>  libavformat/riff.c      |   2 +
>  6 files changed, 713 insertions(+)
>  create mode 100644 libavcodec/agm.c

[...]

> +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, width, height, 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 coded height");
> +        h = -h;
> +        s->flags |= 1;
> +    }
> +
> +    width  = avctx->width;
> +    height = avctx->height;
> +    if (w < width || h < height || w & 7 || h & 7)
> +        return AVERROR_INVALIDDATA;
> +
> +    ret = ff_set_dimensions(avctx, w, h);
> +    if (ret < 0)
> +        return ret;
> +    avctx->width = width;
> +    avctx->height = height;
> +
> +    s->compression = bytestream2_get_le32(gbyte);
> +    if (s->compression < 0 || s->compression > 100)
> +        return AVERROR_INVALIDDATA;
> +
> +    for (int i = 0; i < 3; i++)
> +        s->size[i] = bytestream2_get_le32(gbyte);
> +    if (32LL + s->size[0] + s->size[1] + s->size[2] > avpkt->size)
> +        return AVERROR_INVALIDDATA;
> +
> +    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
> +        return ret;
> +
> +    if (frame->key_frame) {
> +        ret = decode_intra(avctx, gb, frame);
> +    } else {
> +        if (!s->prev_frame->data[0]) {

You should add a flush() function to unref s->prev_frame. Nothing
guarantees that the first frame sent after an avcodec_flush_buffers()
call (AKA, seeking) will be a keyframe, and if it's not, decode_inter()
will be called with bogus frame data.

> +            av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
> +            return AVERROR_INVALIDDATA;
> +        }
> +
> +        if (!(s->flags & 2)) {
> +            ret = av_frame_copy(frame, s->prev_frame);
> +            if (ret < 0)
> +                return ret;
> +        }
> +
> +        ret = decode_inter(avctx, gb, frame, s->prev_frame);
> +    }
> +    if (ret < 0)
> +        return ret;
> +
> +    av_frame_unref(s->prev_frame);
> +    if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
> +        return ret;
> +
> +    frame->crop_top  = avctx->coded_height - avctx->height;
> +    frame->crop_left = avctx->coded_width  - avctx->width;

Setting these fields means you need to set the
FF_CODEC_CAP_EXPORTS_CROPPING caps_internal flag.

> +
> +    *got_frame = 1;
> +
> +    return avpkt->size;
> +}
> +
> +static av_cold int decode_init(AVCodecContext *avctx)
> +{
> +    AGMContext *s = avctx->priv_data;
> +
> +    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> +    s->avctx = avctx;
> +    s->plus = avctx->codec_tag == MKTAG('A', 'G', 'M', '3');
> +
> +    avctx->idct_algo = FF_IDCT_SIMPLE;
> +    ff_idctdsp_init(&s->idsp, avctx);
> +    ff_init_scantable(s->idsp.idct_permutation, &s->scantable, ff_zigzag_direct);
> +
> +    s->prev_frame = av_frame_alloc();
> +    if (!s->prev_frame)
> +        return AVERROR(ENOMEM);
> +
> +    return 0;
> +}
> +
> +static av_cold int decode_close(AVCodecContext *avctx)
> +{
> +    AGMContext *s = avctx->priv_data;
> +
> +    av_frame_free(&s->prev_frame);
> +    av_freep(&s->mvectors);
> +    s->mvectors_size = 0;
> +
> +    return 0;
> +}
> +
> +AVCodec ff_agm_decoder = {
> +    .name             = "agm",
> +    .long_name        = NULL_IF_CONFIG_SMALL("Amuse Graphics Movie"),
> +    .type             = AVMEDIA_TYPE_VIDEO,
> +    .id               = AV_CODEC_ID_AGM,
> +    .priv_data_size   = sizeof(AGMContext),
> +    .init             = decode_init,
> +    .close            = decode_close,
> +    .decode           = decode_frame,
> +    .capabilities     = AV_CODEC_CAP_DR1,
> +    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
> +                        FF_CODEC_CAP_INIT_CLEANUP,
> +};
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index b26aeca239..71fd74a07e 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -35,6 +35,7 @@ extern AVCodec ff_aasc_decoder;
>  extern AVCodec ff_aic_decoder;
>  extern AVCodec ff_alias_pix_encoder;
>  extern AVCodec ff_alias_pix_decoder;
> +extern AVCodec ff_agm_decoder;
>  extern AVCodec ff_amv_encoder;
>  extern AVCodec ff_amv_decoder;
>  extern AVCodec ff_anm_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 0ce22ec4fa..cafc65fce5 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -454,6 +454,7 @@ enum AVCodecID {
>      AV_CODEC_ID_RASC,
>      AV_CODEC_ID_HYMT,
>      AV_CODEC_ID_ARBC,
> +    AV_CODEC_ID_AGM,
>  
>      /* various PCM "codecs" */
>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index a3de8e1c2b..7595ef1eac 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -1705,6 +1705,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
>          .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"),
>          .props     = AV_CODEC_PROP_LOSSY,
>      },
> +    {
> +        .id        = AV_CODEC_ID_AGM,
> +        .type      = AVMEDIA_TYPE_VIDEO,
> +        .name      = "agm",
> +        .long_name = NULL_IF_CONFIG_SMALL("Amuse Graphics Movie"),
> +        .props     = AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_LOSSY,
> +    },
>  
>      /* various PCM "codecs" */
>      {
> diff --git a/libavformat/riff.c b/libavformat/riff.c
> index 8f0fd99e22..a8594b0607 100644
> --- a/libavformat/riff.c
> +++ b/libavformat/riff.c
> @@ -477,6 +477,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
>      { AV_CODEC_ID_RASC,         MKTAG('R', 'A', 'S', 'C') },
>      { AV_CODEC_ID_HYMT,         MKTAG('H', 'Y', 'M', 'T') },
>      { AV_CODEC_ID_ARBC,         MKTAG('A', 'R', 'B', 'C') },
> +    { AV_CODEC_ID_AGM,          MKTAG('A', 'G', 'M', '2') },
> +    { AV_CODEC_ID_AGM,          MKTAG('A', 'G', 'M', '3') },
>      { AV_CODEC_ID_NONE,         0 }
>  };
>  
> 



More information about the ffmpeg-devel mailing list