[FFmpeg-devel] [PATCH] ZeroCodec Decoder

Derek Buitenhuis derek.buitenhuis at gmail.com
Sun Mar 18 18:00:18 CET 2012


An obscure Japanese lossless video codec, originally intended
for use with a remote desktop application.

Signed-off-by: Derek Buitenhuis <derek.buitenhuis at gmail.com>
---
 Changelog              |    1 +
 MAINTAINERS            |    1 +
 configure              |    1 +
 doc/general.texi       |    1 +
 libavcodec/Makefile    |    1 +
 libavcodec/allcodecs.c |    1 +
 libavcodec/avcodec.h   |    1 +
 libavcodec/version.h   |    2 +-
 libavcodec/zerocodec.c |  182 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/riff.c     |    1 +
 10 files changed, 191 insertions(+), 1 deletions(-)
 create mode 100644 libavcodec/zerocodec.c

diff --git a/Changelog b/Changelog
index 8c7eb1b..d5bdc50 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version next:
 - libutvideo encoder wrapper (--enable-libutvideo)
 - swapuv filter
 - bbox filter
+- ZeroCodec decoder
 
 
 version 0.10:
diff --git a/MAINTAINERS b/MAINTAINERS
index 21062be..f1a46b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -244,6 +244,7 @@ Codecs:
   xan.c                                 Mike Melanson
   xl.c                                  Kostya Shishkov
   xvmc.c                                Ivan Kalvachev
+  zerocodec.c                           Derek Buitenhuis
   zmbv*                                 Kostya Shishkov
 
 Hardware acceleration:
diff --git a/configure b/configure
index f46f8d3..d3f9b9a 100755
--- a/configure
+++ b/configure
@@ -1527,6 +1527,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
 wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
 wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
 wmv3image_decoder_select="wmv3_decoder"
+zerocodec_decoder_select="zlib"
 zlib_decoder_select="zlib"
 zlib_encoder_select="zlib"
 zmbv_decoder_select="zlib"
diff --git a/doc/general.texi b/doc/general.texi
index dd744f0..de9a32a 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -351,6 +351,7 @@ library:
 @item eXtended BINary text (XBIN) @tab @tab X
 @item YUV4MPEG pipe             @tab X @tab X
 @item Psygnosis YOP             @tab   @tab X
+ at item ZeroCodec Lossless Video  @tab   @tab X
 @end multitable
 
 @code{X} means that encoding (resp. decoding) is supported.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 69ba632..6298f79 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -492,6 +492,7 @@ OBJS-$(CONFIG_Y41P_ENCODER)            += y41penc.o
 OBJS-$(CONFIG_YOP_DECODER)             += yop.o
 OBJS-$(CONFIG_YUV4_DECODER)            += yuv4dec.o
 OBJS-$(CONFIG_YUV4_ENCODER)            += yuv4enc.o
+OBJS-$(CONFIG_ZEROCODEC_DECODER)       += zerocodec.o
 OBJS-$(CONFIG_ZLIB_DECODER)            += lcldec.o
 OBJS-$(CONFIG_ZLIB_ENCODER)            += lclenc.o
 OBJS-$(CONFIG_ZMBV_DECODER)            += zmbv.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 52a67f3..ecdaa5e 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -254,6 +254,7 @@ void avcodec_register_all(void)
     REGISTER_ENCDEC  (Y41P, y41p);
     REGISTER_DECODER (YOP, yop);
     REGISTER_ENCDEC  (YUV4, yuv4);
+    REGISTER_DECODER (ZEROCODEC, zerocodec);
     REGISTER_ENCDEC  (ZLIB, zlib);
     REGISTER_ENCDEC  (ZMBV, zmbv);
 
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'),
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 95fbd00..c91ac22 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -21,7 +21,7 @@
 #define AVCODEC_VERSION_H
 
 #define LIBAVCODEC_VERSION_MAJOR 54
