[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