xwdenc.c 8.9 KB
Newer Older
Paul B Mahol's avatar
Paul B Mahol committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * XWD image format
 *
 * Copyright (c) 2012 Paul B Mahol
 *
 * This file is part of Libav.
 *
 * Libav is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Libav is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Libav; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "libavutil/intreadwrite.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "bytestream.h"
Anton Khirnov's avatar
Anton Khirnov committed
27
#include "internal.h"
Paul B Mahol's avatar
Paul B Mahol committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include "xwd.h"

#define WINDOW_NAME         "lavcxwdenc"
#define WINDOW_NAME_SIZE    11

static av_cold int xwd_encode_init(AVCodecContext *avctx)
{
    avctx->coded_frame = avcodec_alloc_frame();
    if (!avctx->coded_frame)
        return AVERROR(ENOMEM);

    return 0;
}

Anton Khirnov's avatar
Anton Khirnov committed
42 43
static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                            const AVFrame *p, int *got_packet)
Paul B Mahol's avatar
Paul B Mahol committed
44
{
45
    enum AVPixelFormat pix_fmt = avctx->pix_fmt;
46
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
Paul B Mahol's avatar
Paul B Mahol committed
47
    uint32_t pixdepth, bpp, bpad, ncolors = 0, lsize, vclass, be = 0;
Paul B Mahol's avatar
Paul B Mahol committed
48
    uint32_t rgb[3] = { 0 }, bitorder = 0;
Paul B Mahol's avatar
Paul B Mahol committed
49
    uint32_t header_size;
Anton Khirnov's avatar
Anton Khirnov committed
50 51
    int i, out_size, ret;
    uint8_t *ptr, *buf;
Paul B Mahol's avatar
Paul B Mahol committed
52

53 54
    pixdepth = av_get_bits_per_pixel(desc);
    if (desc->flags & PIX_FMT_BE)
Paul B Mahol's avatar
Paul B Mahol committed
55 56
        be = 1;
    switch (pix_fmt) {
57 58 59 60 61 62
    case AV_PIX_FMT_ARGB:
    case AV_PIX_FMT_BGRA:
    case AV_PIX_FMT_RGBA:
    case AV_PIX_FMT_ABGR:
        if (pix_fmt == AV_PIX_FMT_ARGB ||
            pix_fmt == AV_PIX_FMT_ABGR)
Paul B Mahol's avatar
Paul B Mahol committed
63
            be = 1;
64 65
        if (pix_fmt == AV_PIX_FMT_ABGR ||
            pix_fmt == AV_PIX_FMT_RGBA) {
Paul B Mahol's avatar
Paul B Mahol committed
66 67 68 69 70 71 72 73 74 75 76 77 78
            rgb[0] = 0xFF;
            rgb[1] = 0xFF00;
            rgb[2] = 0xFF0000;
        } else {
            rgb[0] = 0xFF0000;
            rgb[1] = 0xFF00;
            rgb[2] = 0xFF;
        }
        bpp      = 32;
        pixdepth = 24;
        vclass   = XWD_TRUE_COLOR;
        bpad     = 32;
        break;
79 80 81
    case AV_PIX_FMT_BGR24:
    case AV_PIX_FMT_RGB24:
        if (pix_fmt == AV_PIX_FMT_RGB24)
Paul B Mahol's avatar
Paul B Mahol committed
82 83 84 85 86 87 88 89
            be = 1;
        bpp      = 24;
        vclass   = XWD_TRUE_COLOR;
        bpad     = 32;
        rgb[0]   = 0xFF0000;
        rgb[1]   = 0xFF00;
        rgb[2]   = 0xFF;
        break;
90 91 92 93 94 95
    case AV_PIX_FMT_RGB565LE:
    case AV_PIX_FMT_RGB565BE:
    case AV_PIX_FMT_BGR565LE:
    case AV_PIX_FMT_BGR565BE:
        if (pix_fmt == AV_PIX_FMT_BGR565LE ||
            pix_fmt == AV_PIX_FMT_BGR565BE) {
Paul B Mahol's avatar
Paul B Mahol committed
96 97 98 99 100 101 102 103 104 105 106 107
            rgb[0] = 0x1F;
            rgb[1] = 0x7E0;
            rgb[2] = 0xF800;
        } else {
            rgb[0] = 0xF800;
            rgb[1] = 0x7E0;
            rgb[2] = 0x1F;
        }
        bpp      = 16;
        vclass   = XWD_TRUE_COLOR;
        bpad     = 16;
        break;
108 109 110 111 112 113
    case AV_PIX_FMT_RGB555LE:
    case AV_PIX_FMT_RGB555BE:
    case AV_PIX_FMT_BGR555LE:
    case AV_PIX_FMT_BGR555BE:
        if (pix_fmt == AV_PIX_FMT_BGR555LE ||
            pix_fmt == AV_PIX_FMT_BGR555BE) {
Paul B Mahol's avatar
Paul B Mahol committed
114 115 116 117 118 119 120 121 122 123 124 125
            rgb[0] = 0x1F;
            rgb[1] = 0x3E0;
            rgb[2] = 0x7C00;
        } else {
            rgb[0] = 0x7C00;
            rgb[1] = 0x3E0;
            rgb[2] = 0x1F;
        }
        bpp      = 16;
        vclass   = XWD_TRUE_COLOR;
        bpad     = 16;
        break;
126 127 128 129 130
    case AV_PIX_FMT_RGB8:
    case AV_PIX_FMT_BGR8:
    case AV_PIX_FMT_RGB4_BYTE:
    case AV_PIX_FMT_BGR4_BYTE:
    case AV_PIX_FMT_PAL8:
Paul B Mahol's avatar
Paul B Mahol committed
131 132 133 134 135
        bpp      = 8;
        vclass   = XWD_PSEUDO_COLOR;
        bpad     = 8;
        ncolors  = 256;
        break;
136
    case AV_PIX_FMT_MONOWHITE:
Paul B Mahol's avatar
Paul B Mahol committed
137 138
        be       = 1;
        bitorder = 1;
Paul B Mahol's avatar
Paul B Mahol committed
139 140 141 142 143 144 145 146 147 148 149 150 151
        bpp      = 1;
        bpad     = 8;
        vclass   = XWD_STATIC_GRAY;
        break;
    default:
        av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
        return AVERROR(EINVAL);
    }

    lsize       = FFALIGN(bpp * avctx->width, bpad) / 8;
    header_size = XWD_HEADER_SIZE + WINDOW_NAME_SIZE;
    out_size    = header_size + ncolors * XWD_CMAP_SIZE + avctx->height * lsize;

Anton Khirnov's avatar
Anton Khirnov committed
152
    if ((ret = ff_alloc_packet(pkt, out_size)) < 0) {
Paul B Mahol's avatar
Paul B Mahol committed
153
        av_log(avctx, AV_LOG_ERROR, "output buffer too small\n");
Anton Khirnov's avatar
Anton Khirnov committed
154
        return ret;
Paul B Mahol's avatar
Paul B Mahol committed
155
    }
Anton Khirnov's avatar
Anton Khirnov committed
156
    buf = pkt->data;
Paul B Mahol's avatar
Paul B Mahol committed
157 158 159 160 161 162 163 164 165 166 167 168 169

    avctx->coded_frame->key_frame = 1;
    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;

    bytestream_put_be32(&buf, header_size);
    bytestream_put_be32(&buf, XWD_VERSION);   // file version
    bytestream_put_be32(&buf, XWD_Z_PIXMAP);  // pixmap format
    bytestream_put_be32(&buf, pixdepth);      // pixmap depth in pixels
    bytestream_put_be32(&buf, avctx->width);  // pixmap width in pixels
    bytestream_put_be32(&buf, avctx->height); // pixmap height in pixels
    bytestream_put_be32(&buf, 0);             // bitmap x offset
    bytestream_put_be32(&buf, be);            // byte order
    bytestream_put_be32(&buf, 32);            // bitmap unit
Paul B Mahol's avatar
Paul B Mahol committed
170
    bytestream_put_be32(&buf, bitorder);      // bit-order of image data
Paul B Mahol's avatar
Paul B Mahol committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    bytestream_put_be32(&buf, bpad);          // bitmap scan-line pad in bits
    bytestream_put_be32(&buf, bpp);           // bits per pixel
    bytestream_put_be32(&buf, lsize);         // bytes per scan-line
    bytestream_put_be32(&buf, vclass);        // visual class
    bytestream_put_be32(&buf, rgb[0]);        // red mask
    bytestream_put_be32(&buf, rgb[1]);        // green mask
    bytestream_put_be32(&buf, rgb[2]);        // blue mask
    bytestream_put_be32(&buf, 8);             // size of each bitmask in bits
    bytestream_put_be32(&buf, ncolors);       // number of colors
    bytestream_put_be32(&buf, ncolors);       // number of entries in color map
    bytestream_put_be32(&buf, avctx->width);  // window width
    bytestream_put_be32(&buf, avctx->height); // window height
    bytestream_put_be32(&buf, 0);             // window upper left X coordinate
    bytestream_put_be32(&buf, 0);             // window upper left Y coordinate
    bytestream_put_be32(&buf, 0);             // window border width
    bytestream_put_buffer(&buf, WINDOW_NAME, WINDOW_NAME_SIZE);

    for (i = 0; i < ncolors; i++) {
        uint32_t val;
        uint8_t red, green, blue;

        val   = AV_RN32A(p->data[1] + i * 4);
        red   = (val >> 16) & 0xFF;
        green = (val >>  8) & 0xFF;
        blue  =  val        & 0xFF;

        bytestream_put_be32(&buf, i);         // colormap entry number
        bytestream_put_be16(&buf, red   << 8);
        bytestream_put_be16(&buf, green << 8);
        bytestream_put_be16(&buf, blue  << 8);
        bytestream_put_byte(&buf, 0x7);       // bitmask flag
        bytestream_put_byte(&buf, 0);         // padding
    }

    ptr = p->data[0];
    for (i = 0; i < avctx->height; i++) {
        bytestream_put_buffer(&buf, ptr, lsize);
        ptr += p->linesize[0];
    }

Anton Khirnov's avatar
Anton Khirnov committed
211 212 213
    pkt->flags |= AV_PKT_FLAG_KEY;
    *got_packet = 1;
    return 0;
Paul B Mahol's avatar
Paul B Mahol committed
214 215 216 217 218 219 220 221 222 223 224 225
}

