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