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 "libavutil/pixdesc.h" 24#include "avcodec.h" 25#include "bytestream.h" 26#include "codec_internal.h" 27#include "encode.h" 28#include "xwd.h" 29 30#define WINDOW_NAME "lavcxwdenc" 31#define WINDOW_NAME_SIZE 11 32 33static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 34 const AVFrame *pict, int *got_packet) 35{ 36 enum AVPixelFormat pix_fmt = avctx->pix_fmt; 37 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); 38 uint32_t pixdepth, bpp, bpad, ncolors = 0, lsize, vclass, be = 0; 39 uint32_t rgb[3] = { 0 }, bitorder = 0; 40 uint32_t header_size; 41 int i, out_size, ret; 42 uint8_t *ptr, *buf; 43 AVFrame * const p = (AVFrame *)pict; 44 uint32_t pal[256]; 45 46 pixdepth = av_get_bits_per_pixel(desc); 47 if (desc->flags & AV_PIX_FMT_FLAG_BE) 48 be = 1; 49 switch (pix_fmt) { 50 case AV_PIX_FMT_ARGB: 51 case AV_PIX_FMT_BGRA: 52 case AV_PIX_FMT_RGBA: 53 case AV_PIX_FMT_ABGR: 54 if (pix_fmt == AV_PIX_FMT_ARGB || 55 pix_fmt == AV_PIX_FMT_ABGR) 56 be = 1; 57 if (pix_fmt == AV_PIX_FMT_ABGR || 58 pix_fmt == AV_PIX_FMT_RGBA) { 59 rgb[0] = 0xFF; 60 rgb[1] = 0xFF00; 61 rgb[2] = 0xFF0000; 62 } else { 63 rgb[0] = 0xFF0000; 64 rgb[1] = 0xFF00; 65 rgb[2] = 0xFF; 66 } 67 bpp = 32; 68 pixdepth = 24; 69 vclass = XWD_TRUE_COLOR; 70 bpad = 32; 71 break; 72 case AV_PIX_FMT_BGR24: 73 case AV_PIX_FMT_RGB24: 74 if (pix_fmt == AV_PIX_FMT_RGB24) 75 be = 1; 76 bpp = 24; 77 vclass = XWD_TRUE_COLOR; 78 bpad = 32; 79 rgb[0] = 0xFF0000; 80 rgb[1] = 0xFF00; 81 rgb[2] = 0xFF; 82 break; 83 case AV_PIX_FMT_RGB565LE: 84 case AV_PIX_FMT_RGB565BE: 85 case AV_PIX_FMT_BGR565LE: 86 case AV_PIX_FMT_BGR565BE: 87 if (pix_fmt == AV_PIX_FMT_BGR565LE || 88 pix_fmt == AV_PIX_FMT_BGR565BE) { 89 rgb[0] = 0x1F; 90 rgb[1] = 0x7E0; 91 rgb[2] = 0xF800; 92 } else { 93 rgb[0] = 0xF800; 94 rgb[1] = 0x7E0; 95 rgb[2] = 0x1F; 96 } 97 bpp = 16; 98 vclass = XWD_TRUE_COLOR; 99 bpad = 16; 100 break; 101 case AV_PIX_FMT_RGB555LE: 102 case AV_PIX_FMT_RGB555BE: 103 case AV_PIX_FMT_BGR555LE: 104 case AV_PIX_FMT_BGR555BE: 105 if (pix_fmt == AV_PIX_FMT_BGR555LE || 106 pix_fmt == AV_PIX_FMT_BGR555BE) { 107 rgb[0] = 0x1F; 108 rgb[1] = 0x3E0; 109 rgb[2] = 0x7C00; 110 } else { 111 rgb[0] = 0x7C00; 112 rgb[1] = 0x3E0; 113 rgb[2] = 0x1F; 114 } 115 bpp = 16; 116 vclass = XWD_TRUE_COLOR; 117 bpad = 16; 118 break; 119 case AV_PIX_FMT_RGB8: 120 case AV_PIX_FMT_BGR8: 121 case AV_PIX_FMT_RGB4_BYTE: 122 case AV_PIX_FMT_BGR4_BYTE: 123 case AV_PIX_FMT_PAL8: 124 bpp = 8; 125 vclass = XWD_PSEUDO_COLOR; 126 bpad = 8; 127 ncolors = 256; 128 break; 129 case AV_PIX_FMT_GRAY8: 130 bpp = 8; 131 bpad = 8; 132 vclass = XWD_STATIC_GRAY; 133 break; 134 case AV_PIX_FMT_MONOWHITE: 135 be = 1; 136 bitorder = 1; 137 bpp = 1; 138 bpad = 8; 139 vclass = XWD_STATIC_GRAY; 140 break; 141 default: 142 av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n"); 143 return AVERROR(EINVAL); 144 } 145 146 lsize = FFALIGN(bpp * avctx->width, bpad) / 8; 147 header_size = XWD_HEADER_SIZE + WINDOW_NAME_SIZE; 148 out_size = header_size + ncolors * XWD_CMAP_SIZE + avctx->height * lsize; 149 150 if ((ret = ff_get_encode_buffer(avctx, pkt, out_size, 0)) < 0) 151 return ret; 152 buf = pkt->data; 153 154 p->key_frame = 1; 155 p->pict_type = AV_PICTURE_TYPE_I; 156 157 bytestream_put_be32(&buf, header_size); 158 bytestream_put_be32(&buf, XWD_VERSION); // file version 159 bytestream_put_be32(&buf, XWD_Z_PIXMAP); // pixmap format 160 bytestream_put_be32(&buf, pixdepth); // pixmap depth in pixels 161 bytestream_put_be32(&buf, avctx->width); // pixmap width in pixels 162 bytestream_put_be32(&buf, avctx->height); // pixmap height in pixels 163 bytestream_put_be32(&buf, 0); // bitmap x offset 164 bytestream_put_be32(&buf, be); // byte order 165 bytestream_put_be32(&buf, 32); // bitmap unit 166 bytestream_put_be32(&buf, bitorder); // bit-order of image data 167 bytestream_put_be32(&buf, bpad); // bitmap scan-line pad in bits 168 bytestream_put_be32(&buf, bpp); // bits per pixel 169 bytestream_put_be32(&buf, lsize); // bytes per scan-line 170 bytestream_put_be32(&buf, vclass); // visual class 171 bytestream_put_be32(&buf, rgb[0]); // red mask 172 bytestream_put_be32(&buf, rgb[1]); // green mask 173 bytestream_put_be32(&buf, rgb[2]); // blue mask 174 bytestream_put_be32(&buf, 8); // size of each bitmask in bits 175 bytestream_put_be32(&buf, ncolors); // number of colors 176 bytestream_put_be32(&buf, ncolors); // number of entries in color map 177 bytestream_put_be32(&buf, avctx->width); // window width 178 bytestream_put_be32(&buf, avctx->height); // window height 179 bytestream_put_be32(&buf, 0); // window upper left X coordinate 180 bytestream_put_be32(&buf, 0); // window upper left Y coordinate 181 bytestream_put_be32(&buf, 0); // window border width 182 bytestream_put_buffer(&buf, WINDOW_NAME, WINDOW_NAME_SIZE); 183 184 if (pix_fmt == AV_PIX_FMT_PAL8) { 185 memcpy(pal, p->data[1], sizeof(pal)); 186 } else { 187 avpriv_set_systematic_pal2(pal, pix_fmt); 188 } 189 190 for (i = 0; i < ncolors; i++) { 191 uint32_t val; 192 uint8_t red, green, blue; 193 194 val = pal[i]; 195 red = (val >> 16) & 0xFF; 196 green = (val >> 8) & 0xFF; 197 blue = val & 0xFF; 198 199 bytestream_put_be32(&buf, i); // colormap entry number 200 bytestream_put_be16(&buf, red << 8); 201 bytestream_put_be16(&buf, green << 8); 202 bytestream_put_be16(&buf, blue << 8); 203 bytestream_put_byte(&buf, 0x7); // bitmask flag 204 bytestream_put_byte(&buf, 0); // padding 205 } 206 207 ptr = p->data[0]; 208 for (i = 0; i < avctx->height; i++) { 209 bytestream_put_buffer(&buf, ptr, lsize); 210 ptr += p->linesize[0]; 211 } 212 213 *got_packet = 1; 214 return 0; 215} 216 217const FFCodec ff_xwd_encoder = { 218 .p.name = "xwd", 219 .p.long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"), 220 .p.type = AVMEDIA_TYPE_VIDEO, 221 .p.id = AV_CODEC_ID_XWD, 222 .p.capabilities = AV_CODEC_CAP_DR1, 223 FF_CODEC_ENCODE_CB(xwd_encode_frame), 224 .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGRA, 225 AV_PIX_FMT_RGBA, 226 AV_PIX_FMT_ARGB, 227 AV_PIX_FMT_ABGR, 228 AV_PIX_FMT_RGB24, 229 AV_PIX_FMT_BGR24, 230 AV_PIX_FMT_RGB565BE, 231 AV_PIX_FMT_RGB565LE, 232 AV_PIX_FMT_BGR565BE, 233 AV_PIX_FMT_BGR565LE, 234 AV_PIX_FMT_RGB555BE, 235 AV_PIX_FMT_RGB555LE, 236 AV_PIX_FMT_BGR555BE, 237 AV_PIX_FMT_BGR555LE, 238 AV_PIX_FMT_RGB8, 239 AV_PIX_FMT_BGR8, 240 AV_PIX_FMT_RGB4_BYTE, 241 AV_PIX_FMT_BGR4_BYTE, 242 AV_PIX_FMT_PAL8, 243 AV_PIX_FMT_GRAY8, 244 AV_PIX_FMT_MONOWHITE, 245 AV_PIX_FMT_NONE }, 246}; 247