On 3/28/2019 6:12 PM, Paul B Mahol wrote: > This work is sponsored by VideoLAN. > > Signed-off-by: Paul B Mahol <one...@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 } > }; > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".