ZeroCodec Decoder
authorDerek Buitenhuis <derek.buitenhuis@gmail.com>
Sun, 18 Mar 2012 17:00:18 +0000 (13:00 -0400)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 18 Mar 2012 23:19:13 +0000 (00:19 +0100)
An obscure Japanese lossless video codec, originally intended
for use with a remote desktop application.

Signed-off-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Changelog
MAINTAINERS
configure
doc/general.texi
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavcodec/zerocodec.c [new file with mode: 0644]
libavformat/riff.c

index cfcaf6b..e427db7 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@ version next:
 - swapuv filter
 - bbox filter
 - XBM encoder
+- ZeroCodec decoder
 
 
 version 0.10:
index 21062be..f1a46b7 100644 (file)
@@ -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:
index 55a1f45..c6a4d17 100755 (executable)
--- 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"
index 0d520ad..f2c21b9 100644 (file)
@@ -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
+@item ZeroCodec Lossless Video  @tab   @tab X
 @end multitable
 
 @code{X} means that encoding (resp. decoding) is supported.
index 08a5728..77ba256 100644 (file)
@@ -493,6 +493,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
index 26ea1dc..7337d8c 100644 (file)
@@ -255,6 +255,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);
 
index 235ebf2..2f8a8c3 100644 (file)
@@ -248,6 +248,7 @@ enum CodecID {
     CODEC_ID_XWD,
     CODEC_ID_CDXL,
     CODEC_ID_XBM,
+    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/zerocodec.c b/libavcodec/zerocodec.c
new file mode 100644 (file)
index 0000000..826063c
--- /dev/null
@@ -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"),
+};
index 774a02f..650bea6 100644 (file)
@@ -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 }
 };