-#define LIBAVCODEC_VERSION_MINOR  10
+#define LIBAVCODEC_VERSION_MINOR  11
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c
new file mode 100644
index 0000000..824e4d1
--- /dev/null
+++ b/libavcodec/zerocodec.c
@@ -0,0 +1,182 @@
+/*
+ * ZeroCodec Decoder
+ *
+ * Copyright (c) 2012, Derek Buitenhuis
+ *
+ * This file is part of FFMpeg.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <zlib.h>
+#include "avcodec.h"
+
+typedef struct {
+    AVFrame  previous_frame;
+    z_stream zstream; 
+    int size;
+} ZeroCodecContext;
+
+static int zerocodec_decode_frame(AVCodecContext *avctx, void *data,
+                                  int *data_size, AVPacket *avpkt)
+{
+    ZeroCodecContext *zc = avctx->priv_data;
+    AVFrame *pic         = avctx->coded_frame;
+    AVFrame *prev_pic    = &zc->previous_frame;
+    z_stream *zstream    = &zc->zstream;
+    uint8_t *prev, *dst;
+    int i, j, zret;
+
+    pic->reference = 3;
+
+    if (avctx->get_buffer(avctx, pic) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+        return AVERROR(ENOMEM);
+    }
+
+    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;
+
+    prev = prev_pic->data[0];
+    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) {
+
+        pic->key_frame = 1;
+        pic->pict_type = AV_PICTURE_TYPE_I;
+
+        for (i = 0; i < avctx->height; i++) {
+
+            zstream->next_out  = dst;
+            zstream->avail_out = avctx->width << 1;
+
+            zret = inflate(zstream, Z_SYNC_FLUSH);
+
+            if (zret != Z_OK && zret != Z_STREAM_END) {
+                av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret);
+                return AVERROR(EINVAL);
+            }
+
+            dst += pic->linesize[0];
+        }
+    } else {
+
+        pic->key_frame = 0;
+        pic->pict_type = AV_PICTURE_TYPE_P;
+
+        for (i = 0; i < avctx->height; i++) {
+
+            zstream->next_out  = dst;
+            zstream->avail_out = avctx->width << 1;
+
+            zret = inflate(zstream, Z_SYNC_FLUSH);
+
+            if (zret != Z_OK && zret != Z_STREAM_END) {
+                av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret);
+                return AVERROR(EINVAL);
+            }
+
+            for (j = 0; j < avctx->width << 1; j++)
+                dst[j] += prev[j] & -!dst[j];
+
+            prev += prev_pic->linesize[0];
+            dst  += pic->linesize[0];
+        }
+    }
+
+    /* Release the previous buffer if need be */
+    if (prev_pic->data[0])
+        avctx->release_buffer(avctx, prev_pic);
+
+    /* Store the previouse frame for use later */
+    *prev_pic = *pic;
+
+    *data_size = sizeof(AVFrame);
+    *(AVFrame *)data = *pic;
+
+    return avpkt->size;
+}
+
+static av_cold int zerocodec_decode_close(AVCodecContext *avctx)
+{
+    ZeroCodecContext *zc = avctx->priv_data;
+    AVFrame *prev_pic    = &zc->previous_frame;
+
+    inflateEnd(&zc->zstream);
+
+    /* Release last frame */
+    if (prev_pic->data[0])
+        avctx->release_buffer(avctx, prev_pic);
+
+    av_freep(&avctx->coded_frame);
+
+    return 0;
+}
+
+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");
+        zerocodec_decode_close(avctx);
+        return AVERROR(ENOMEM);
+    }
+
+    return 0;
+}
+
+AVCodec ff_zerocodec_decoder = {
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .name           = "zerocodec",
+    .id             = CODEC_ID_ZEROCODEC,
+    .priv_data_size = sizeof(ZeroCodecContext),
+    .init           = zerocodec_decode_init,
+    .decode         = zerocodec_decode_frame,
+    .close          = zerocodec_decode_close,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"),
+};
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 774a02f..650bea6 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -298,6 +298,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
     { CODEC_ID_VBLE,         MKTAG('V', 'B', 'L', 'E') },
     { CODEC_ID_ESCAPE130,    MKTAG('E', '1', '3', '0') },
     { CODEC_ID_DXTORY,       MKTAG('x', 't', 'o', 'r') },
+    { CODEC_ID_ZEROCODEC,    MKTAG('Z', 'E', 'C', 'O') },
     { CODEC_ID_Y41P,         MKTAG('Y', '4', '1', 'P') },
     { CODEC_ID_NONE,         0 }
 };
-- 
1.7.9.1



More information about the ffmpeg-devel mailing list