Browse code

Merge commit '9a3202a98b2e095b54dd784c3e01a09a676fc3fa'

* commit '9a3202a98b2e095b54dd784c3e01a09a676fc3fa':
Screenpresso SPV1 decoder

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>

Hendrik Leppkes authored on 2015/10/03 19:22:41
Showing 12 changed files
... ...
@@ -13,6 +13,7 @@ version <next>:
13 13
 - agate filter
14 14
 - chromakey filter
15 15
 - maskedmerge filter
16
+- Screenpresso SPV1 decoding
16 17
 
17 18
 
18 19
 version 2.8:
... ...
@@ -2325,6 +2325,7 @@ rv20_decoder_select="h263_decoder"
2325 2325
 rv20_encoder_select="h263_encoder"
2326 2326
 rv30_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp"
2327 2327
 rv40_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp"
2328
+screenpresso_decoder_deps="zlib"
2328 2329
 shorten_decoder_select="golomb"
2329 2330
 sipr_decoder_select="lsp"
2330 2331
 snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp"
... ...
@@ -475,6 +475,7 @@ library:
475 475
 @item RTSP                      @tab X @tab X
476 476
 @item SAP                       @tab X @tab X
477 477
 @item SBG                       @tab   @tab X
478
+@item Screenpresso              @tab   @tab X
478 479
 @item SDP                       @tab   @tab X
479 480
 @item Sega FILM/CPK             @tab   @tab X
480 481
     @tab Used in many Sega Saturn console games.
... ...
@@ -455,6 +455,7 @@ OBJS-$(CONFIG_SAMI_DECODER)            += samidec.o ass.o htmlsubtitles.o
455 455
 OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
456 456
 OBJS-$(CONFIG_S302M_ENCODER)           += s302menc.o
457 457
 OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
458
+OBJS-$(CONFIG_SCREENPRESSO_DECODER)    += screenpresso.o
458 459
 OBJS-$(CONFIG_SGI_DECODER)             += sgidec.o
459 460
 OBJS-$(CONFIG_SGI_ENCODER)             += sgienc.o rle.o
460 461
 OBJS-$(CONFIG_SGIRLE_DECODER)          += sgirledec.o
... ...
@@ -285,6 +285,7 @@ void avcodec_register_all(void)
285 285
     REGISTER_DECODER(RV40,              rv40);
286 286
     REGISTER_ENCDEC (S302M,             s302m);
287 287
     REGISTER_DECODER(SANM,              sanm);
288
+    REGISTER_DECODER(SCREENPRESSO,      screenpresso);
288 289
     REGISTER_ENCDEC (SGI,               sgi);
289 290
     REGISTER_DECODER(SGIRLE,            sgirle);
290 291
     REGISTER_DECODER(SMACKER,           smacker);
... ...
@@ -296,6 +296,7 @@ enum AVCodecID {
296 296
     AV_CODEC_ID_HAP,
297 297
     AV_CODEC_ID_DDS,
298 298
     AV_CODEC_ID_DXV,
299
+    AV_CODEC_ID_SCREENPRESSO,
299 300
 
300 301
     AV_CODEC_ID_Y41P = 0x8000,
301 302
     AV_CODEC_ID_AVRP,
... ...
@@ -1266,6 +1266,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
1266 1266
         .long_name = NULL_IF_CONFIG_SMALL("Resolume DXV"),
1267 1267
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
1268 1268
     },
1269
+    {
1270
+        .id        = AV_CODEC_ID_SCREENPRESSO,
1271
+        .type      = AVMEDIA_TYPE_VIDEO,
1272
+        .name      = "screenpresso",
1273
+        .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"),
1274
+        .props     = AV_CODEC_PROP_LOSSLESS,
1275
+    },
1269 1276
 
1270 1277
     /* image codecs */
