00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "libavutil/imgutils.h"
00024 #include "avcodec.h"
00025 #include "bytestream.h"
00026 #include "internal.h"
00027 #include "xwd.h"
00028
00029 static av_cold int xwd_decode_init(AVCodecContext *avctx)
00030 {
00031 avctx->coded_frame = avcodec_alloc_frame();
00032 if (!avctx->coded_frame)
00033 return AVERROR(ENOMEM);
00034
00035 return 0;
00036 }
00037
00038 static int xwd_decode_frame(AVCodecContext *avctx, void *data,
00039 int *got_frame, AVPacket *avpkt)
00040 {
00041 AVFrame *p = avctx->coded_frame;
00042 const uint8_t *buf = avpkt->data;
00043 int i, ret, buf_size = avpkt->size;
00044 uint32_t version, header_size, vclass, ncolors;
00045 uint32_t xoffset, be, bpp, lsize, rsize;
00046 uint32_t pixformat, pixdepth, bunit, bitorder, bpad;
00047 uint32_t rgb[3];
00048 uint8_t *ptr;
00049 GetByteContext gb;
00050
00051 if (buf_size < XWD_HEADER_SIZE)
00052 return AVERROR_INVALIDDATA;
00053
00054 bytestream2_init(&gb, buf, buf_size);
00055 header_size = bytestream2_get_be32u(&gb);
00056
00057 version = bytestream2_get_be32u(&gb);
00058 if (version != XWD_VERSION) {
00059 av_log(avctx, AV_LOG_ERROR, "unsupported version\n");
00060 return AVERROR_INVALIDDATA;
00061 }
00062
00063 if (buf_size < header_size || header_size < XWD_HEADER_SIZE) {
00064 av_log(avctx, AV_LOG_ERROR, "invalid header size\n");
00065 return AVERROR_INVALIDDATA;
00066 }
00067
00068 pixformat = bytestream2_get_be32u(&gb);
00069 pixdepth = bytestream2_get_be32u(&gb);
00070 avctx->width = bytestream2_get_be32u(&gb);
00071 avctx->height = bytestream2_get_be32u(&gb);
00072 xoffset = bytestream2_get_be32u(&gb);
00073 be = bytestream2_get_be32u(&gb);
00074 bunit = bytestream2_get_be32u(&gb);
00075 bitorder = bytestream2_get_be32u(&gb);
00076 bpad = bytestream2_get_be32u(&gb);
00077 bpp = bytestream2_get_be32u(&gb);
00078 lsize = bytestream2_get_be32u(&gb);
00079 vclass = bytestream2_get_be32u(&gb);
00080 rgb[0] = bytestream2_get_be32u(&gb);
00081 rgb[1] = bytestream2_get_be32u(&gb);
00082 rgb[2] = bytestream2_get_be32u(&gb);
00083 bytestream2_skipu(&gb, 8);
00084 ncolors = bytestream2_get_be32u(&gb);
00085 bytestream2_skipu(&gb, header_size - (XWD_HEADER_SIZE - 20));
00086
00087 av_log(avctx, AV_LOG_DEBUG, "pixformat %d, pixdepth %d, bunit %d, bitorder %d, bpad %d\n",
00088 pixformat, pixdepth, bunit, bitorder, bpad);
00089 av_log(avctx, AV_LOG_DEBUG, "vclass %d, ncolors %d, bpp %d, be %d, lsize %d, xoffset %d\n",
00090 vclass, ncolors, bpp, be, lsize, xoffset);
00091 av_log(avctx, AV_LOG_DEBUG, "red %0x, green %0x, blue %0x\n", rgb[0], rgb[1], rgb[2]);
00092
00093 if (pixformat > XWD_Z_PIXMAP) {
00094 av_log(avctx, AV_LOG_ERROR, "invalid pixmap format\n");
00095 return AVERROR_INVALIDDATA;
00096 }
00097
00098 if (pixdepth == 0 || pixdepth > 32) {
00099 av_log(avctx, AV_LOG_ERROR, "invalid pixmap depth\n");
00100 return AVERROR_INVALIDDATA;
00101 }
00102
00103 if (xoffset) {
00104 av_log_ask_for_sample(avctx, "unsupported xoffset %d\n", xoffset);
00105 return AVERROR_PATCHWELCOME;
00106 }
00107
00108 if (be > 1) {
00109 av_log(avctx, AV_LOG_ERROR, "invalid byte order\n");
00110 return AVERROR_INVALIDDATA;
00111 }
00112
00113 if (bitorder > 1) {
00114 av_log(avctx, AV_LOG_ERROR, "invalid bitmap bit order\n");
00115 return AVERROR_INVALIDDATA;
00116 }
00117
00118 if (bunit != 8 && bunit != 16 && bunit != 32) {
00119 av_log(avctx, AV_LOG_ERROR, "invalid bitmap unit\n");
00120 return AVERROR_INVALIDDATA;
00121 }
00122
00123 if (bpad != 8 && bpad != 16 && bpad != 32) {
00124 av_log(avctx, AV_LOG_ERROR, "invalid bitmap scan-line pad\n");
00125 return AVERROR_INVALIDDATA;
00126 }
00127
00128 if (bpp == 0 || bpp > 32) {
00129 av_log(avctx, AV_LOG_ERROR, "invalid bits per pixel\n");
00130 return AVERROR_INVALIDDATA;
00131 }
00132
00133 if (ncolors > 256) {
00134 av_log(avctx, AV_LOG_ERROR, "invalid number of entries in colormap\n");
00135 return AVERROR_INVALIDDATA;
00136 }
00137
00138 if ((ret = av_image_check_size(avctx->width, avctx->height, 0, NULL)) < 0)
00139 return ret;
00140
00141 rsize = FFALIGN(avctx->width * bpp, bpad) / 8;
00142 if (lsize < rsize) {
00143 av_log(avctx, AV_LOG_ERROR, "invalid bytes per scan-line\n");
00144 return AVERROR_INVALIDDATA;
00145 }
00146
00147 if (bytestream2_get_bytes_left(&gb) < ncolors * XWD_CMAP_SIZE + avctx->height * lsize) {
00148 av_log(avctx, AV_LOG_ERROR, "input buffer too small\n");
00149 return AVERROR_INVALIDDATA;
00150 }
00151
00152 if (pixformat != XWD_Z_PIXMAP) {
00153 av_log(avctx, AV_LOG_ERROR, "pixmap format %d unsupported\n", pixformat);
00154 return AVERROR_PATCHWELCOME;
00155 }
00156
00157 avctx->pix_fmt = AV_PIX_FMT_NONE;
00158 switch (vclass) {
00159 case XWD_STATIC_GRAY:
00160 case XWD_GRAY_SCALE:
00161 if (bpp != 1 && bpp != 8)
00162 return AVERROR_INVALIDDATA;
00163 if (pixdepth == 1) {
00164 avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
00165 } else if (pixdepth == 8) {
00166 avctx->pix_fmt = AV_PIX_FMT_GRAY8;
00167 }
00168 break;
00169 case XWD_STATIC_COLOR:
00170 case XWD_PSEUDO_COLOR:
00171 if (bpp == 8)
00172 avctx->pix_fmt = AV_PIX_FMT_PAL8;
00173 break;
00174 case XWD_TRUE_COLOR:
00175 case XWD_DIRECT_COLOR:
00176 if (bpp != 16 && bpp != 24 && bpp != 32)
00177 return AVERROR_INVALIDDATA;
00178 if (bpp == 16 && pixdepth == 15) {
00179 if (rgb[0] == 0x7C00 && rgb[1] == 0x3E0 && rgb[2] == 0x1F)
00180 avctx->pix_fmt = be ? AV_PIX_FMT_RGB555BE : AV_PIX_FMT_RGB555LE;
00181 else if (rgb[0] == 0x1F && rgb[1] == 0x3E0 && rgb[2] == 0x7C00)
00182 avctx->pix_fmt = be ? AV_PIX_FMT_BGR555BE : AV_PIX_FMT_BGR555LE;
00183 } else if (bpp == 16 && pixdepth == 16) {
00184 if (rgb[0] == 0xF800 && rgb[1] == 0x7E0 && rgb[2] == 0x1F)
00185 avctx->pix_fmt = be ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_RGB565LE;
00186 else if (rgb[0] == 0x1F && rgb[1] == 0x7E0 && rgb[2] == 0xF800)
00187 avctx->pix_fmt = be ? AV_PIX_FMT_BGR565BE : AV_PIX_FMT_BGR565LE;
00188 } else if (bpp == 24) {
00189 if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
00190 avctx->pix_fmt = be ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24;
00191 else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
00192 avctx->pix_fmt = be ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24;
00193 } else if (bpp == 32) {
00194 if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
00195 avctx->pix_fmt = be ? AV_PIX_FMT_ARGB : AV_PIX_FMT_BGRA;
00196 else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
00197 avctx->pix_fmt = be ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA;
00198 }
00199 bytestream2_skipu(&gb, ncolors * XWD_CMAP_SIZE);
00200 break;
00201 default:
00202 av_log(avctx, AV_LOG_ERROR, "invalid visual class\n");
00203 return AVERROR_INVALIDDATA;
00204 }
00205
00206 if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
00207 av_log_ask_for_sample(avctx, "unknown file: bpp %d, pixdepth %d, vclass %d\n", bpp, pixdepth, vclass);
00208 return AVERROR_PATCHWELCOME;
00209 }
00210
00211 if (p->data[0])
00212 avctx->release_buffer(avctx, p);
00213
00214 p->reference = 0;
00215 if ((ret = ff_get_buffer(avctx, p)) < 0) {
00216 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00217 return ret;
00218 }
00219
00220 p->key_frame = 1;
00221 p->pict_type = AV_PICTURE_TYPE_I;
00222
00223 if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
00224 uint32_t *dst = (uint32_t *)p->data[1];
00225 uint8_t red, green, blue;
00226
00227 for (i = 0; i < ncolors; i++) {
00228
00229 bytestream2_skipu(&gb, 4);
00230 red = bytestream2_get_byteu(&gb);
00231 bytestream2_skipu(&gb, 1);
00232 green = bytestream2_get_byteu(&gb);
00233 bytestream2_skipu(&gb, 1);
00234 blue = bytestream2_get_byteu(&gb);
00235 bytestream2_skipu(&gb, 3);
00236
00237 dst[i] = red << 16 | green << 8 | blue;
00238 }
00239 }
00240
00241 ptr = p->data[0];
00242 for (i = 0; i < avctx->height; i++) {
00243 bytestream2_get_bufferu(&gb, ptr, rsize);
00244 bytestream2_skipu(&gb, lsize - rsize);
00245 ptr += p->linesize[0];
00246 }
00247
00248 *got_frame = 1;
00249 *(AVFrame *)data = *p;
00250
00251 return buf_size;
00252 }
00253
00254 static av_cold int xwd_decode_close(AVCodecContext *avctx)
00255 {
00256 if (avctx->coded_frame->data[0])
00257 avctx->release_buffer(avctx, avctx->coded_frame);
00258
00259 av_freep(&avctx->coded_frame);
00260
00261 return 0;
00262 }
00263
00264 AVCodec ff_xwd_decoder = {
00265 .name = "xwd",
00266 .type = AVMEDIA_TYPE_VIDEO,
00267 .id = AV_CODEC_ID_XWD,
00268 .init = xwd_decode_init,
00269 .close = xwd_decode_close,
00270 .decode = xwd_decode_frame,
00271 .capabilities = CODEC_CAP_DR1,
00272 .long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
00273 };