4 * Copyright (c) 2012 Paul B Mahol
6 * This file is part of Libav.
8 * Libav 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.
13 * Libav 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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/imgutils.h"
27 #include "bytestream.h"
31 static int xwd_decode_frame(AVCodecContext
*avctx
, void *data
,
32 int *got_frame
, AVPacket
*avpkt
)
35 const uint8_t *buf
= avpkt
->data
;
36 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
;
44 if (buf_size
< XWD_HEADER_SIZE
)
45 return AVERROR_INVALIDDATA
;
47 bytestream2_init(&gb
, buf
, buf_size
);
48 header_size
= bytestream2_get_be32u(&gb
);
50 version
= bytestream2_get_be32u(&gb
);
51 if (version
!= XWD_VERSION
) {
52 av_log(avctx
, AV_LOG_ERROR
, "unsupported version\n");
53 return AVERROR_INVALIDDATA
;
56 if (buf_size
< header_size
|| header_size
< XWD_HEADER_SIZE
) {
57 av_log(avctx
, AV_LOG_ERROR
, "invalid header size\n");
58 return AVERROR_INVALIDDATA
;
61 pixformat
= bytestream2_get_be32u(&gb
);
62 pixdepth
= bytestream2_get_be32u(&gb
);
63 avctx
->width
= bytestream2_get_be32u(&gb
);
64 avctx
->height
= bytestream2_get_be32u(&gb
);
65 xoffset
= bytestream2_get_be32u(&gb
);
66 be
= bytestream2_get_be32u(&gb
);
67 bunit
= bytestream2_get_be32u(&gb
);
68 bitorder
= bytestream2_get_be32u(&gb
);
69 bpad
= bytestream2_get_be32u(&gb
);
70 bpp
= bytestream2_get_be32u(&gb
);
71 lsize
= bytestream2_get_be32u(&gb
);
72 vclass
= bytestream2_get_be32u(&gb
);
73 rgb
[0] = bytestream2_get_be32u(&gb
);
74 rgb
[1] = bytestream2_get_be32u(&gb
);
75 rgb
[2] = bytestream2_get_be32u(&gb
);
76 bytestream2_skipu(&gb
, 8);
77 ncolors
= bytestream2_get_be32u(&gb
);
78 bytestream2_skipu(&gb
, header_size
- (XWD_HEADER_SIZE
- 20));
80 av_log(avctx
, AV_LOG_DEBUG
,
81 "pixformat %"PRIu32
", pixdepth %"PRIu32
", bunit %"PRIu32
", bitorder %"PRIu32
", bpad %"PRIu32
"\n",
82 pixformat
, pixdepth
, bunit
, bitorder
, bpad
);
83 av_log(avctx
, AV_LOG_DEBUG
,
84 "vclass %"PRIu32
", ncolors %"PRIu32
", bpp %"PRIu32
", be %"PRIu32
", lsize %"PRIu32
", xoffset %"PRIu32
"\n",
85 vclass
, ncolors
, bpp
, be
, lsize
, xoffset
);
86 av_log(avctx
, AV_LOG_DEBUG
,
87 "red %0"PRIx32
", green %0"PRIx32
", blue %0"PRIx32
"\n",
88 rgb
[0], rgb
[1], rgb
[2]);
90 if (pixformat
> XWD_Z_PIXMAP
) {
91 av_log(avctx
, AV_LOG_ERROR
, "invalid pixmap format\n");
92 return AVERROR_INVALIDDATA
;
95 if (pixdepth
== 0 || pixdepth
> 32) {
96 av_log(avctx
, AV_LOG_ERROR
, "invalid pixmap depth\n");
97 return AVERROR_INVALIDDATA
;
101 avpriv_request_sample(avctx
, "xoffset %"PRIu32
"", xoffset
);
102 return AVERROR_PATCHWELCOME
;
106 av_log(avctx
, AV_LOG_ERROR
, "invalid byte order\n");
107 return AVERROR_INVALIDDATA
;
111 av_log(avctx
, AV_LOG_ERROR
, "invalid bitmap bit order\n");
112 return AVERROR_INVALIDDATA
;
115 if (bunit
!= 8 && bunit
!= 16 && bunit
!= 32) {
116 av_log(avctx
, AV_LOG_ERROR
, "invalid bitmap unit\n");
117 return AVERROR_INVALIDDATA
;
120 if (bpad
!= 8 && bpad
!= 16 && bpad
!= 32) {
121 av_log(avctx
, AV_LOG_ERROR
, "invalid bitmap scan-line pad\n");
122 return AVERROR_INVALIDDATA
;
125 if (bpp
== 0 || bpp
> 32) {
126 av_log(avctx
, AV_LOG_ERROR
, "invalid bits per pixel\n");
127 return AVERROR_INVALIDDATA
;
131 av_log(avctx
, AV_LOG_ERROR
, "invalid number of entries in colormap\n");
132 return AVERROR_INVALIDDATA
;
135 if ((ret
= av_image_check_size(avctx
->width
, avctx
->height
, 0, NULL
)) < 0)
138 rsize
= FFALIGN(avctx
->width
* bpp
, bpad
) / 8;
140 av_log(avctx
, AV_LOG_ERROR
, "invalid bytes per scan-line\n");
141 return AVERROR_INVALIDDATA
;
144 if (bytestream2_get_bytes_left(&gb
) < ncolors
* XWD_CMAP_SIZE
+ (uint64_t)avctx
->height
* lsize
) {
145 av_log(avctx
, AV_LOG_ERROR
, "input buffer too small\n");
146 return AVERROR_INVALIDDATA
;
149 if (pixformat
!= XWD_Z_PIXMAP
) {
150 avpriv_report_missing_feature(avctx
, "Pixmap format %"PRIu32
, pixformat
);
151 return AVERROR_PATCHWELCOME
;
154 avctx
->pix_fmt
= AV_PIX_FMT_NONE
;
156 case XWD_STATIC_GRAY
:
158 if (bpp
!= 1 && bpp
!= 8 || bpp
!= pixdepth
)
159 return AVERROR_INVALIDDATA
;
161 avctx
->pix_fmt
= AV_PIX_FMT_MONOWHITE
;
162 else if (pixdepth
== 8)
163 avctx
->pix_fmt
= AV_PIX_FMT_GRAY8
;
165 case XWD_STATIC_COLOR
:
166 case XWD_PSEUDO_COLOR
:
168 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
171 case XWD_DIRECT_COLOR
:
172 if (bpp
!= 16 && bpp
!= 24 && bpp
!= 32)
173 return AVERROR_INVALIDDATA
;
174 if (bpp
== 16 && pixdepth
== 15) {
175 if (rgb
[0] == 0x7C00 && rgb
[1] == 0x3E0 && rgb
[2] == 0x1F)
176 avctx
->pix_fmt
= be
? AV_PIX_FMT_RGB555BE
: AV_PIX_FMT_RGB555LE
;
177 else if (rgb
[0] == 0x1F && rgb
[1] == 0x3E0 && rgb
[2] == 0x7C00)
178 avctx
->pix_fmt
= be
? AV_PIX_FMT_BGR555BE
: AV_PIX_FMT_BGR555LE
;
179 } else if (bpp
== 16 && pixdepth
== 16) {
180 if (rgb
[0] == 0xF800 && rgb
[1] == 0x7E0 && rgb
[2] == 0x1F)
181 avctx
->pix_fmt
= be
? AV_PIX_FMT_RGB565BE
: AV_PIX_FMT_RGB565LE
;
182 else if (rgb
[0] == 0x1F && rgb
[1] == 0x7E0 && rgb
[2] == 0xF800)
183 avctx
->pix_fmt
= be
? AV_PIX_FMT_BGR565BE
: AV_PIX_FMT_BGR565LE
;
184 } else if (bpp
== 24) {
185 if (rgb
[0] == 0xFF0000 && rgb
[1] == 0xFF00 && rgb
[2] == 0xFF)
186 avctx
->pix_fmt
= be
? AV_PIX_FMT_RGB24
: AV_PIX_FMT_BGR24
;
187 else if (rgb
[0] == 0xFF && rgb
[1] == 0xFF00 && rgb
[2] == 0xFF0000)
188 avctx
->pix_fmt
= be
? AV_PIX_FMT_BGR24
: AV_PIX_FMT_RGB24
;
189 } else if (bpp
== 32) {
190 if (rgb
[0] == 0xFF0000 && rgb
[1] == 0xFF00 && rgb
[2] == 0xFF)
191 avctx
->pix_fmt
= be
? AV_PIX_FMT_ARGB
: AV_PIX_FMT_BGRA
;
192 else if (rgb
[0] == 0xFF && rgb
[1] == 0xFF00 && rgb
[2] == 0xFF0000)
193 avctx
->pix_fmt
= be
? AV_PIX_FMT_ABGR
: AV_PIX_FMT_RGBA
;
195 bytestream2_skipu(&gb
, ncolors
* XWD_CMAP_SIZE
);
198 av_log(avctx
, AV_LOG_ERROR
, "invalid visual class\n");
199 return AVERROR_INVALIDDATA
;
202 if (avctx
->pix_fmt
== AV_PIX_FMT_NONE
) {
203 avpriv_request_sample(avctx
,
204 "Unknown file: bpp %"PRIu32
", pixdepth %"PRIu32
", vclass %"PRIu32
"",
205 bpp
, pixdepth
, vclass
);
206 return AVERROR_PATCHWELCOME
;
209 if ((ret
= ff_get_buffer(avctx
, p
, 0)) < 0) {
210 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
215 p
->pict_type
= AV_PICTURE_TYPE_I
;
217 if (avctx
->pix_fmt
== AV_PIX_FMT_PAL8
) {
218 uint32_t *dst
= (uint32_t *)p
->data
[1];
219 uint8_t red
, green
, blue
;
221 for (i
= 0; i
< ncolors
; i
++) {
223 bytestream2_skipu(&gb
, 4); // skip colormap entry number
224 red
= bytestream2_get_byteu(&gb
);
225 bytestream2_skipu(&gb
, 1);
226 green
= bytestream2_get_byteu(&gb
);
227 bytestream2_skipu(&gb
, 1);
228 blue
= bytestream2_get_byteu(&gb
);
229 bytestream2_skipu(&gb
, 3); // skip bitmask flag and padding
231 dst
[i
] = red
<< 16 | green
<< 8 | blue
;
236 for (i
= 0; i
< avctx
->height
; i
++) {
237 bytestream2_get_bufferu(&gb
, ptr
, rsize
);
238 bytestream2_skipu(&gb
, lsize
- rsize
);
239 ptr
+= p
->linesize
[0];
247 AVCodec ff_xwd_decoder
= {
249 .long_name
= NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
250 .type
= AVMEDIA_TYPE_VIDEO
,
251 .id
= AV_CODEC_ID_XWD
,
252 .decode
= xwd_decode_frame
,
253 .capabilities
= AV_CODEC_CAP_DR1
,