static av_cold int xwd_encode_close(AVCodecContext *avctx)
{
    av_freep(&avctx->coded_frame);

    return 0;
}

AVCodec ff_xwd_encoder = {
    .name         = "xwd",
    .type         = AVMEDIA_TYPE_VIDEO,
226
    .id           = AV_CODEC_ID_XWD,
Paul B Mahol's avatar
Paul B Mahol committed
227
    .init         = xwd_encode_init,
Anton Khirnov's avatar
Anton Khirnov committed
228
    .encode2      = xwd_encode_frame,
Paul B Mahol's avatar
Paul B Mahol committed
229
    .close        = xwd_encode_close,
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    .pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGRA,
                                                 AV_PIX_FMT_RGBA,
                                                 AV_PIX_FMT_ARGB,
                                                 AV_PIX_FMT_ABGR,
                                                 AV_PIX_FMT_RGB24,
                                                 AV_PIX_FMT_BGR24,
                                                 AV_PIX_FMT_RGB565BE,
                                                 AV_PIX_FMT_RGB565LE,
                                                 AV_PIX_FMT_BGR565BE,
                                                 AV_PIX_FMT_BGR565LE,
                                                 AV_PIX_FMT_RGB555BE,
                                                 AV_PIX_FMT_RGB555LE,
                                                 AV_PIX_FMT_BGR555BE,
                                                 AV_PIX_FMT_BGR555LE,
                                                 AV_PIX_FMT_RGB8,
                                                 AV_PIX_FMT_BGR8,
                                                 AV_PIX_FMT_RGB4_BYTE,
                                                 AV_PIX_FMT_BGR4_BYTE,
                                                 AV_PIX_FMT_PAL8,
                                                 AV_PIX_FMT_MONOWHITE,
                                                 AV_PIX_FMT_NONE },
Paul B Mahol's avatar
Paul B Mahol committed
251 252
    .long_name    = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
};