LCOV - code coverage report
Current view: top level - libavcodec - xwddec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 142 68.3 %
Date: 2017-12-17 04:34:43 Functions: 1 1 100.0 %

          Line data    Source code
       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             :     GetByteContext gb;
      43             : 
      44         112 :     if (buf_size < XWD_HEADER_SIZE)
      45           0 :         return AVERROR_INVALIDDATA;
      46             : 
      47         112 :     bytestream2_init(&gb, buf, buf_size);
      48         112 :     header_size = bytestream2_get_be32u(&gb);
      49             : 
      50         112 :     version = bytestream2_get_be32u(&gb);
      51         112 :     if (version != XWD_VERSION) {
      52           0 :         av_log(avctx, AV_LOG_ERROR, "unsupported version\n");
      53           0 :         return AVERROR_INVALIDDATA;
      54             :     }
      55             : 
      56         112 :     if (buf_size < header_size || header_size < XWD_HEADER_SIZE) {
      57           0 :         av_log(avctx, AV_LOG_ERROR, "invalid header size\n");
      58           0 :         return AVERROR_INVALIDDATA;
      59             :     }
      60             : 
      61         112 :     pixformat     = bytestream2_get_be32u(&gb);
      62         112 :     pixdepth      = bytestream2_get_be32u(&gb);
      63         112 :     avctx->width  = bytestream2_get_be32u(&gb);
      64         112 :     avctx->height = bytestream2_get_be32u(&gb);
      65         112 :     xoffset       = bytestream2_get_be32u(&gb);
      66         112 :     be            = bytestream2_get_be32u(&gb);
      67         112 :     bunit         = bytestream2_get_be32u(&gb);
      68         112 :     bitorder      = bytestream2_get_be32u(&gb);
      69         112 :     bpad          = bytestream2_get_be32u(&gb);
      70         112 :     bpp           = bytestream2_get_be32u(&gb);
      71         112 :     lsize         = bytestream2_get_be32u(&gb);
      72         112 :     vclass        = bytestream2_get_be32u(&gb);
      73         112 :     rgb[0]        = bytestream2_get_be32u(&gb);
      74         112 :     rgb[1]        = bytestream2_get_be32u(&gb);
      75         112 :     rgb[2]        = bytestream2_get_be32u(&gb);
      76         112 :     bytestream2_skipu(&gb, 8);
      77         112 :     ncolors       = bytestream2_get_be32u(&gb);
      78         112 :     bytestream2_skipu(&gb, header_size - (XWD_HEADER_SIZE - 20));
      79             : 
      80         112 :     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         112 :     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         112 :     av_log(avctx, AV_LOG_DEBUG,
      87             :            "red %0"PRIx32", green %0"PRIx32", blue %0"PRIx32"\n",
      88             :            rgb[0], rgb[1], rgb[2]);
      89             : 
      90         112 :     if (pixformat > XWD_Z_PIXMAP) {
      91           0 :         av_log(avctx, AV_LOG_ERROR, "invalid pixmap format\n");
      92           0 :         return AVERROR_INVALIDDATA;
      93             :     }
      94             : 
      95         112 :     if (pixdepth == 0 || pixdepth > 32) {
      96           0 :         av_log(avctx, AV_LOG_ERROR, "invalid pixmap depth\n");
      97           0 :         return AVERROR_INVALIDDATA;
      98             :     }
      99             : 
     100         112 :     if (xoffset) {
     101           0 :         avpriv_request_sample(avctx, "xoffset %"PRIu32"", xoffset);
     102           0 :         return AVERROR_PATCHWELCOME;
     103             :     }
     104             : 
     105         112 :     if (be > 1) {
     106           0 :         av_log(avctx, AV_LOG_ERROR, "invalid byte order\n");
     107           0 :         return AVERROR_INVALIDDATA;
     108             :     }
     109             : 
     110         112 :     if (bitorder > 1) {
     111           0 :         av_log(avctx, AV_LOG_ERROR, "invalid bitmap bit order\n");
     112           0 :         return AVERROR_INVALIDDATA;
     113             :     }
     114             : 
     115         112 :     if (bunit != 8 && bunit != 16 && bunit != 32) {
     116           0 :         av_log(avctx, AV_LOG_ERROR, "invalid bitmap unit\n");
     117           0 :         return AVERROR_INVALIDDATA;
     118             :     }
     119             : 
     120         112 :     if (bpad != 8 && bpad != 16 && bpad != 32) {
     121           0 :         av_log(avctx, AV_LOG_ERROR, "invalid bitmap scan-line pad\n");
     122           0 :         return AVERROR_INVALIDDATA;
     123             :     }
     124             : 
     125         112 :     if (bpp == 0 || bpp > 32) {
     126           0 :         av_log(avctx, AV_LOG_ERROR, "invalid bits per pixel\n");
     127           0 :         return AVERROR_INVALIDDATA;
     128             :     }
     129             : 
     130         112 :     if (ncolors > 256) {
     131           0 :         av_log(avctx, AV_LOG_ERROR, "invalid number of entries in colormap\n");
     132           0 :         return AVERROR_INVALIDDATA;
     133             :     }
     134             : 
     135         112 :     if ((ret = av_image_check_size(avctx->width, avctx->height, 0, NULL)) < 0)
     136           0 :         return ret;
     137             : 
     138         112 :     rsize = FFALIGN(avctx->width * bpp, bpad) / 8;
     139         112 :     if (lsize < rsize) {
     140           0 :         av_log(avctx, AV_LOG_ERROR, "invalid bytes per scan-line\n");
     141           0 :         return AVERROR_INVALIDDATA;
     142             :     }
     143             : 
     144         112 :     if (bytestream2_get_bytes_left(&gb) < ncolors * XWD_CMAP_SIZE + (uint64_t)avctx->height * lsize) {
     145           0 :         av_log(avctx, AV_LOG_ERROR, "input buffer too small\n");
     146           0 :         return AVERROR_INVALIDDATA;
     147             :     }
     148             : 
     149         112 :     if (pixformat != XWD_Z_PIXMAP) {
     150           0 :         avpriv_report_missing_feature(avctx, "Pixmap format %"PRIu32, pixformat);
     151           0 :         return AVERROR_PATCHWELCOME;
     152             :     }
     153             : 
     154         112 :     avctx->pix_fmt = AV_PIX_FMT_NONE;
     155         112 :     switch (vclass) {
     156          28 :     case XWD_STATIC_GRAY:
     157             :     case XWD_GRAY_SCALE:
     158          28 :         if (bpp != 1 && bpp != 8)
     159           0 :             return AVERROR_INVALIDDATA;
     160          28 :         if (bpp == 1 && pixdepth == 1) {
     161          14 :             avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
     162          14 :         } else if (bpp == 8 && pixdepth == 8) {
     163          14 :             avctx->pix_fmt = AV_PIX_FMT_GRAY8;
     164             :         }
     165          28 :         break;
     166          28 :     case XWD_STATIC_COLOR:
     167             :     case XWD_PSEUDO_COLOR:
     168          28 :         if (bpp == 8)
     169          28 :             avctx->pix_fmt = AV_PIX_FMT_PAL8;
     170          28 :         break;
     171          56 :     case XWD_TRUE_COLOR:
     172             :     case XWD_DIRECT_COLOR:
     173          56 :         if (bpp != 16 && bpp != 24 && bpp != 32)
     174           0 :             return AVERROR_INVALIDDATA;
     175          56 :         if (bpp == 16 && pixdepth == 15) {
     176          28 :             if (rgb[0] == 0x7C00 && rgb[1] == 0x3E0 && rgb[2] == 0x1F)
     177          14 :                 avctx->pix_fmt = be ? AV_PIX_FMT_RGB555BE : AV_PIX_FMT_RGB555LE;
     178           0 :             else if (rgb[0] == 0x1F && rgb[1] == 0x3E0 && rgb[2] == 0x7C00)
     179           0 :                 avctx->pix_fmt = be ? AV_PIX_FMT_BGR555BE : AV_PIX_FMT_BGR555LE;
     180          42 :         } else if (bpp == 16 && pixdepth == 16) {
     181          28 :             if (rgb[0] == 0xF800 && rgb[1] == 0x7E0 && rgb[2] == 0x1F)
     182          14 :                 avctx->pix_fmt = be ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_RGB565LE;
     183           0 :             else if (rgb[0] == 0x1F && rgb[1] == 0x7E0 && rgb[2] == 0xF800)
     184           0 :                 avctx->pix_fmt = be ? AV_PIX_FMT_BGR565BE : AV_PIX_FMT_BGR565LE;
     185          28 :         } else if (bpp == 24) {
     186          14 :             if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
     187          14 :                 avctx->pix_fmt = be ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24;
     188           0 :             else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
     189           0 :                 avctx->pix_fmt = be ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24;
     190          14 :         } else if (bpp == 32) {
     191          14 :             if (rgb[0] == 0xFF0000 && rgb[1] == 0xFF00 && rgb[2] == 0xFF)
     192           0 :                 avctx->pix_fmt = be ? AV_PIX_FMT_ARGB : AV_PIX_FMT_BGRA;
     193          14 :             else if (rgb[0] == 0xFF && rgb[1] == 0xFF00 && rgb[2] == 0xFF0000)
     194          14 :                 avctx->pix_fmt = be ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA;
     195             :         }
     196          56 :         bytestream2_skipu(&gb, ncolors * XWD_CMAP_SIZE);
     197          56 :         break;
     198           0 :     default:
     199           0 :         av_log(avctx, AV_LOG_ERROR, "invalid visual class\n");
     200           0 :         return AVERROR_INVALIDDATA;
     201             :     }
     202             : 
     203         112 :     if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
     204           0 :         avpriv_request_sample(avctx,
     205             :                               "Unknown file: bpp %"PRIu32", pixdepth %"PRIu32", vclass %"PRIu32"",
     206             :                               bpp, pixdepth, vclass);
     207           0 :         return AVERROR_PATCHWELCOME;
     208             :     }
     209             : 
     210         112 :     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
     211           0 :         return ret;
     212             : 
     213         112 :     p->key_frame = 1;
     214         112 :     p->pict_type = AV_PICTURE_TYPE_I;
     215             : 
     216         112 :     if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
     217          28 :         uint32_t *dst = (uint32_t *)p->data[1];
     218             :         uint8_t red, green, blue;
     219             : 
     220        7196 :         for (i = 0; i < ncolors; i++) {
     221             : 
     222        7168 :             bytestream2_skipu(&gb, 4); // skip colormap entry number
     223        7168 :             red    = bytestream2_get_byteu(&gb);
     224        7168 :             bytestream2_skipu(&gb, 1);
     225        7168 :             green  = bytestream2_get_byteu(&gb);
     226        7168 :             bytestream2_skipu(&gb, 1);
     227        7168 :             blue   = bytestream2_get_byteu(&gb);
     228        7168 :             bytestream2_skipu(&gb, 3); // skip bitmask flag and padding
     229             : 
     230        7168 :             dst[i] = red << 16 | green << 8 | blue;
     231             :         }
     232             :     }
     233             : 
     234         112 :     ptr = p->data[0];
     235       32368 :     for (i = 0; i < avctx->height; i++) {
     236       32256 :         bytestream2_get_bufferu(&gb, ptr, rsize);
     237       32256 :         bytestream2_skipu(&gb, lsize - rsize);
     238       32256 :         ptr += p->linesize[0];
     239             :     }
     240             : 
     241         112 :     *got_frame       = 1;
     242             : 
     243         112 :     return buf_size;
     244             : }
     245             : 
     246             : AVCodec ff_xwd_decoder = {
     247             :     .name           = "xwd",
     248             :     .long_name      = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
     249             :     .type           = AVMEDIA_TYPE_VIDEO,
     250             :     .id             = AV_CODEC_ID_XWD,
     251             :     .decode         = xwd_decode_frame,
     252             :     .capabilities   = AV_CODEC_CAP_DR1,
     253             : };

Generated by: LCOV version 1.13