Quoting Vittorio Giovara (2015-09-27 16:39:54)
> Signed-off-by: Vittorio Giovara <[email protected]>
> ---
> In this version:
>  - added pkt size check
>  - reworded comments a little
>  - included fate test
> 
> Big thanks to nevcariel for providing the test file.
> Vittorio
> 
>  Changelog                   |   1 +
>  configure                   |   1 +
>  doc/general.texi            |   1 +
>  libavcodec/Makefile         |   1 +
>  libavcodec/allcodecs.c      |   1 +
>  libavcodec/avcodec.h        |   1 +
>  libavcodec/codec_desc.c     |   7 ++
>  libavcodec/screenpresso.c   | 190 
> ++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h        |   2 +-
>  libavformat/riff.c          |   1 +
>  tests/fate/video.mak        |   3 +
>  tests/ref/fate/screenpresso |   5 ++
>  12 files changed, 213 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/screenpresso.c
>  create mode 100644 tests/ref/fate/screenpresso
> 
> diff --git a/Changelog b/Changelog
> index 461c5b1..696c881 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -43,6 +43,7 @@ version <next>:
>  - Intel QSV-accelerated MPEG-2 video and HEVC decoding
>  - Support DNx100 (1440x1080@8)
>  - DXV decoding
> +- Screenpresso SPV1 decoding
>  
>  
>  version 11:
> diff --git a/configure b/configure
> index 852b931..ba827f9 100755
> --- a/configure
> +++ b/configure
> @@ -1962,6 +1962,7 @@ rv20_decoder_select="error_resilience h263_decoder 
> h263dsp mpeg_er"
>  rv20_encoder_select="h263_encoder"
>  rv30_decoder_select="error_resilience golomb h264chroma h264pred h264qpel 
> mpeg_er mpegvideo rv34dsp videodsp"
>  rv40_decoder_select="error_resilience golomb h264chroma h264pred h264qpel 
> mpeg_er mpegvideo rv34dsp videodsp"
> +screenpresso_decoder_deps="zlib"
>  shorten_decoder_select="golomb"
>  sipr_decoder_select="lsp"
>  sp5x_decoder_select="mjpeg_decoder"
> diff --git a/doc/general.texi b/doc/general.texi
> index 7cd7693..6e43269 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -409,6 +409,7 @@ library:
>  @item RTP                       @tab X @tab X
>  @item RTSP                      @tab X @tab X
>  @item SAP                       @tab X @tab X
> +@item Screenpresso              @tab   @tab X
>  @item SDP                       @tab   @tab X
>  @item Sega FILM/CPK             @tab   @tab X
>      @tab Used in many Sega Saturn console games.
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index f163a79..632a8a6 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -385,6 +385,7 @@ OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o 
> rv30dsp.o
>  OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o
>  OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
>  OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
> +OBJS-$(CONFIG_SCREENPRESSO_DECODER)    += screenpresso.o
>  OBJS-$(CONFIG_SGI_DECODER)             += sgidec.o
>  OBJS-$(CONFIG_SGI_ENCODER)             += sgienc.o rle.o
>  OBJS-$(CONFIG_SGIRLE_DECODER)          += sgirledec.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 49f5a70..2d8474a 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -249,6 +249,7 @@ void avcodec_register_all(void)
>      REGISTER_DECODER(RV40,              rv40);
>      REGISTER_DECODER(S302M,             s302m);
>      REGISTER_DECODER(SANM,              sanm);
> +    REGISTER_DECODER(SCREENPRESSO,      screenpresso);
>      REGISTER_ENCDEC (SGI,               sgi);
>      REGISTER_DECODER(SGIRLE,            sgirle);
>      REGISTER_DECODER(SMACKER,           smacker);
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 8c635d7..de59320 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -299,6 +299,7 @@ enum AVCodecID {
>      AV_CODEC_ID_HAP,
>      AV_CODEC_ID_DDS,
>      AV_CODEC_ID_DXV,
> +    AV_CODEC_ID_SCREENPRESSO,
>  
>      /* 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 c1be40b..d28fe9a 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -1162,6 +1162,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
>          .long_name = NULL_IF_CONFIG_SMALL("Resolume DXV"),
>          .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
>      },
> +    {
> +        .id        = AV_CODEC_ID_SCREENPRESSO,
> +        .type      = AVMEDIA_TYPE_VIDEO,
> +        .name      = "screenpresso",
> +        .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"),
> +        .props     = AV_CODEC_PROP_LOSSLESS,
> +    },
>  
>      /* image codecs */
>      {
> diff --git a/libavcodec/screenpresso.c b/libavcodec/screenpresso.c
> new file mode 100644
> index 0000000..bb869d5
> --- /dev/null
> +++ b/libavcodec/screenpresso.c
> @@ -0,0 +1,190 @@
> +/*
> + * Screenpresso decoder
> + * Copyright (C) 2015 Vittorio Giovara <[email protected]>
> + *
> + * This file is part of Libav.
> + *
> + * Libav is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * Libav is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +/**
> + * @file
> + * Screenpresso decoder
> + *
> + * Fourcc: SPV1
> + *
> + * Screenpresso simply horizontally flips and then deflates frames,
> + * alternating full pictures and deltas. Deltas are related to the currently
> + * rebuilt frame (not the reference), and since there is no coordinate system
> + * they contain exactly as many pixel as the keyframe.
> + *
> + * Supports: BGR24
> + */
> +
> +#include <stdint.h>
> +#include <string.h>
> +#include <zlib.h>
> +
> +#include "libavutil/imgutils.h"
> +#include "libavutil/internal.h"
> +
> +#include "avcodec.h"
> +#include "internal.h"
> +
> +typedef struct ScreenpressoContext {
> +    AVFrame *current;
> +
> +    /* zlib interation */
> +    uint8_t *deflatebuffer;
> +    uLongf deflatelen;
> +} ScreenpressoContext;
> +
> +static av_cold int screenpresso_close(AVCodecContext *avctx)
> +{
> +    ScreenpressoContext *ctx = avctx->priv_data;
> +
> +    av_frame_free(&ctx->current);
> +    av_freep(&ctx->deflatebuffer);
> +
> +    return 0;
> +}
> +
> +static av_cold int screenpresso_init(AVCodecContext *avctx)
> +{
> +    ScreenpressoContext *ctx = avctx->priv_data;
> +
> +    /* These needs to be set to estimate uncompressed buffer */
> +    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
> +    if (ret < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
> +               avctx->width, avctx->height);
> +        return ret;
> +    }
> +
> +    /* Allocate current frame */
> +    ctx->current = av_frame_alloc();
> +    if (!ctx->current)
> +        return AVERROR(ENOMEM);
> +
> +    avctx->pix_fmt = AV_PIX_FMT_BGR24;
> +
> +    return 0;
> +}
> +
> +static void copy_plane_flipped(uint8_t       *dst, int dst_linesize,
> +                               const uint8_t *src, int src_linesize,
> +                               int bytewidth, int height)
> +{
> +    for (; height > 0; height--) {
> +        memcpy(dst, src + (height - 1) * src_linesize, bytewidth);
> +        dst += dst_linesize;
> +    }
> +}
> +
> +static void copy_delta_flipped(uint8_t       *dst, int dst_linesize,
> +                               const uint8_t *src, int src_linesize,
> +                               int bytewidth, int height)
> +{
> +    int i;
> +    for (; height > 0; height--) {
> +        for (i = 0; i < bytewidth; i++)
> +            dst[i] += src[(height - 1) * src_linesize + i];
> +        dst += dst_linesize;
> +    }
> +}
> +
> +static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
> +                                     int *got_frame, AVPacket *avpkt)
> +{
> +    ScreenpressoContext *ctx = avctx->priv_data;
> +    AVFrame *frame = data;
> +    int keyframe;
> +    int ret;
> +
> +    /* Size check */
> +    if (avpkt->size < 3) {
> +        av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    /* Basic sanity check, but not really harmful */
> +    if ((avpkt->data[0] != 0x73 && avpkt->data[0] != 0x72) ||
> +        avpkt->data[1] != 8) { // bpp probably
> +        av_log(avctx, AV_LOG_WARNING, "Unknown header 0x%02X%02X\n",
> +               avpkt->data[0], avpkt->data[1]);
> +    }
> +    keyframe = (avpkt->data[0] == 0x73);
> +
> +    /* Resize deflate buffer and frame on resolution change */
> +    if (ctx->deflatelen != avctx->width * avctx->height * 3) {
> +        ret = ff_get_buffer(avctx, ctx->current, 0);

You're keeping this buffer for later use, so the flag should not be 0.

> +        if (ret < 0)
> +            return ret;
> +
> +        ctx->deflatelen = avctx->width * avctx->height * 3;
> +        ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen);
> +        if (ret < 0)
> +            return ret;

You should probably set deflatelen to 0 on fail, otherwise BadStuff
could happen.

> +    }
> +
> +    /* Inflate the frame after the 2 byte header */
> +    ret = uncompress(ctx->deflatebuffer, &ctx->deflatelen,
> +                     avpkt->data + 2, avpkt->size - 2);
> +    if (ret) {
> +        av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret);
> +        return AVERROR_UNKNOWN;
> +    }
> +
> +    /* When a keyframe is found, copy it as it contains the whole picture */
> +    if (keyframe)
> +        copy_plane_flipped(ctx->current->data[0], ctx->current->linesize[0],
> +                           ctx->deflatebuffer, avctx->width * 3,
> +                           avctx->width * 3, avctx->height);

Why not do what other flipped codecs do -- multiply linesize by -1 and
advance data[0] appropriately.

-- 
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to