[FFmpeg-devel] [PATCH] ZeroCodec Decoder

Michael Niedermayer michaelni at gmx.at
Fri Mar 16 08:20:45 CET 2012


On Thu, Mar 15, 2012 at 03:59:54PM -0400, Derek Buitenhuis wrote:
> An obscure Japanese screen capture video codec.
[...]
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index a3d5614..4e984dc 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -247,6 +247,7 @@ enum CodecID {
>      CODEC_ID_V410,
>      CODEC_ID_XWD,
>      CODEC_ID_CDXL,
> +    CODEC_ID_ZEROCODEC,
>      CODEC_ID_Y41P       = MKBETAG('Y','4','1','P'),
>      CODEC_ID_ESCAPE130  = MKBETAG('E','1','3','0'),
>      CODEC_ID_AVRP       = MKBETAG('A','V','R','P'),

I hope this wont break compatibility


[...]
> +static int zerocodec_decode_frame(AVCodecContext *avctx, void *data,
> +                                  int *data_size, AVPacket *avpkt)
> +{
> +    ZeroCodecContext *zc = avctx->priv_data;
> +    AVFrame *pic = avctx->coded_frame;
> +    z_stream *zstream = &zc->zstream;
> +    uint8_t *src, *prev_src, *dst;
> +    int i, j, zret;
> +
> +    pic->reference = 0;
> +
> +    if (pic->data[0])
> +        avctx->release_buffer(avctx, pic);
> +
> +    if (avctx->get_buffer(avctx, pic) < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +

> +    pic->key_frame = 1;
> +    pic->pict_type = AV_PICTURE_TYPE_I;

these look wrong


> +
> +    zret = inflateReset(zstream);
> +
> +    if (zret != Z_OK) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d\n", zret);
> +        return AVERROR(EINVAL);
> +    }
> +
> +    zstream->next_in   = avpkt->data;
> +    zstream->avail_in  = avpkt->size;
> +    zstream->next_out  = zc->current_frame;
> +    zstream->avail_out = zc->size;
> +
> +    inflate(zstream, Z_FINISH);
> +
> +    src      = zc->current_frame;
> +    prev_src = zc->previous_frame;
> +    dst      = pic->data[0];
> +
> +    /**
> +     * ZeroCodec has very simple interframe compression. If a value
> +     * is the same as the previous frame, set it to 0.
> +     */
> +
> +    if (avpkt->flags & AV_PKT_FLAG_KEY) {
> +        for (i = 0; i < avctx->height; i++) {
> +            memcpy(dst, src, avctx->width << 1);
> +            src += avctx->width << 1;
> +            dst += pic->linesize[0];
> +        }
> +    } else {
> +        for (i = 0; i < avctx->height; i++) {
> +
> +            for (j = 0; j < avctx->width << 1; j++)
> +                src[j] = src[j] ? src[j] : prev_src[j];
> +
> +            memcpy(dst, src, avctx->width << 1);
> +
> +            src      += avctx->width << 1;
> +            prev_src += avctx->width << 1;
> +            dst      +=  pic->linesize[0];
> +        }
> +    }
> +

> +    /* Store the current frame for later use */
> +    memcpy(zc->previous_frame, zc->current_frame, zc->size);

this can be avoided by exchanging the pointers

its also possible to get rid of the second memcpy by keeping and
using the previous frame instead of a seperate buffer
not sure if the codec is used in practice, if not optimizing it
doesnt make much sense


[...]
> +static av_cold int zerocodec_decode_init(AVCodecContext *avctx)
> +{
> +    ZeroCodecContext *zc = avctx->priv_data;
> +    z_stream *zstream = &zc->zstream;
> +    int zret;
> +
> +    avctx->pix_fmt = PIX_FMT_UYVY422;
> +    avctx->bits_per_raw_sample = 8;
> +
> +    zc->size = avpicture_get_size(avctx->pix_fmt,
> +                                  avctx->width, avctx->height);
> +
> +    zstream->zalloc = Z_NULL;
> +    zstream->zfree  = Z_NULL;
> +    zstream->opaque = Z_NULL;
> +
> +    zret = inflateInit(zstream);
> +
> +    if (zret != Z_OK) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not initialize inflate: %d\n", zret);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    avctx->coded_frame = avcodec_alloc_frame();
> +
> +    if (!avctx->coded_frame) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame buffer.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    zc->current_frame = av_malloc(zc->size * sizeof(*zc->current_frame));
> +
> +    if (!zc->current_frame) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not allocate current frame buffer.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    zc->previous_frame = av_malloc(zc->size * sizeof(*zc->previous_frame));
> +
> +    if (!zc->previous_frame) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not allocate previous frame buffer.\n");
> +        return AVERROR(ENOMEM);
> +    }

memleaks in case of malloc failures

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I do not agree with what you have to say, but I'll defend to the death your
right to say it. -- Voltaire
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120316/2622895c/attachment.asc>


More information about the ffmpeg-devel mailing list