Mercurial > libavcodec.hg
comparison targaenc.c @ 4678:ae5abc4dc946 libavcodec
Add RLE encoding support, patch by Bobby Bingham, uhmmmm gmail com.
author | diego |
---|---|
date | Sat, 17 Mar 2007 14:59:58 +0000 |
parents | 47237f2638b2 |
children | a3667e74f44b |
comparison
equal
deleted
inserted
replaced
4677:47237f2638b2 | 4678:ae5abc4dc946 |
---|---|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 * | 20 * |
21 */ | 21 */ |
22 #include "avcodec.h" | 22 #include "avcodec.h" |
23 | 23 |
24 /** | |
25 * Count up to 127 consecutive pixels which are either all the same or | |
26 * all differ from the previous and next pixels. | |
27 * @param start Pointer to the first pixel | |
28 * @param len Maximum number of pixels | |
29 * @param bpp Bytes per pixel | |
30 * @param same 1 if searching for identical pixel values. 0 for differing | |
31 * @return Number of matching consecutive pixels found | |
32 */ | |
33 static int count_pixels(uint8_t *start, int len, int bpp, int same) | |
34 { | |
35 uint8_t *pos; | |
36 int count = 1; | |
37 | |
38 for(pos = start + bpp; count < FFMIN(128, len); pos += bpp, count ++) { | |
39 if(same != !memcmp(pos-bpp, pos, bpp)) { | |
40 if(!same) { | |
41 /* if bpp == 1, then 0 1 1 0 is more efficiently encoded as a single | |
42 * raw block of pixels. for larger bpp, RLE is as good or better */ | |
43 if(bpp == 1 && count + 1 < FFMIN(128, len) && *pos != *(pos+1)) | |
44 continue; | |
45 | |
46 /* if RLE can encode the next block better than as a raw block, | |
47 * back up and leave _all_ the identical pixels for RLE */ | |
48 count --; | |
49 } | |
50 break; | |
51 } | |
52 } | |
53 | |
54 return count; | |
55 } | |
56 | |
57 /** | |
58 * RLE compress the image, with maximum size of out_size | |
59 * @param outbuf Output buffer | |
60 * @param out_size Maximum output size | |
61 * @param pic Image to compress | |
62 * @param bpp Bytes per pixel | |
63 * @param w Image width | |
64 * @param h Image height | |
65 * @return Size of output in bytes, or -1 if larger than out_size | |
66 */ | |
67 static int targa_encode_rle(uint8_t *outbuf, int out_size, AVFrame *pic, | |
68 int bpp, int w, int h) | |
69 { | |
70 int count, x, y; | |
71 uint8_t *ptr, *line, *out; | |
72 | |
73 out = outbuf; | |
74 line = pic->data[0]; | |
75 | |
76 for(y = 0; y < h; y ++) { | |
77 ptr = line; | |
78 | |
79 for(x = 0; x < w; x += count) { | |
80 /* see if we can encode the next set of pixels with RLE */ | |
81 if((count = count_pixels(ptr, w-x, bpp, 1)) > 1) { | |
82 if(out + bpp + 1 > outbuf + out_size) return -1; | |
83 *out++ = 0x80 | (count - 1); | |
84 memcpy(out, ptr, bpp); | |
85 out += bpp; | |
86 } else { | |
87 /* fall back on uncompressed */ | |
88 count = count_pixels(ptr, w-x, bpp, 0); | |
89 *out++ = count - 1; | |
90 | |
91 if(out + bpp*count > outbuf + out_size) return -1; | |
92 memcpy(out, ptr, bpp * count); | |
93 out += bpp * count; | |
94 } | |
95 ptr += count * bpp; | |
96 } | |
97 | |
98 line += pic->linesize[0]; | |
99 } | |
100 | |
101 return out - outbuf; | |
102 } | |
103 | |
24 static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h) | 104 static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h) |
25 { | 105 { |
26 int i, n = bpp * w; | 106 int i, n = bpp * w; |
27 uint8_t *out = outbuf; | 107 uint8_t *out = outbuf; |
28 uint8_t *ptr = pic->data[0]; | 108 uint8_t *ptr = pic->data[0]; |
38 | 118 |
39 static int targa_encode_frame(AVCodecContext *avctx, | 119 static int targa_encode_frame(AVCodecContext *avctx, |
40 unsigned char *outbuf, | 120 unsigned char *outbuf, |
41 int buf_size, void *data){ | 121 int buf_size, void *data){ |
42 AVFrame *p = data; | 122 AVFrame *p = data; |
43 int bpp; | 123 int bpp, picsize, datasize; |
44 uint8_t *out; | 124 uint8_t *out; |
45 | 125 |
46 if(avctx->width > 0xffff || avctx->height > 0xffff) { | 126 if(avctx->width > 0xffff || avctx->height > 0xffff) { |
47 av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n"); | 127 av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n"); |
48 return -1; | 128 return -1; |
49 } | 129 } |
50 if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 45) { | 130 picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height); |
131 if(buf_size < picsize + 45) { | |
51 av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); | 132 av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); |
52 return -1; | 133 return -1; |
53 } | 134 } |
54 | 135 |
55 p->pict_type= FF_I_TYPE; | 136 p->pict_type= FF_I_TYPE; |
59 memset(outbuf, 0, 11); | 140 memset(outbuf, 0, 11); |
60 AV_WL16(outbuf+12, avctx->width); | 141 AV_WL16(outbuf+12, avctx->width); |
61 AV_WL16(outbuf+14, avctx->height); | 142 AV_WL16(outbuf+14, avctx->height); |
62 outbuf[17] = 0x20; /* origin is top-left. no alpha */ | 143 outbuf[17] = 0x20; /* origin is top-left. no alpha */ |
63 | 144 |
64 /* TODO: support alpha channel and RLE */ | 145 /* TODO: support alpha channel */ |
65 switch(avctx->pix_fmt) { | 146 switch(avctx->pix_fmt) { |
66 case PIX_FMT_GRAY8: | 147 case PIX_FMT_GRAY8: |
67 outbuf[2] = 3; /* uncompressed grayscale image */ | 148 outbuf[2] = 3; /* uncompressed grayscale image */ |
68 outbuf[16] = 8; /* bpp */ | 149 outbuf[16] = 8; /* bpp */ |
69 break; | 150 break; |
80 } | 161 } |
81 bpp = outbuf[16] >> 3; | 162 bpp = outbuf[16] >> 3; |
82 | 163 |
83 out = outbuf + 18; /* skip past the header we just output */ | 164 out = outbuf + 18; /* skip past the header we just output */ |
84 | 165 |
85 out += targa_encode_normal(out, p, bpp, avctx->width, avctx->height); | 166 /* try RLE compression */ |
167 datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height); | |
168 | |
169 /* if that worked well, mark the picture as RLE compressed */ | |
170 if(datasize >= 0) | |
171 outbuf[2] |= 8; | |
172 | |
173 /* if RLE didn't make it smaller, go back to no compression */ | |
174 else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height); | |
175 | |
176 out += datasize; | |
86 | 177 |
87 /* The standard recommends including this section, even if we don't use | 178 /* The standard recommends including this section, even if we don't use |
88 * any of the features it affords. TODO: take advantage of the pixel | 179 * any of the features it affords. TODO: take advantage of the pixel |
89 * aspect ratio and encoder ID fields available? */ | 180 * aspect ratio and encoder ID fields available? */ |
90 memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26); | 181 memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26); |