GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/xwddec.c Lines: 98 144 68.1 %
Date: 2020-10-23 17:01:47 Branches: 78 158 49.4 %

Line Branch Exec Source
1
/*
2
 * XWD image format
3
 *
4
 * Copyright (c) 2012 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 <inttypes.h>
24
25
#include "libavutil/imgutils.h"
26
#include "avcodec.h"
27
#include "bytestream.h"
28
#include "internal.h"
29
#include "xwd.h"
30
31
112
static int xwd_decode_frame(AVCodecContext *avctx, void *data,
32
                            int *got_frame, AVPacket *avpkt)
33
{
34
112
    AVFrame *p = data;
35
112
    const uint8_t *buf = avpkt->data;
36
112
    int i, ret, buf_size = avpkt->size;
37
    uint32_t version, header_size, vclass, ncolors;
38
    uint32_t xoffset, be, bpp, lsize, rsize;
39
    uint32_t pixformat, pixdepth, bunit, bitorder, bpad;
40
    uint32_t rgb[3];
41
    uint8_t *ptr;
42
    int width, height;
43
    GetByteContext gb;
44
45
112
    if (buf_size < XWD_HEADER_SIZE)
46
        return AVERROR_INVALIDDATA;
47
48
112
    bytestream2_init(&gb, buf, buf_size);
49
112
    header_size = bytestream2_get_be32u(&gb);
50
51
112
    version = bytestream2_get_be32u(&gb);
52
112
    if (version != XWD_VERSION) {
53
        av_log(avctx, AV_LOG_ERROR, "unsupported version\n");
54
        return AVERROR_INVALIDDATA;
55
    }
56
57

112
    if (buf_size < header_size || header_size < XWD_HEADER_SIZE) {
58
        av_log(avctx, AV_LOG_ERROR, "invalid header size\n");
59
        return AVERROR_INVALIDDATA;
60
    }
61
62
112
    pixformat     = bytestream2_get_be32u(&gb);
63
112
    pixdepth      = bytestream2_get_be32u(&gb);
64
112
    width         = bytestream2_get_be32u(&gb);
65
112
    height        = bytestream2_get_be32u(&gb);
66
112
    xoffset       = bytestream2_get_be32u(&gb);
67
112
    be            = bytestream2_get_be32u(&gb);
68
112
    bunit         = bytestream2_get_be32u(&gb);
69
112
    bitorder      = bytestream2_get_be32u(&gb);
70
112
    bpad          = bytestream2_get_be32u(&gb);
71
112
    bpp           = bytestream2_get_be32u(&gb);
72
112
    lsize         = bytestream2_get_be32u(&gb);
73
112
    vclass        = bytestream2_get_be32u(&gb);
74
112
    rgb[0]        = bytestream2_get_be32u(&gb);
75
112
    rgb[1]        = bytestream2_get_be32u(&gb);
76
112
    rgb[2]        = bytestream2_get_be32u(&gb);
77
112
    bytestream2_skipu(&gb, 8);
78
112
    ncolors       = bytestream2_get_be32u(&gb);
79
112
    bytestream2_skipu(&gb, header_size - (XWD_HEADER_SIZE - 20));
80
81
112
    if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
82
        return ret;
83
84
112
    av_log(avctx, AV_LOG_DEBUG,
85
           "pixformat %"PRIu32", pixdepth %"PRIu32", bunit %"PRIu32", bitorder %"PRIu32", bpad %"PRIu32"\n",
86
           pixformat, pixdepth, bunit, bitorder, bpad);
87
112
    av_log(avctx, AV_LOG_DEBUG,
88
           "vclass %"PRIu32", ncolors %"PRIu32", bpp %"PRIu32", be %"PRIu32", lsize %"PRIu32", xoffset %"PRIu32"\n",
89
           vclass, ncolors, bpp, be, lsize, xoffset);
90
112
    av_log(avctx, AV_LOG_DEBUG,
91
           "red %0"PRIx32", green %0"PRIx32", blue %0"PRIx32"\n",
92
           rgb[0], rgb[1], rgb[2]);
93
94
112
    if (pixformat > XWD_Z_PIXMAP) {
95
        av_log(avctx, AV_LOG_ERROR, "invalid pixmap format\n");
96
        return AVERROR_INVALIDDATA;
97
    }
98
99

112
    if (pixdepth == 0 || pixdepth > 32) {
100
        av_log(avctx, AV_LOG_ERROR, "invalid pixmap depth\n");
101
        return AVERROR_INVALIDDATA;
102
    }
103
104
112
    if (xoffset) {
105
        avpriv_request_sample(avctx, "xoffset %"PRIu32"", xoffset);
106
        return AVERROR_PATCHWELCOME;
107
    }
108
109
112
    if (be > 1) {
110
        av_log(avctx, AV_LOG_ERROR, "invalid byte order\n");
111
        return AVERROR_INVALIDDATA;
112
    }
113
114
112
    if (bitorder > 1) {
115
        av_log(avctx, AV_LOG_ERROR, "invalid bitmap bit order\n");
116
        return AVERROR_INVALIDDATA;
117
    }
118
119

112
    if (bunit != 8 && bunit != 16 && bunit != 32) {
120
        av_log(avctx, AV_LOG_ERROR, "invalid bitmap unit\n");
121
        return AVERROR_INVALIDDATA;
122
    }
123
124

112
    if (bpad != 8 && bpad != 16 && bpad != 32) {
125
        av_log(avctx, AV_LOG_ERROR, "invalid bitmap scan-line pad\n");
126
        return AVERROR_INVALIDDATA;
127
    }
128
129

112
    if (bpp == 0 || bpp > 32) {
130
        av_log(avctx, AV_LOG_ERROR, "invalid bits per pixel\n");
131
        return AVERROR_INVALIDDATA;
132
    }
133
134
112
    if (ncolors > 256) {
135
        av_log(avctx, AV_LOG_ERROR, "invalid number of entries in colormap\n");
136
        return AVERROR_INVALIDDATA;
137
    }
138
139
112
    if ((ret = av_image_check_size(avctx->width, avctx->height, 0, NULL)) < 0)
140
        return ret;
141
142
112
    rsize = FFALIGN(avctx->width * bpp, bpad) / 8;
143
112
    if (lsize < rsize) {
144
        av_log(avctx, AV_LOG_ERROR, "invalid bytes per scan-line\n");
145
        return AVERROR_INVALIDDATA;
146
    }
147
148
112
    if (bytestream2_get_bytes_left(&gb) < ncolors * XWD_CMAP_SIZE + (uint64_t)avctx->height * lsize) {
149
        av_log(avctx, AV_LOG_ERROR, "input buffer too small\n");
150
        return AVERROR_INVALIDDATA;
151
    }
152
153
112
    if (pixformat != XWD_Z_PIXMAP) {
154
        avpriv_report_missing_feature(avctx, "Pixmap format %"PRIu32, pixformat);
155
        return AVERROR_PATCHWELCOME;
156
    }
157
158
112
    avctx->pix_fmt = AV_PIX_FMT_NONE;
159

112
    switch (vclass) {
160
28
    case XWD_STATIC_GRAY:
161
    case XWD_GRAY_SCALE:
162

28
        if (bpp != 1 && bpp != 8)
163
            return AVERROR_INVALIDDATA;
164

28
        if (bpp == 1 && pixdepth == 1) {
165
14
            avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
166

14
        } else if (bpp == 8 && pixdepth == 8) {
167
14
            avctx->pix_fmt = AV_PIX_FMT_GRAY8;
168
        }
169
28
        break;
170
28
    case XWD_STATIC_COLOR:
171
    case XWD_PSEUDO_COLOR:
172
28
        if (bpp == 8)
173
28
            avctx->pix_fmt = AV_PIX_FMT_PAL8;
174
28
        break;
175
56
    case XWD_TRUE_COLOR:
176
    case XWD_DIRECT_COLOR:
177

56
        if (bpp != 16 && bpp != 24 && bpp != 32)
178
            return AVERROR_INVALIDDATA;
179

56
        if (bpp == 16 && pixdepth == 15) {
180

14
            if (rgb[0] == 0x7C00 && rgb[1] == 0x3E0 && rgb[2] == 0x1F)
181
14
                avctx->pix_fmt = be ? AV_PIX_FMT_RGB555BE : AV_PIX_FMT_RGB555LE;
182
            else if (rgb[0] == 0x1F && rgb[1] == 0x3E0 && rgb[2] == 0x7C00)
183
                avctx->pix_fmt = be ? AV_PIX_FMT_BGR555BE : AV_PIX_FMT_BGR555LE;
184

42
        } else if (bpp == 16 && pixdepth == 16) {
185

14
            if (rgb[0] == 0xF800 && rgb[1] == 0x7E0 && rgb[2] == 0x1F)
186
14
                avctx->pix_fmt = be ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_RGB565LE;
187
            else if (rgb[0] == 0x1F && rgb[1] == 0x7E0 && rgb[2] == 0xF800)
188
                avctx->pix_fmt = be ? AV_PIX_FMT_BGR565BE : AV_PIX_FMT_BGR565LE;
189
28
        } else if (bpp == 24) {
190

14
            if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
191
14
                avctx->pix_fmt = be ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24;
192
            else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
193
                avctx->pix_fmt = be ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24;
194
14
        } else if (bpp == 32) {
195

14
            if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
196
                avctx->pix_fmt = be ? AV_PIX_FMT_ARGB : AV_PIX_FMT_BGRA;
197

14
            else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
198
14
                avctx->pix_fmt = be ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA;
199
        }
200
56
        bytestream2_skipu(&gb, ncolors * XWD_CMAP_SIZE);
201
56
        break;
202
    default:
203
        av_log(avctx, AV_LOG_ERROR, "invalid visual class\n");
204
        return AVERROR_INVALIDDATA;
205
    }
206
207
112
    if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
208
        avpriv_request_sample(avctx,
209
                              "Unknown file: bpp %"PRIu32", pixdepth %"PRIu32", vclass %"PRIu32"",
210
                              bpp, pixdepth, vclass);
211
        return AVERROR_PATCHWELCOME;
212
    }
213
214
112
    if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
215
        return ret;
216
217
112
    p->key_frame = 1;
218
112
    p->pict_type = AV_PICTURE_TYPE_I;
219
220
112
    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
221
28
        uint32_t *dst = (uint32_t *)p->data[1];
222
        uint8_t red, green, blue;
223
224
7196
        for (i = 0; i < ncolors; i++) {
225
226
7168
            bytestream2_skipu(&gb, 4); // skip colormap entry number
227
7168
            red    = bytestream2_get_byteu(&gb);
228
7168
            bytestream2_skipu(&gb, 1);
229
7168
            green  = bytestream2_get_byteu(&gb);
230
7168
            bytestream2_skipu(&gb, 1);
231
7168
            blue   = bytestream2_get_byteu(&gb);
232
7168
            bytestream2_skipu(&gb, 3); // skip bitmask flag and padding
233
234
7168
            dst[i] = 0xFFU << 24 | red << 16 | green << 8 | blue;
235
        }
236
    }
237
238
112
    ptr = p->data[0];
239
32368
    for (i = 0; i < avctx->height; i++) {
240
32256
        bytestream2_get_bufferu(&gb, ptr, rsize);
241
32256
        bytestream2_skipu(&gb, lsize - rsize);
242
32256
        ptr += p->linesize[0];
243
    }
244
245
112
    *got_frame       = 1;
246
247
112
    return buf_size;
248
}
249
250
AVCodec ff_xwd_decoder = {
251
    .name           = "xwd",
252
    .long_name      = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
253
    .type           = AVMEDIA_TYPE_VIDEO,
254
    .id             = AV_CODEC_ID_XWD,
255
    .decode         = xwd_decode_frame,
256
    .capabilities   = AV_CODEC_CAP_DR1,
257
};