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 #include "libavutil/imgutils.h"
00032 #include "internal.h"
00033
00034 typedef struct PCXContext {
00035 AVFrame picture;
00036 } PCXContext;
00037
00038 static const uint32_t monoblack_pal[16] = { 0x000000, 0xFFFFFF };
00039
00040 static av_cold int pcx_encode_init(AVCodecContext *avctx)
00041 {
00042 PCXContext *s = avctx->priv_data;
00043
00044 avcodec_get_frame_defaults(&s->picture);
00045 avctx->coded_frame = &s->picture;
00046
00047 return 0;
00048 }
00049
00060 static int pcx_rle_encode( uint8_t *dst, int dst_size,
00061 const uint8_t *src, int src_plane_size, int nplanes)
00062 {
00063 int p;
00064 const uint8_t *dst_start = dst;
00065
00066
00067 if (dst_size < 2LL * src_plane_size * nplanes || src_plane_size <= 0)
00068 return -1;
00069
00070 for (p = 0; p < nplanes; p++) {
00071 int count = 1;
00072 const uint8_t *src_plane = src + p;
00073 const uint8_t *src_plane_end = src_plane + src_plane_size * nplanes;
00074 uint8_t prev = *src_plane;
00075 src_plane += nplanes;
00076
00077 for (; ; src_plane += nplanes) {
00078 if (src_plane < src_plane_end && *src_plane == prev && count < 0x3F) {
00079
00080 ++count;
00081 } else {
00082
00083 if (count != 1 || prev >= 0xC0)
00084 *dst++ = 0xC0 | count;
00085 *dst++ = prev;
00086
00087 if (src_plane == src_plane_end)
00088 break;
00089
00090
00091 count = 1;
00092 prev = *src_plane;
00093 }
00094 }
00095 }
00096
00097 return dst - dst_start;
00098 }
00099
00100 static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
00101 const AVFrame *frame, int *got_packet)
00102 {
00103 PCXContext *s = avctx->priv_data;
00104 AVFrame *const pict = &s->picture;
00105 const uint8_t *buf_end;
00106 uint8_t *buf;
00107
00108 int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size;
00109 const uint32_t *pal = NULL;
00110 uint32_t palette256[256];
00111 const uint8_t *src;
00112
00113 *pict = *frame;
00114 pict->pict_type = AV_PICTURE_TYPE_I;
00115 pict->key_frame = 1;
00116
00117 if (avctx->width > 65535 || avctx->height > 65535) {
00118 av_log(avctx, AV_LOG_ERROR, "image dimensions do not fit in 16 bits\n");
00119 return -1;
00120 }
00121
00122 switch (avctx->pix_fmt) {
00123 case PIX_FMT_RGB24:
00124 bpp = 8;
00125 nplanes = 3;
00126 break;
00127 case PIX_FMT_RGB8:
00128 case PIX_FMT_BGR8:
00129 case PIX_FMT_RGB4_BYTE:
00130 case PIX_FMT_BGR4_BYTE:
00131 case PIX_FMT_GRAY8:
00132 bpp = 8;
00133 nplanes = 1;
00134 ff_set_systematic_pal2(palette256, avctx->pix_fmt);
00135 pal = palette256;
00136 break;
00137 case PIX_FMT_PAL8:
00138 bpp = 8;
00139 nplanes = 1;
00140 pal = (uint32_t *)pict->data[1];
00141 break;
00142 case PIX_FMT_MONOBLACK:
00143 bpp = 1;
00144 nplanes = 1;
00145 pal = monoblack_pal;
00146 break;
00147 default:
00148 av_log(avctx, AV_LOG_ERROR, "unsupported pixfmt\n");
00149 return -1;
00150 }
00151
00152 line_bytes = (avctx->width * bpp + 7) >> 3;
00153 line_bytes = (line_bytes + 1) & ~1;
00154
00155 max_pkt_size = 128 + avctx->height * 2 * line_bytes * nplanes + (pal ? 256*3 + 1 : 0);
00156 if ((ret = ff_alloc_packet2(avctx, pkt, max_pkt_size)) < 0)
00157 return ret;
00158 buf = pkt->data;
00159 buf_end = pkt->data + pkt->size;
00160
00161 bytestream_put_byte(&buf, 10);
00162 bytestream_put_byte(&buf, 5);
00163 bytestream_put_byte(&buf, 1);
00164 bytestream_put_byte(&buf, bpp);
00165 bytestream_put_le16(&buf, 0);
00166 bytestream_put_le16(&buf, 0);
00167 bytestream_put_le16(&buf, avctx->width - 1);
00168 bytestream_put_le16(&buf, avctx->height - 1);
00169 bytestream_put_le16(&buf, 0);
00170 bytestream_put_le16(&buf, 0);
00171 for (i = 0; i < 16; i++)
00172 bytestream_put_be24(&buf, pal ? pal[i] : 0);
00173 bytestream_put_byte(&buf, 0);
00174 bytestream_put_byte(&buf, nplanes);
00175 bytestream_put_le16(&buf, line_bytes);
00176
00177 while (buf - pkt->data < 128)
00178 *buf++= 0;
00179
00180 src = pict->data[0];
00181
00182 for (y = 0; y < avctx->height; y++) {
00183 if ((written = pcx_rle_encode(buf, buf_end - buf,
00184 src, line_bytes, nplanes)) < 0) {
00185 av_log(avctx, AV_LOG_ERROR, "buffer too small\n");
00186 return -1;
00187 }
00188 buf += written;
00189 src += pict->linesize[0];
00190 }
00191
00192 if (nplanes == 1 && bpp == 8) {
00193 if (buf_end - buf < 257) {
00194 av_log(avctx, AV_LOG_ERROR, "buffer too small\n");
00195 return -1;
00196 }
00197 bytestream_put_byte(&buf, 12);
00198 for (i = 0; i < 256; i++) {
00199 bytestream_put_be24(&buf, pal[i]);
00200 }
00201 }
00202
00203 pkt->size = buf - pkt->data;
00204 pkt->flags |= AV_PKT_FLAG_KEY;
00205 *got_packet = 1;
00206
00207 return 0;
00208 }
00209
00210 AVCodec ff_pcx_encoder = {
00211 .name = "pcx",
00212 .type = AVMEDIA_TYPE_VIDEO,
00213 .id = AV_CODEC_ID_PCX,
00214 .priv_data_size = sizeof(PCXContext),
00215 .init = pcx_encode_init,
00216 .encode2 = pcx_encode_frame,
00217 .pix_fmts = (const enum PixelFormat[]){
00218 PIX_FMT_RGB24,
00219 PIX_FMT_RGB8, PIX_FMT_BGR8, PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE,
00220 PIX_FMT_GRAY8, PIX_FMT_PAL8,
00221 PIX_FMT_MONOBLACK,
00222 PIX_FMT_NONE
00223 },
00224 .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
00225 };