Browse code

ZeroCodec Decoder

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>

Derek Buitenhuis authored on 2012/03/19 02:00:18
Showing 9 changed files
... ...
@@ -16,6 +16,7 @@ version next:
16 16
 - swapuv filter
17 17
 - bbox filter
18 18
 - XBM encoder
19
+- ZeroCodec decoder
19 20
 
20 21
 
21 22
 version 0.10:
... ...
@@ -244,6 +244,7 @@ Codecs:
244 244
   xan.c                                 Mike Melanson
245 245
   xl.c                                  Kostya Shishkov
246 246
   xvmc.c                                Ivan Kalvachev
247
+  zerocodec.c                           Derek Buitenhuis
247 248
   zmbv*                                 Kostya Shishkov
248 249
 
249 250
 Hardware acceleration:
... ...
@@ -1527,6 +1527,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
1527 1527
 wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
1528 1528
 wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
1529 1529
 wmv3image_decoder_select="wmv3_decoder"
1530
+zerocodec_decoder_select="zlib"
1530 1531
 zlib_decoder_select="zlib"
1531 1532
 zlib_encoder_select="zlib"
1532 1533
 zmbv_decoder_select="zlib"
... ...
@@ -351,6 +351,7 @@ library:
351 351
 @item eXtended BINary text (XBIN) @tab @tab X
352 352
 @item YUV4MPEG pipe             @tab X @tab X
353 353
 @item Psygnosis YOP             @tab   @tab X
354
+@item ZeroCodec Lossless Video  @tab   @tab X
354 355
 @end multitable
355 356
 
356 357
 @code{X} means that encoding (resp. decoding) is supported.
... ...
@@ -493,6 +493,7 @@ OBJS-$(CONFIG_Y41P_ENCODER)            += y41penc.o
493 493
 OBJS-$(CONFIG_YOP_DECODER)             += yop.o
494 494
 OBJS-$(CONFIG_YUV4_DECODER)            += yuv4dec.o
495 495
 OBJS-$(CONFIG_YUV4_ENCODER)            += yuv4enc.o
496
+OBJS-$(CONFIG_ZEROCODEC_DECODER)       += zerocodec.o
496 497
 OBJS-$(CONFIG_ZLIB_DECODER)            += lcldec.o
497 498
 OBJS-$(CONFIG_ZLIB_ENCODER)            += lclenc.o
498 499
 OBJS-$(CONFIG_ZMBV_DECODER)            += zmbv.o
... ...
@@ -255,6 +255,7 @@ void avcodec_register_all(void)
255 255
     REGISTER_ENCDEC  (Y41P, y41p);
256 256
     REGISTER_DECODER (YOP, yop);
257 257
     REGISTER_ENCDEC  (YUV4, yuv4);
258
+    REGISTER_DECODER (ZEROCODEC, zerocodec);
258 259
     REGISTER_ENCDEC  (ZLIB, zlib);
259 260
     REGISTER_ENCDEC  (ZMBV, zmbv);
260 261
 
