1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * PC Paintbrush PCX (.pcx) image encoder 3cabdff1aSopenharmony_ci * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * PCX image encoder 25cabdff1aSopenharmony_ci * @author Daniel Verkamp 26cabdff1aSopenharmony_ci * @see http://bespin.org/~qz/pc-gpe/pcx.txt 27cabdff1aSopenharmony_ci */ 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include "avcodec.h" 30cabdff1aSopenharmony_ci#include "bytestream.h" 31cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 32cabdff1aSopenharmony_ci#include "codec_internal.h" 33cabdff1aSopenharmony_ci#include "encode.h" 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_cistatic const uint32_t monoblack_pal[16] = { 0x000000, 0xFFFFFF }; 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci/** 38cabdff1aSopenharmony_ci * PCX run-length encoder 39cabdff1aSopenharmony_ci * @param dst output buffer 40cabdff1aSopenharmony_ci * @param dst_size size of output buffer 41cabdff1aSopenharmony_ci * @param src input buffer 42cabdff1aSopenharmony_ci * @param src_plane_size size of one plane of input buffer in bytes 43cabdff1aSopenharmony_ci * @param nplanes number of planes in input buffer 44cabdff1aSopenharmony_ci * @return number of bytes written to dst or -1 on error 45cabdff1aSopenharmony_ci * @bug will not work for nplanes != 1 && bpp != 8 46cabdff1aSopenharmony_ci */ 47cabdff1aSopenharmony_cistatic int pcx_rle_encode( uint8_t *dst, int dst_size, 48cabdff1aSopenharmony_ci const uint8_t *src, int src_plane_size, int nplanes) 49cabdff1aSopenharmony_ci{ 50cabdff1aSopenharmony_ci int p; 51cabdff1aSopenharmony_ci const uint8_t *dst_start = dst; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci // check worst-case upper bound on dst_size 54cabdff1aSopenharmony_ci if (dst_size < 2LL * src_plane_size * nplanes || src_plane_size <= 0) 55cabdff1aSopenharmony_ci return AVERROR(EINVAL); 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci for (p = 0; p < nplanes; p++) { 58cabdff1aSopenharmony_ci int count = 1; 59cabdff1aSopenharmony_ci const uint8_t *src_plane = src + p; 60cabdff1aSopenharmony_ci const uint8_t *src_plane_end = src_plane + src_plane_size * nplanes; 61cabdff1aSopenharmony_ci uint8_t prev = *src_plane; 62cabdff1aSopenharmony_ci src_plane += nplanes; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci for (; ; src_plane += nplanes) { 65cabdff1aSopenharmony_ci if (src_plane < src_plane_end && *src_plane == prev && count < 0x3F) { 66cabdff1aSopenharmony_ci // current byte is same as prev 67cabdff1aSopenharmony_ci ++count; 68cabdff1aSopenharmony_ci } else { 69cabdff1aSopenharmony_ci // output prev * count 70cabdff1aSopenharmony_ci if (count != 1 || prev >= 0xC0) 71cabdff1aSopenharmony_ci *dst++ = 0xC0 | count; 72cabdff1aSopenharmony_ci *dst++ = prev; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci if (src_plane == src_plane_end) 75cabdff1aSopenharmony_ci break; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci // start new run 78cabdff1aSopenharmony_ci count = 1; 79cabdff1aSopenharmony_ci prev = *src_plane; 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci } 82cabdff1aSopenharmony_ci } 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci return dst - dst_start; 85cabdff1aSopenharmony_ci} 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_cistatic int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 88cabdff1aSopenharmony_ci const AVFrame *frame, int *got_packet) 89cabdff1aSopenharmony_ci{ 90cabdff1aSopenharmony_ci const uint8_t *buf_end; 91cabdff1aSopenharmony_ci uint8_t *buf; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size, sw, sh; 94cabdff1aSopenharmony_ci const uint32_t *pal = NULL; 95cabdff1aSopenharmony_ci uint32_t palette256[256]; 96cabdff1aSopenharmony_ci const uint8_t *src; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci if (avctx->width > 65535 || avctx->height > 65535) { 99cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "image dimensions do not fit in 16 bits\n"); 100cabdff1aSopenharmony_ci return AVERROR(EINVAL); 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 104cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB24: 105cabdff1aSopenharmony_ci bpp = 8; 106cabdff1aSopenharmony_ci nplanes = 3; 107cabdff1aSopenharmony_ci break; 108cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB8: 109cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR8: 110cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB4_BYTE: 111cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR4_BYTE: 112cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 113cabdff1aSopenharmony_ci bpp = 8; 114cabdff1aSopenharmony_ci nplanes = 1; 115cabdff1aSopenharmony_ci avpriv_set_systematic_pal2(palette256, avctx->pix_fmt); 116cabdff1aSopenharmony_ci pal = palette256; 117cabdff1aSopenharmony_ci break; 118cabdff1aSopenharmony_ci case AV_PIX_FMT_PAL8: 119cabdff1aSopenharmony_ci bpp = 8; 120cabdff1aSopenharmony_ci nplanes = 1; 121cabdff1aSopenharmony_ci pal = (uint32_t *)frame->data[1]; 122cabdff1aSopenharmony_ci break; 123cabdff1aSopenharmony_ci case AV_PIX_FMT_MONOBLACK: 124cabdff1aSopenharmony_ci bpp = 1; 125cabdff1aSopenharmony_ci nplanes = 1; 126cabdff1aSopenharmony_ci pal = monoblack_pal; 127cabdff1aSopenharmony_ci break; 128cabdff1aSopenharmony_ci default: 129cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "unsupported pixfmt\n"); 130cabdff1aSopenharmony_ci return AVERROR(EINVAL); 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci line_bytes = (avctx->width * bpp + 7) >> 3; 134cabdff1aSopenharmony_ci line_bytes = (line_bytes + 1) & ~1; 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci max_pkt_size = 128 + avctx->height * 2 * line_bytes * nplanes + (pal ? 256*3 + 1 : 0); 137cabdff1aSopenharmony_ci if ((ret = ff_alloc_packet(avctx, pkt, max_pkt_size)) < 0) 138cabdff1aSopenharmony_ci return ret; 139cabdff1aSopenharmony_ci buf = pkt->data; 140cabdff1aSopenharmony_ci buf_end = pkt->data + pkt->size; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci sw = avctx->sample_aspect_ratio.num; 143cabdff1aSopenharmony_ci sh = avctx->sample_aspect_ratio.den; 144cabdff1aSopenharmony_ci if (sw > 0xFFFFu || sh > 0xFFFFu) 145cabdff1aSopenharmony_ci av_reduce(&sw, &sh, sw, sh, 0xFFFFu); 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 10); // manufacturer 148cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 5); // version 149cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 1); // encoding 150cabdff1aSopenharmony_ci bytestream_put_byte(&buf, bpp); // bits per pixel per plane 151cabdff1aSopenharmony_ci bytestream_put_le16(&buf, 0); // x min 152cabdff1aSopenharmony_ci bytestream_put_le16(&buf, 0); // y min 153cabdff1aSopenharmony_ci bytestream_put_le16(&buf, avctx->width - 1); // x max 154cabdff1aSopenharmony_ci bytestream_put_le16(&buf, avctx->height - 1); // y max 155cabdff1aSopenharmony_ci bytestream_put_le16(&buf, sw); // horizontal DPI 156cabdff1aSopenharmony_ci bytestream_put_le16(&buf, sh); // vertical DPI 157cabdff1aSopenharmony_ci for (i = 0; i < 16; i++) 158cabdff1aSopenharmony_ci bytestream_put_be24(&buf, pal ? pal[i] : 0);// palette (<= 16 color only) 159cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 0); // reserved 160cabdff1aSopenharmony_ci bytestream_put_byte(&buf, nplanes); // number of planes 161cabdff1aSopenharmony_ci bytestream_put_le16(&buf, line_bytes); // scanline plane size in bytes 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci while (buf - pkt->data < 128) 164cabdff1aSopenharmony_ci *buf++= 0; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci src = frame->data[0]; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 169cabdff1aSopenharmony_ci if ((written = pcx_rle_encode(buf, buf_end - buf, 170cabdff1aSopenharmony_ci src, line_bytes, nplanes)) < 0) { 171cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "buffer too small\n"); 172cabdff1aSopenharmony_ci return AVERROR_BUG; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci buf += written; 175cabdff1aSopenharmony_ci src += frame->linesize[0]; 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci if (nplanes == 1 && bpp == 8) { 179cabdff1aSopenharmony_ci if (buf_end - buf < 257) { 180cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "buffer too small\n"); 181cabdff1aSopenharmony_ci return AVERROR_BUG; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 12); 184cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) { 185cabdff1aSopenharmony_ci bytestream_put_be24(&buf, pal[i]); 186cabdff1aSopenharmony_ci } 187cabdff1aSopenharmony_ci } 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci pkt->size = buf - pkt->data; 190cabdff1aSopenharmony_ci *got_packet = 1; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci return 0; 193cabdff1aSopenharmony_ci} 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ciconst FFCodec ff_pcx_encoder = { 196cabdff1aSopenharmony_ci .p.name = "pcx", 197cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), 198cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 199cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_PCX, 200cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(pcx_encode_frame), 201cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]){ 202cabdff1aSopenharmony_ci AV_PIX_FMT_RGB24, 203cabdff1aSopenharmony_ci AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, 204cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, 205cabdff1aSopenharmony_ci AV_PIX_FMT_MONOBLACK, 206cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 207cabdff1aSopenharmony_ci }, 208cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 209cabdff1aSopenharmony_ci}; 210