GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/screenpresso.c Lines: 65 76 85.5 %
Date: 2020-09-25 14:59:26 Branches: 19 26 73.1 %

Line Branch Exec Source
1
/*
2
 * Screenpresso decoder
3
 * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
/**
23
 * @file
24
 * Screenpresso decoder
25
 *
26
 * Fourcc: SPV1
27
 *
28
 * Screenpresso simply horizontally flips and then deflates frames,
29
 * alternating full pictures and deltas. Deltas are related to the currently
30
 * rebuilt frame (not the reference), and since there is no coordinate system
31
 * they contain exactly as many pixel as the keyframe.
32
 *
33
 * Supports: BGR0, BGR24, RGB555
34
 */
35
36
#include <stdint.h>
37
#include <string.h>
38
#include <zlib.h>
39
40
#include "libavutil/imgutils.h"
41
#include "libavutil/internal.h"
42
#include "libavutil/mem.h"
43
44
#include "avcodec.h"
45
#include "internal.h"
46
47
typedef struct ScreenpressoContext {
48
    AVFrame *current;
49
50
    /* zlib interaction */
51
    uint8_t *inflated_buf;
52
    uLongf inflated_size;
53
} ScreenpressoContext;
54
55
6
static av_cold int screenpresso_close(AVCodecContext *avctx)
56
{
57
6
    ScreenpressoContext *ctx = avctx->priv_data;
58
59
6
    av_frame_free(&ctx->current);
60
6
    av_freep(&ctx->inflated_buf);
61
62
6
    return 0;
63
}
64
65
6
static av_cold int screenpresso_init(AVCodecContext *avctx)
66
{
67
6
    ScreenpressoContext *ctx = avctx->priv_data;
68
69
    /* These needs to be set to estimate uncompressed buffer */
70
6
    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
71
6
    if (ret < 0) {
72
        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
73
               avctx->width, avctx->height);
74
        return ret;
75
    }
76
77
    /* Allocate current frame */
78
6
    ctx->current = av_frame_alloc();
79
6
    if (!ctx->current)
80
        return AVERROR(ENOMEM);
81
82
    /* Allocate maximum size possible, a full RGBA frame */
83
6
    ctx->inflated_size = avctx->width * avctx->height * 4;
84
6
    ctx->inflated_buf  = av_malloc(ctx->inflated_size);
85
6
    if (!ctx->inflated_buf)
86
        return AVERROR(ENOMEM);
87
88
6
    return 0;
89
}
90
91
13
static void sum_delta_flipped(uint8_t       *dst, int dst_linesize,
92
                              const uint8_t *src, int src_linesize,
93
                              int bytewidth, int height)
94
{
95
    int i;
96
3493
    for (; height > 0; height--) {
97
3480
        const uint8_t *src1 = &src[(height - 1) * src_linesize];
98
4073880
        for (i = 0; i < bytewidth; i++)
99
4070400
            dst[i] += src1[i];
100
3480
        dst += dst_linesize;
101
    }
102
13
}
103
104
21
static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
105
                                     int *got_frame, AVPacket *avpkt)
106
{
107
21
    ScreenpressoContext *ctx = avctx->priv_data;
108
21
    AVFrame *frame = data;
109
21
    uLongf length = ctx->inflated_size;
110
    int keyframe, component_size, src_linesize;
111
    int ret;
112
113
    /* Size check */
114
21
    if (avpkt->size < 3) {
115
        av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
116
        return AVERROR_INVALIDDATA;
117
    }
118
119
    /* Compression level (4 bits) and keyframe information (1 bit) */
120
21
    av_log(avctx, AV_LOG_DEBUG, "Compression level %d\n", avpkt->data[0] >> 4);
121
21
    keyframe = avpkt->data[0] & 1;
122
123
    /* Pixel size */
124
21
    component_size = ((avpkt->data[1] >> 2) & 0x03) + 1;
125

21
    switch (component_size) {
126
10
    case 2:
127
10
        avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
128
10
        break;
129
5
    case 3:
130
5
        avctx->pix_fmt = AV_PIX_FMT_BGR24;
131
5
        break;
132
6
    case 4:
133
6
        avctx->pix_fmt = AV_PIX_FMT_BGR0;
134
6
        break;
135
    default:
136
        av_log(avctx, AV_LOG_ERROR, "Invalid bits per pixel value (%d)\n",
137
               component_size);
138
        return AVERROR_INVALIDDATA;
139
    }
140
141
    /* Inflate the frame after the 2 byte header */
142
21
    ret = uncompress(ctx->inflated_buf, &length,
143
21
                     avpkt->data + 2, avpkt->size - 2);
144
21
    if (ret) {
145
2
        av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret);
146
2
        return AVERROR_UNKNOWN;
147
    }
148
149
19
    ret = ff_reget_buffer(avctx, ctx->current, 0);
150
19
    if (ret < 0)
151
        return ret;
152
153
    /* Codec has aligned strides */
154
19
    src_linesize = FFALIGN(avctx->width * component_size, 4);
155
156
    /* When a keyframe is found, copy it (flipped) */
157
19
    if (keyframe)
158
6
        av_image_copy_plane(ctx->current->data[0] +
159
6
                            ctx->current->linesize[0] * (avctx->height - 1),
160
6
                            -1 * ctx->current->linesize[0],
161
6
                            ctx->inflated_buf, src_linesize,
162
6
                            avctx->width * component_size, avctx->height);
163
    /* Otherwise sum the delta on top of the current frame */
164
    else
165
13
        sum_delta_flipped(ctx->current->data[0], ctx->current->linesize[0],
166
13
                          ctx->inflated_buf, src_linesize,
167
13
                          avctx->width * component_size, avctx->height);
168
169
    /* Frame is ready to be output */
170
19
    ret = av_frame_ref(frame, ctx->current);
171
19
    if (ret < 0)
172
        return ret;
173
174
    /* Usual properties */
175
19
    if (keyframe) {
176
6
        frame->pict_type = AV_PICTURE_TYPE_I;
177
6
        frame->key_frame = 1;
178
    } else {
179
13
        frame->pict_type = AV_PICTURE_TYPE_P;
180
    }
181
19
    *got_frame = 1;
182
183
19
    return avpkt->size;
184
}
185
186
AVCodec ff_screenpresso_decoder = {
187
    .name           = "screenpresso",
188
    .long_name      = NULL_IF_CONFIG_SMALL("Screenpresso"),
189
    .type           = AVMEDIA_TYPE_VIDEO,
190
    .id             = AV_CODEC_ID_SCREENPRESSO,
191
    .init           = screenpresso_init,
192
    .decode         = screenpresso_decode_frame,
193
    .close          = screenpresso_close,
194
    .priv_data_size = sizeof(ScreenpressoContext),
195
    .capabilities   = AV_CODEC_CAP_DR1,
196
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
197
                      FF_CODEC_CAP_INIT_CLEANUP,
198
};