• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/xwddec.c

Go to the documentation of this file.
00001 /*
00002  * XWD image format
00003  *
00004  * Copyright (c) 2012 Paul B Mahol
00005  *
00006  * This file is part of Libav.
00007  *
00008  * Libav is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * Libav is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with Libav; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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 
00049     if (buf_size < XWD_HEADER_SIZE)
00050         return AVERROR_INVALIDDATA;
00051 
00052     header_size = bytestream_get_be32(&buf);
00053     if (buf_size < header_size)
00054         return AVERROR_INVALIDDATA;
00055 
00056     version = bytestream_get_be32(&buf);
00057     if (version != XWD_VERSION) {
00058         av_log(avctx, AV_LOG_ERROR, "unsupported version\n");
00059         return AVERROR_INVALIDDATA;
00060     }
00061 
00062     if (header_size < XWD_HEADER_SIZE) {
00063         av_log(avctx, AV_LOG_ERROR, "invalid header size\n");
00064         return AVERROR_INVALIDDATA;
00065     }
00066 
00067     pixformat     = bytestream_get_be32(&buf);
00068     pixdepth      = bytestream_get_be32(&buf);
00069     avctx->width  = bytestream_get_be32(&buf);
00070     avctx->height = bytestream_get_be32(&buf);
00071     xoffset       = bytestream_get_be32(&buf);
00072     be            = bytestream_get_be32(&buf);
00073     bunit         = bytestream_get_be32(&buf);
00074     bitorder      = bytestream_get_be32(&buf);
00075     bpad          = bytestream_get_be32(&buf);
00076     bpp           = bytestream_get_be32(&buf);
00077     lsize         = bytestream_get_be32(&buf);
00078     vclass        = bytestream_get_be32(&buf);
00079     rgb[0]        = bytestream_get_be32(&buf);
00080     rgb[1]        = bytestream_get_be32(&buf);
00081     rgb[2]        = bytestream_get_be32(&buf);
00082     buf          += 8;
00083     ncolors       = bytestream_get_be32(&buf);
00084     buf          += 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 (buf_size < header_size + 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)
00161             return AVERROR_INVALIDDATA;
00162         if (pixdepth == 1)
00163             avctx->pix_fmt = PIX_FMT_MONOWHITE;
00164         break;
00165     case XWD_STATIC_COLOR:
00166     case XWD_PSEUDO_COLOR:
00167         if (bpp == 8)
00168             avctx->pix_fmt = PIX_FMT_PAL8;
00169         break;
00170     case XWD_TRUE_COLOR:
00171     case XWD_DIRECT_COLOR:
00172         if (bpp != 16 && bpp != 24 && bpp != 32)
00173             return AVERROR_INVALIDDATA;
00174         if (bpp == 16 && pixdepth == 15) {
00175             if (rgb[0] == 0x7C00 && rgb[1] == 0x3E0 && rgb[2] == 0x1F)
00176                 avctx->pix_fmt = be ? PIX_FMT_RGB555BE : PIX_FMT_RGB555LE;
00177             else if (rgb[0] == 0x1F && rgb[1] == 0x3E0 && rgb[2] == 0x7C00)
00178                 avctx->pix_fmt = be ? PIX_FMT_BGR555BE : PIX_FMT_BGR555LE;
00179         } else if (bpp == 16 && pixdepth == 16) {
00180             if (rgb[0] == 0xF800 && rgb[1] == 0x7E0 && rgb[2] == 0x1F)
00181                 avctx->pix_fmt = be ? PIX_FMT_RGB565BE : PIX_FMT_RGB565LE;
00182             else if (rgb[0] == 0x1F && rgb[1] == 0x7E0 && rgb[2] == 0xF800)
00183                 avctx->pix_fmt = be ? PIX_FMT_BGR565BE : PIX_FMT_BGR565LE;
00184         } else if (bpp == 24) {
00185             if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
00186                 avctx->pix_fmt = be ? PIX_FMT_RGB24 : PIX_FMT_BGR24;
00187             else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
00188                 avctx->pix_fmt = be ? PIX_FMT_BGR24 : PIX_FMT_RGB24;
00189         } else if (bpp == 32) {
00190             if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
00191                 avctx->pix_fmt = be ? PIX_FMT_ARGB : PIX_FMT_BGRA;
00192             else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
00193                 avctx->pix_fmt = be ? PIX_FMT_ABGR : PIX_FMT_RGBA;
00194         }
00195         buf += ncolors * XWD_CMAP_SIZE;
00196         break;
00197     default:
00198         av_log(avctx, AV_LOG_ERROR, "invalid visual class\n");
00199         return AVERROR_INVALIDDATA;
00200     }
00201 
00202     if (avctx->pix_fmt == PIX_FMT_NONE) {
00203         av_log_ask_for_sample(avctx, "unknown file: bpp %d, pixdepth %d, vclass %d\n", bpp, pixdepth, vclass);
00204         return AVERROR_PATCHWELCOME;
00205     }
00206 
00207     if (p->data[0])
00208         avctx->release_buffer(avctx, p);
00209 
00210     p->reference = 0;
00211     if ((ret = avctx->get_buffer(avctx, p)) < 0) {
00212         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00213         return ret;
00214     }
00215 
00216     p->key_frame = 1;
00217     p->pict_type = AV_PICTURE_TYPE_I;
00218 
00219     if (avctx->pix_fmt == PIX_FMT_PAL8) {
00220         uint32_t *dst = (uint32_t *)p->data[1];
00221         uint8_t red, green, blue;
00222 
00223         for (i = 0; i < ncolors; i++) {
00224 
00225             buf   += 4;  // skip colormap entry number
00226             red    = *buf; buf += 2;
00227             green  = *buf; buf += 2;
00228             blue   = *buf; buf += 2;
00229             buf   += 2;  // skip bitmask flag and padding
00230 
00231             dst[i] = red << 16 | green << 8 | blue;
00232         }
00233     }
00234 
00235     ptr = p->data[0];
00236     for (i = 0; i < avctx->height; i++) {
00237         bytestream_get_buffer(&buf, ptr, rsize);
00238         buf += lsize - rsize;
00239         ptr += p->linesize[0];
00240     }
00241 
00242     *data_size = sizeof(AVFrame);
00243     *(AVFrame *)data = *p;
00244 
00245     return buf_size;
00246 }
00247 
00248 static av_cold int xwd_decode_close(AVCodecContext *avctx)
00249 {
00250     if (avctx->coded_frame->data[0])
00251         avctx->release_buffer(avctx, avctx->coded_frame);
00252 
00253     av_freep(&avctx->coded_frame);
00254 
00255     return 0;
00256 }
00257 
00258 AVCodec ff_xwd_decoder = {
00259     .name           = "xwd",
00260     .type           = AVMEDIA_TYPE_VIDEO,
00261     .id             = CODEC_ID_XWD,
00262     .init           = xwd_decode_init,
00263     .close          = xwd_decode_close,
00264     .decode         = xwd_decode_frame,
00265     .capabilities   = CODEC_CAP_DR1,
00266     .long_name      = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
00267 };
Generated on Fri Feb 1 2013 14:34:47 for FFmpeg by doxygen 1.7.1