... ...
@@ -248,6 +248,7 @@ enum CodecID {
248 248
     CODEC_ID_XWD,
249 249
     CODEC_ID_CDXL,
250 250
     CODEC_ID_XBM,
251
+    CODEC_ID_ZEROCODEC,
251 252
     CODEC_ID_Y41P       = MKBETAG('Y','4','1','P'),
252 253
     CODEC_ID_ESCAPE130  = MKBETAG('E','1','3','0'),
253 254
     CODEC_ID_AVRP       = MKBETAG('A','V','R','P'),
254 255
new file mode 100644
... ...
@@ -0,0 +1,182 @@
0
+/*
1
+ * ZeroCodec Decoder
2
+ *
3
+ * Copyright (c) 2012, Derek Buitenhuis
4
+ *
5
+ * This file is part of FFMpeg.
6
+ *
7
+ * Permission to use, copy, modify, and/or distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ */
19
+
20
+#include <zlib.h>
21
+#include "avcodec.h"
22
+
23
+typedef struct {
24
+    AVFrame  previous_frame;
25
+    z_stream zstream;
26
+    int size;
27
+} ZeroCodecContext;
28
+
29
+static int zerocodec_decode_frame(AVCodecContext *avctx, void *data,
30
+                                  int *data_size, AVPacket *avpkt)
31
+{
32
+    ZeroCodecContext *zc = avctx->priv_data;
33
+    AVFrame *pic         = avctx->coded_frame;
34
+    AVFrame *prev_pic    = &zc->previous_frame;
35
+    z_stream *zstream    = &zc->zstream;
36
+    uint8_t *prev, *dst;
37
+    int i, j, zret;
38
+
39
+    pic->reference = 3;
40
+
41
+    if (avctx->get_buffer(avctx, pic) < 0) {
42
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
43
+        return AVERROR(ENOMEM);
44
+    }
45
+
46
+    zret = inflateReset(zstream);
47
+
48
+    if (zret != Z_OK) {
49
+        av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d\n", zret);
50
+        return AVERROR(EINVAL);
51
+    }
52
+
53
+    zstream->next_in   = avpkt->data;
54
+    zstream->avail_in  = avpkt->size;
55
+
56
+    prev = prev_pic->data[0];
57
+    dst  = pic->data[0];
58
+
59
+    /**
60
+     * ZeroCodec has very simple interframe compression. If a value
61
+     * is the same as the previous frame, set it to 0.
62
+     */
63
+
64
+    if (avpkt->flags & AV_PKT_FLAG_KEY) {
65
+
66
+        pic->key_frame = 1;
67
+        pic->pict_type = AV_PICTURE_TYPE_I;
68
+
69
+        for (i = 0; i < avctx->height; i++) {
70
+
71
+            zstream->next_out  = dst;
72
+            zstream->avail_out = avctx->width << 1;
73
+
74
+            zret = inflate(zstream, Z_SYNC_FLUSH);
75
+
76
+            if (zret != Z_OK && zret != Z_STREAM_END) {
77
+                av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret);
78
+                return AVERROR(EINVAL);
79
+            }
80
+
81
+            dst += pic->linesize[0];
82
+        }
83
+    } else {
84
+
85
+        pic->key_frame = 0;
86
+        pic->pict_type = AV_PICTURE_TYPE_P;
87
+
88
+        for (i = 0; i < avctx->height; i++) {
89
+
90
+            zstream->next_out  = dst;
91
+            zstream->avail_out = avctx->width << 1;
92
+
93
+            zret = inflate(zstream, Z_SYNC_FLUSH);
94
+
95
+            if (zret != Z_OK && zret != Z_STREAM_END) {
96
+                av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret);
97
+                return AVERROR(EINVAL);
98
+            }
99
+
100
+            for (j = 0; j < avctx->width << 1; j++)
101
+                dst[j] += prev[j] & -!dst[j];
102
+
103
+            prev += prev_pic->linesize[0];
104
+            dst  += pic->linesize[0];
105
+        }
106
+    }
107
+
108
+    /* Release the previous buffer if need be */
109
+    if (prev_pic->data[0])
110
+        avctx->release_buffer(avctx, prev_pic);
111
+
112
+    /* Store the previouse frame for use later */
113
+    *prev_pic = *pic;
114
+
115
+    *data_size = sizeof(AVFrame);
116
+    *(AVFrame *)data = *pic;
117
+
118
+    return avpkt->size;
119
+}
120
+
121
+static av_cold int zerocodec_decode_close(AVCodecContext *avctx)
122
+{
123
+    ZeroCodecContext *zc = avctx->priv_data;
124
+    AVFrame *prev_pic    = &zc->previous_frame;
125
+
126
+    inflateEnd(&zc->zstream);
127
+
128
+    /* Release last frame */
129
+    if (prev_pic->data[0])
130
+        avctx->release_buffer(avctx, prev_pic);
131
+
132
+    av_freep(&avctx->coded_frame);
133
+
134
+    return 0;
135
+}
136
+
137
+static av_cold int zerocodec_decode_init(AVCodecContext *avctx)
138
+{
139
+    ZeroCodecContext *zc = avctx->priv_data;
140
+    z_stream *zstream    = &zc->zstream;
141
+    int zret;
142
+
143
+    avctx->pix_fmt             = PIX_FMT_UYVY422;
144
+    avctx->bits_per_raw_sample = 8;
145
+
146
+    zc->size = avpicture_get_size(avctx->pix_fmt,
147
+                                  avctx->width, avctx->height);
148
+
149
+    zstream->zalloc = Z_NULL;
150
+    zstream->zfree  = Z_NULL;
151
+    zstream->opaque = Z_NULL;
152
+
153
+    zret = inflateInit(zstream);
154
+
155
+    if (zret != Z_OK) {
156
+        av_log(avctx, AV_LOG_ERROR, "Could not initialize inflate: %d\n", zret);
157
+        return AVERROR(ENOMEM);
158
+    }
159
+
160
+    avctx->coded_frame = avcodec_alloc_frame();
161
+
162
+    if (!avctx->coded_frame) {
163
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame buffer.\n");
164
+        zerocodec_decode_close(avctx);
165
+        return AVERROR(ENOMEM);
166
+    }
167
+
168
+    return 0;
169
+}
170
+
171
+AVCodec ff_zerocodec_decoder = {
172
+    .type           = AVMEDIA_TYPE_VIDEO,
173
+    .name           = "zerocodec",
174
+    .id             = CODEC_ID_ZEROCODEC,
175
+    .priv_data_size = sizeof(ZeroCodecContext),
176
+    .init           = zerocodec_decode_init,
177
+    .decode         = zerocodec_decode_frame,
178
+    .close          = zerocodec_decode_close,
179
+    .capabilities   = CODEC_CAP_DR1,
180
+    .long_name      = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"),
181
+};
... ...
@@ -298,6 +298,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
298 298
     { CODEC_ID_VBLE,         MKTAG('V', 'B', 'L', 'E') },
299 299
     { CODEC_ID_ESCAPE130,    MKTAG('E', '1', '3', '0') },
300 300
     { CODEC_ID_DXTORY,       MKTAG('x', 't', 'o', 'r') },
301
+    { CODEC_ID_ZEROCODEC,    MKTAG('Z', 'E', 'C', 'O') },
301 302
     { CODEC_ID_Y41P,         MKTAG('Y', '4', '1', 'P') },
302 303
     { CODEC_ID_NONE,         0 }
303 304
 };