1271 1278
     {
1272 1279
new file mode 100644
... ...
@@ -0,0 +1,186 @@
0
+/*
1
+ * Screenpresso decoder
2
+ * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * Screenpresso decoder
24
+ *
25
+ * Fourcc: SPV1
26
+ *
27
+ * Screenpresso simply horizontally flips and then deflates frames,
28
+ * alternating full pictures and deltas. Deltas are related to the currently
29
+ * rebuilt frame (not the reference), and since there is no coordinate system
30
+ * they contain exactly as many pixel as the keyframe.
31
+ *
32
+ * Supports: BGR24
33
+ */
34
+
35
+#include <stdint.h>
36
+#include <string.h>
37
+#include <zlib.h>
38
+
39
+#include "libavutil/imgutils.h"
40
+#include "libavutil/internal.h"
41
+
42
+#include "avcodec.h"
43
+#include "internal.h"
44
+
45
+typedef struct ScreenpressoContext {
46
+    AVFrame *current;
47
+
48
+    /* zlib interation */
49
+    uint8_t *inflated_buf;
50
+    uLongf inflated_size;
51
+} ScreenpressoContext;
52
+
53
+static av_cold int screenpresso_close(AVCodecContext *avctx)
54
+{
55
+    ScreenpressoContext *ctx = avctx->priv_data;
56
+
57
+    av_frame_free(&ctx->current);
58
+    av_freep(&ctx->inflated_buf);
59
+
60
+    return 0;
61
+}
62
+
63
+static av_cold int screenpresso_init(AVCodecContext *avctx)
64
+{
65
+    ScreenpressoContext *ctx = avctx->priv_data;
66
+
67
+    /* These needs to be set to estimate uncompressed buffer */
68
+    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
69
+    if (ret < 0) {
70
+        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
71
+               avctx->width, avctx->height);
72
+        return ret;
73
+    }
74
+
75
+    /* Allocate current frame */
76
+    ctx->current = av_frame_alloc();
77
+    if (!ctx->current)
78
+        return AVERROR(ENOMEM);
79
+
80
+    avctx->pix_fmt = AV_PIX_FMT_BGR24;
81
+
82
+    return 0;
83
+}
84
+
85
+static void sum_delta_flipped(uint8_t       *dst, int dst_linesize,
86
+                              const uint8_t *src, int src_linesize,
87
+                              int bytewidth, int height)
88
+{
89
+    int i;
90
+    for (; height > 0; height--) {
91
+        for (i = 0; i < bytewidth; i++)
92
+            dst[i] += src[(height - 1) * src_linesize + i];
93
+        dst += dst_linesize;
94
+    }
95
+}
96
+
97
+static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
98
+                                     int *got_frame, AVPacket *avpkt)
99
+{
100
+    ScreenpressoContext *ctx = avctx->priv_data;
101
+    AVFrame *frame = data;
102
+    int keyframe;
103
+    int ret;
104
+
105
+    /* Size check */
106
+    if (avpkt->size < 3) {
107
+        av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
108
+        return AVERROR_INVALIDDATA;
109
+    }
110
+
111
+    /* Basic sanity check, but not really harmful */
112
+    if ((avpkt->data[0] != 0x73 && avpkt->data[0] != 0x72) ||
113
+        avpkt->data[1] != 8) { // bpp probably
114
+        av_log(avctx, AV_LOG_WARNING, "Unknown header 0x%02X%02X\n",
115
+               avpkt->data[0], avpkt->data[1]);
116
+    }
117
+    keyframe = (avpkt->data[0] == 0x73);
118
+
119
+    /* Resize deflate buffer and frame on resolution change */
120
+    if (ctx->inflated_size != avctx->width * avctx->height * 3) {
121
+        av_frame_unref(ctx->current);
122
+        ret = ff_get_buffer(avctx, ctx->current, AV_GET_BUFFER_FLAG_REF);
123
+        if (ret < 0)
124
+            return ret;
125
+
126
+        /* If malloc fails, reset len to avoid preserving an invalid value */
127
+        ctx->inflated_size = avctx->width * avctx->height * 3;
128
+        ret = av_reallocp(&ctx->inflated_buf, ctx->inflated_size);
129
+        if (ret < 0) {
130
+            ctx->inflated_size = 0;
131
+            return ret;
132
+        }
133
+    }
134
+
135
+    /* Inflate the frame after the 2 byte header */
136
+    ret = uncompress(ctx->inflated_buf, &ctx->inflated_size,
137
+                     avpkt->data + 2, avpkt->size - 2);
138
+    if (ret) {
139
+        av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret);
140
+        return AVERROR_UNKNOWN;
141
+    }
142
+
143
+    /* When a keyframe is found, copy it (flipped) */
144
+    if (keyframe)
145
+        av_image_copy_plane(ctx->current->data[0] +
146
+                            ctx->current->linesize[0] * (avctx->height - 1),
147
+                            -1 * ctx->current->linesize[0],
148
+                            ctx->inflated_buf, avctx->width * 3,
149
+                            avctx->width * 3, avctx->height);
150
+    /* Otherwise sum the delta on top of the current frame */
151
+    else
152
+        sum_delta_flipped(ctx->current->data[0], ctx->current->linesize[0],
153
+                          ctx->inflated_buf, avctx->width * 3,
154
+                          avctx->width * 3, avctx->height);
155
+
156
+    /* Frame is ready to be output */
157
+    ret = av_frame_ref(frame, ctx->current);
158
+    if (ret < 0)
159
+        return ret;
160
+
161
+    /* Usual properties */
162
+    if (keyframe) {
163
+        frame->pict_type = AV_PICTURE_TYPE_I;
164
+        frame->key_frame = 1;
165
+    } else {
166
+        frame->pict_type = AV_PICTURE_TYPE_P;
167
+    }
168
+    *got_frame = 1;
169
+
170
+    return 0;
171
+}
172
+
173
+AVCodec ff_screenpresso_decoder = {
174
+    .name           = "screenpresso",
175
+    .long_name      = NULL_IF_CONFIG_SMALL("Screenpresso"),
176
+    .type           = AVMEDIA_TYPE_VIDEO,
177
+    .id             = AV_CODEC_ID_SCREENPRESSO,
178
+    .init           = screenpresso_init,
179
+    .decode         = screenpresso_decode_frame,
180
+    .close          = screenpresso_close,
181
+    .priv_data_size = sizeof(ScreenpressoContext),
182
+    .capabilities   = AV_CODEC_CAP_DR1,
183
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
184
+                      FF_CODEC_CAP_INIT_CLEANUP,
185
+};
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR  57
32
-#define LIBAVCODEC_VERSION_MINOR   3
32
+#define LIBAVCODEC_VERSION_MINOR   4
33 33
 #define LIBAVCODEC_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -374,6 +374,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
