GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/mwsc.c Lines: 0 86 0.0 %
Date: 2019-11-18 18:00:01 Branches: 0 36 0.0 %

Line Branch Exec Source
1
/*
2
 * MatchWare Screen Capture Codec decoder
3
 *
4
 * Copyright (c) 2018 Paul B Mahol
5
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "avcodec.h"
28
#include "bytestream.h"
29
#include "internal.h"
30
31
#include <zlib.h>
32
33
typedef struct MWSCContext {
34
    unsigned int      decomp_size;
35
    uint8_t          *decomp_buf;
36
    z_stream          zstream;
37
    AVFrame          *prev_frame;
38
} MWSCContext;
39
40
static int rle_uncompress(GetByteContext *gb, PutByteContext *pb, GetByteContext *gbp,
41
                          int width, int height, int stride, int pb_linesize, int gbp_linesize)
42
{
43
    int intra = 1, w = 0;
44
45
    bytestream2_seek_p(pb, (height - 1) * pb_linesize, SEEK_SET);
46
47
    while (bytestream2_get_bytes_left(gb) > 0) {
48
        uint32_t fill = bytestream2_get_le24(gb);
49
        unsigned run = bytestream2_get_byte(gb);
50
51
        if (run == 0) {
52
            run = bytestream2_get_le32(gb);
53
            for (int j = 0; j < run; j++, w++) {
54
                if (w == width) {
55
                    w = 0;
56
                    bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
57
                }
58
                bytestream2_put_le24(pb, fill);
59
            }
60
        } else if (run == 255) {
61
            int pos = bytestream2_tell_p(pb);
62
63
            bytestream2_seek(gbp, pos, SEEK_SET);
64
            for (int j = 0; j < fill; j++, w++) {
65
                if (w == width) {
66
                    w = 0;
67
                    bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
68
                    bytestream2_seek(gbp, -(gbp_linesize + stride), SEEK_CUR);
69
                }
70
                bytestream2_put_le24(pb, bytestream2_get_le24(gbp));
71
            }
72
73
            intra = 0;
74
        } else {
75
            for (int j = 0; j < run; j++, w++) {
76
                if (w == width) {
77
                    w = 0;
78
                    bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR);
79
                }
80
                bytestream2_put_le24(pb, fill);
81
            }
82
        }
83
    }
84
85
    return intra;
86
}
87
88
static int decode_frame(AVCodecContext *avctx,
89
                        void *data, int *got_frame,
90
                        AVPacket *avpkt)
91
{
92
    MWSCContext *s = avctx->priv_data;
93
    AVFrame *frame = data;
94
    uint8_t *buf = avpkt->data;
95
    int buf_size = avpkt->size;
96
    GetByteContext gb;
97
    GetByteContext gbp;
98
    PutByteContext pb;
99
    int ret;
100
101
    ret = inflateReset(&s->zstream);
102
    if (ret != Z_OK) {
103
        av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
104
        return AVERROR_EXTERNAL;
105
    }
106
    s->zstream.next_in   = buf;
107
    s->zstream.avail_in  = buf_size;
108
    s->zstream.next_out  = s->decomp_buf;
109
    s->zstream.avail_out = s->decomp_size;
110
    ret = inflate(&s->zstream, Z_FINISH);
111
    if (ret != Z_STREAM_END) {
112
        av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret);
113
        return AVERROR_EXTERNAL;
114
    }
115
116
    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
117
        return ret;
118
119
    bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out);
120
    bytestream2_init(&gbp, s->prev_frame->data[0], avctx->height * s->prev_frame->linesize[0]);
121
    bytestream2_init_writer(&pb, frame->data[0], avctx->height * frame->linesize[0]);
122
123
    frame->key_frame = rle_uncompress(&gb, &pb, &gbp, avctx->width, avctx->height, avctx->width * 3,
124
                                      frame->linesize[0], s->prev_frame->linesize[0]);
125
126
    frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
127
128
    av_frame_unref(s->prev_frame);
129
    if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
130
        return ret;
131
132
    *got_frame = 1;
133
134
    return avpkt->size;
135
}
136
137
static av_cold int decode_init(AVCodecContext *avctx)
138
{
139
    MWSCContext *s = avctx->priv_data;
140
    int64_t size;
141
    int zret;
142
143
    avctx->pix_fmt = AV_PIX_FMT_BGR24;
144
145
    size = 32LL * avctx->height * avctx->width;
146
    if (size >= INT32_MAX)
147
        return AVERROR_INVALIDDATA;
148
    s->decomp_size = size;
149
    if (!(s->decomp_buf = av_malloc(s->decomp_size)))
150
        return AVERROR(ENOMEM);
151
152
    s->zstream.zalloc = Z_NULL;
153
    s->zstream.zfree = Z_NULL;
154
    s->zstream.opaque = Z_NULL;
155
    zret = inflateInit(&s->zstream);
156
    if (zret != Z_OK) {
157
        av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
158
        return AVERROR_EXTERNAL;
159
    }
160
161
    s->prev_frame = av_frame_alloc();
162
    if (!s->prev_frame)
163
        return AVERROR(ENOMEM);
164
165
    return 0;
166
}
167
168
static av_cold int decode_close(AVCodecContext *avctx)
169
{
170
    MWSCContext *s = avctx->priv_data;
171
172
    av_frame_free(&s->prev_frame);
173
    av_freep(&s->decomp_buf);
174
    s->decomp_size = 0;
175
    inflateEnd(&s->zstream);
176
177
    return 0;
178
}
179
180
AVCodec ff_mwsc_decoder = {
181
    .name             = "mwsc",
182
    .long_name        = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"),
183
    .type             = AVMEDIA_TYPE_VIDEO,
184
    .id               = AV_CODEC_ID_MWSC,
185
    .priv_data_size   = sizeof(MWSCContext),
186
    .init             = decode_init,
187
    .close            = decode_close,
188
    .decode           = decode_frame,
189
    .capabilities     = AV_CODEC_CAP_DR1,
190
    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
191
                        FF_CODEC_CAP_INIT_CLEANUP,
192
};