[FFmpeg-devel] [PATCH] ZeroCodec Decoder

Derek Buitenhuis derek.buitenhuis at gmail.com
Thu Mar 15 20:59:54 CET 2012


An obscure Japanese screen capture video codec.

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 |  189 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/riff.c     |    1 +
 10 files changed, 198 insertions(+), 1 deletions(-)
 create mode 100644 libavcodec/zerocodec.c

diff --git a/Changelog b/Changelog
index 6b17483..fe13577 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version next:
 - blackdetect filter
 - libutvideo encoder wrapper (--enable-libutvideo)
 - swapuv 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..994e692
--- /dev/null
+++ b/libavcodec/zerocodec.c
@@ -0,0 +1,189 @@
+/*
+ * ZeroCodec Decoder
+ *
+ * Copyright (c) 2012, Derek Buitenhuis
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Libav, nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DEREK BUITENHUIS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "avcodec.h"
+
+#include <zlib.h>
+
+typedef struct {
+    uint8_t *previous_frame;
+    uint8_t *current_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;
+    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;
+
+    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);
+
+    *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 *pic = avctx->coded_frame;
+
+    if (pic->data[0])
+        avctx->release_buffer(avctx, pic);
+
+    inflateEnd(&zc->zstream);
+
+    av_freep(&avctx->coded_frame);
+    av_freep(&zc->current_frame);
+    av_freep(&zc->previous_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");
+        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);
+    }
+
+    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