00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00029 #include "avcodec.h"
00030 #include "bytestream.h"
00031
00032 typedef struct PCXContext {
00033 AVFrame picture;
00034 } PCXContext;
00035
00036 static const uint32_t monoblack_pal[16] = { 0x000000, 0xFFFFFF };
00037
00038 static av_cold int pcx_encode_init(AVCodecContext *avctx)
00039 {
00040 PCXContext *s = avctx->priv_data;
00041
00042 avcodec_get_frame_defaults(&s->picture);
00043 avctx->coded_frame = &s->picture;
00044
00045 return 0;
00046 }
00047
00058 static int pcx_rle_encode( uint8_t *dst, int dst_size,
00059 const uint8_t *src, int src_plane_size, int nplanes)
00060 {
00061 int p;
00062 const uint8_t *dst_start = dst;
00063
00064
00065 if (dst_size < 2LL * src_plane_size * nplanes || src_plane_size <= 0)
00066 return -1;
00067
00068 for (p = 0; p < nplanes; p++) {
00069 int count = 1;
00070 const uint8_t *src_plane = src + p;
00071 const uint8_t *src_plane_end = src_plane + src_plane_size * nplanes;
00072 uint8_t prev = *src_plane;
00073 src_plane += nplanes;
00074
00075 for (; ; src_plane += nplanes) {
00076 if (src_plane < src_plane_end && *src_plane == prev && count < 0x3F) {
00077
00078 ++count;
00079 } else {
00080
00081 if (count != 1 || prev >= 0xC0)
00082 *dst++ = 0xC0 | count;
00083 *dst++ = prev;
00084
00085 if (src_plane == src_plane_end)
00086 break;
00087
00088
00089 count = 1;
00090 prev = *src_plane;
00091 }
00092 }
00093 }
00094
00095 return dst - dst_start;
00096 }
00097
00098 static int pcx_encode_frame(AVCodecContext *avctx,
00099 unsigned char *buf, int buf_size, void *data)
00100 {
00101 PCXContext *s = avctx->priv_data;
00102 AVFrame *const pict = &s->picture;
00103 const uint8_t *buf_start = buf;
00104 const uint8_t *buf_end = buf + buf_size;
00105
00106 int bpp, nplanes, i, y, line_bytes, written;
00107 const uint32_t *pal = NULL;
00108 const uint8_t *src;
00109
00110 *pict = *(AVFrame *)data;
00111 pict->pict_type = AV_PICTURE_TYPE_I;
00112 pict->key_frame = 1;
00113
00114 if (avctx->width > 65535 || avctx->height > 65535) {
00115 av_log(avctx, AV_LOG_ERROR, "image dimensions do not fit in 16 bits\n");
00116 return -1;
00117 }
00118
00119 switch (avctx->pix_fmt) {
00120 case PIX_FMT_RGB24:
00121 bpp = 8;
00122 nplanes = 3;
00123 break;
00124 case PIX_FMT_RGB8:
00125 case PIX_FMT_BGR8:
00126 case PIX_FMT_RGB4_BYTE:
00127 case PIX_FMT_BGR4_BYTE:
00128 case PIX_FMT_GRAY8:
00129 case PIX_FMT_PAL8:
00130 bpp = 8;
00131 nplanes = 1;
00132 pal = (uint32_t *)pict->data[1];
00133 break;
00134 case PIX_FMT_MONOBLACK:
00135 bpp = 1;
00136 nplanes = 1;
00137 pal = monoblack_pal;
00138 break;
00139 default:
00140 av_log(avctx, AV_LOG_ERROR, "unsupported pixfmt\n");
00141 return -1;
00142 }
00143
00144 line_bytes = (avctx->width * bpp + 7) >> 3;
00145 line_bytes = (line_bytes + 1) & ~1;
00146
00147 bytestream_put_byte(&buf, 10);
00148 bytestream_put_byte(&buf, 5);
00149 bytestream_put_byte(&buf, 1);
00150 bytestream_put_byte(&buf, bpp);
00151 bytestream_put_le16(&buf, 0);
00152 bytestream_put_le16(&buf, 0);
00153 bytestream_put_le16(&buf, avctx->width - 1);
00154 bytestream_put_le16(&buf, avctx->height - 1);
00155 bytestream_put_le16(&buf, 0);
00156 bytestream_put_le16(&buf, 0);
00157 for (i = 0; i < 16; i++)
00158 bytestream_put_be24(&buf, pal ? pal[i] : 0);
00159 bytestream_put_byte(&buf, 0);
00160 bytestream_put_byte(&buf, nplanes);
00161 bytestream_put_le16(&buf, line_bytes);
00162
00163 while (buf - buf_start < 128)
00164 *buf++= 0;
00165
00166 src = pict->data[0];
00167
00168 for (y = 0; y < avctx->height; y++) {
00169 if ((written = pcx_rle_encode(buf, buf_end - buf,
00170 src, line_bytes, nplanes)) < 0) {
00171 av_log(avctx, AV_LOG_ERROR, "buffer too small\n");
00172 return -1;
00173 }
00174 buf += written;
00175 src += pict->linesize[0];
00176 }
00177
00178 if (nplanes == 1 && bpp == 8) {
00179 if (buf_end - buf < 257) {
00180 av_log(avctx, AV_LOG_ERROR, "buffer too small\n");
00181 return -1;
00182 }
00183 bytestream_put_byte(&buf, 12);
00184 for (i = 0; i < 256; i++) {
00185 bytestream_put_be24(&buf, pal[i]);
00186 }
00187 }
00188
00189 return buf - buf_start;
00190 }
00191
00192 AVCodec ff_pcx_encoder = {
00193 .name = "pcx",
00194 .type = AVMEDIA_TYPE_VIDEO,
00195 .id = CODEC_ID_PCX,
00196 .priv_data_size = sizeof(PCXContext),
00197 .init = pcx_encode_init,
00198 .encode = pcx_encode_frame,
00199 .pix_fmts = (const enum PixelFormat[]){
00200 PIX_FMT_RGB24,
00201 PIX_FMT_RGB8, PIX_FMT_BGR8, PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE, PIX_FMT_GRAY8, PIX_FMT_PAL8,
00202 PIX_FMT_MONOBLACK,
00203 PIX_FMT_NONE},
00204 .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
00205 };