374 374
     { AV_CODEC_ID_TDSC,         MKTAG('T', 'D', 'S', 'C') },
375 375
     { AV_CODEC_ID_HQ_HQA,       MKTAG('C', 'U', 'V', 'C') },
376 376
     { AV_CODEC_ID_RV40,         MKTAG('R', 'V', '4', '0') },
377
+    { AV_CODEC_ID_SCREENPRESSO, MKTAG('S', 'P', 'V', '1') },
377 378
     { AV_CODEC_ID_NONE,         0 }
378 379
 };
379 380
 
... ...
@@ -286,6 +286,9 @@ fate-roqvideo: CMD = framecrc -i $(TARGET_SAMPLES)/idroq/idlogo.roq -an
286 286
 FATE_VIDEO-$(call DEMDEC, SMUSH, SANM) += fate-sanm
287 287
 fate-sanm: CMD = framecrc -i $(TARGET_SAMPLES)/smush/ronin_part.znm -an -pix_fmt rgb24
288 288
 
289
+FATE_VIDEO-$(call DEMDEC, AVI, SCREENPRESSO) += fate-screenpresso
290
+fate-screenpresso: CMD = framecrc -i $(TARGET_SAMPLES)/spv1/bunny.avi
291
+
289 292
 FATE_VIDEO-$(call DEMDEC, VMD, VMDVIDEO) += fate-sierra-vmd-video
290 293
 fate-sierra-vmd-video: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -pix_fmt rgb24 -an
291 294
 
292 295
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+#tb 0: 1/15
1
+0,          0,          0,        1,   691200, 0xfdbdfad6
2
+0,          1,          1,        1,   691200, 0xc5feb961
3
+0,          4,          4,        1,   691200, 0x4c8c7e23
4
+0,          8,          8,        1,   691200, 0xd95c89f8