/src/ffmpeg/libavcodec/targaenc.c
Line | Count | Source |
1 | | /* |
2 | | * Targa (.tga) image encoder |
3 | | * Copyright (c) 2007 Bobby Bingham |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include <string.h> |
23 | | |
24 | | #include "libavutil/avassert.h" |
25 | | #include "libavutil/imgutils.h" |
26 | | #include "libavutil/internal.h" |
27 | | #include "libavutil/intreadwrite.h" |
28 | | #include "libavutil/opt.h" |
29 | | #include "libavutil/pixdesc.h" |
30 | | #include "avcodec.h" |
31 | | #include "codec_internal.h" |
32 | | #include "encode.h" |
33 | | #include "rle.h" |
34 | | #include "targa.h" |
35 | | |
36 | | typedef struct TargaContext { |
37 | | AVClass *class; |
38 | | |
39 | | int rle; |
40 | | } TargaContext; |
41 | | |
42 | | /** |
43 | | * RLE compress the image, with maximum size of out_size |
44 | | * @param outbuf Output buffer |
45 | | * @param out_size Maximum output size |
46 | | * @param pic Image to compress |
47 | | * @param bpp Bytes per pixel |
48 | | * @param w Image width |
49 | | * @param h Image height |
50 | | * @return Size of output in bytes, or -1 if larger than out_size |
51 | | */ |
52 | | static int targa_encode_rle(uint8_t *outbuf, int out_size, const AVFrame *pic, |
53 | | int bpp, int w, int h) |
54 | 10.7k | { |
55 | 10.7k | int y,ret; |
56 | 10.7k | uint8_t *out; |
57 | | |
58 | 10.7k | out = outbuf; |
59 | | |
60 | 2.37M | for(y = 0; y < h; y ++) { |
61 | 2.36M | ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0); |
62 | 2.36M | if(ret == -1){ |
63 | 4.65k | return -1; |
64 | 4.65k | } |
65 | 2.36M | out+= ret; |
66 | 2.36M | out_size -= ret; |
67 | 2.36M | } |
68 | | |
69 | 6.05k | return out - outbuf; |
70 | 10.7k | } |
71 | | |
72 | | static int targa_encode_normal(uint8_t *outbuf, const AVFrame *pic, int bpp, int w, int h) |
73 | 4.65k | { |
74 | 4.65k | int i, n = bpp * w; |
75 | 4.65k | uint8_t *out = outbuf; |
76 | 4.65k | const uint8_t *ptr = pic->data[0]; |
77 | | |
78 | 806k | for(i=0; i < h; i++) { |
79 | 801k | memcpy(out, ptr, n); |
80 | 801k | out += n; |
81 | 801k | ptr += pic->linesize[0]; |
82 | 801k | } |
83 | | |
84 | 4.65k | return out - outbuf; |
85 | 4.65k | } |
86 | | |
87 | | static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
88 | | const AVFrame *p, int *got_packet) |
89 | 10.7k | { |
90 | 10.7k | TargaContext *s = avctx->priv_data; |
91 | 10.7k | int bpp, picsize, datasize = -1, ret, i; |
92 | 10.7k | uint8_t *out; |
93 | 10.7k | int maxpal = 32*32; |
94 | | |
95 | 10.7k | picsize = av_image_get_buffer_size(avctx->pix_fmt, |
96 | 10.7k | avctx->width, avctx->height, 1); |
97 | 10.7k | if ((ret = ff_alloc_packet(avctx, pkt, picsize + 45 + maxpal)) < 0) |
98 | 0 | return ret; |
99 | | |
100 | | /* zero out the header and only set applicable fields */ |
101 | 10.7k | memset(pkt->data, 0, 12); |
102 | 10.7k | AV_WL16(pkt->data+12, avctx->width); |
103 | 10.7k | AV_WL16(pkt->data+14, avctx->height); |
104 | | /* image descriptor byte: origin is always top-left, bits 0-3 specify alpha */ |
105 | 10.7k | pkt->data[17] = 0x20 | (avctx->pix_fmt == AV_PIX_FMT_BGRA ? 8 : 0); |
106 | | |
107 | 10.7k | out = pkt->data + 18; /* skip past the header we write */ |
108 | | |
109 | 10.7k | avctx->bits_per_coded_sample = av_get_bits_per_pixel(av_pix_fmt_desc_get(avctx->pix_fmt)); |
110 | 10.7k | switch(avctx->pix_fmt) { |
111 | 2.48k | case AV_PIX_FMT_PAL8: { |
112 | 2.48k | int pal_bpp = 24; /* Only write 32bit palette if there is transparency information */ |
113 | 359k | for (i = 0; i < 256; i++) |
114 | 357k | if (AV_RN32(p->data[1] + 4 * i) >> 24 != 0xFF) { |
115 | 1.19k | pal_bpp = 32; |
116 | 1.19k | break; |
117 | 1.19k | } |
118 | 2.48k | pkt->data[1] = 1; /* palette present */ |
119 | 2.48k | pkt->data[2] = TGA_PAL; /* uncompressed palettised image */ |
120 | 2.48k | pkt->data[6] = 1; /* palette contains 256 entries */ |
121 | 2.48k | pkt->data[7] = pal_bpp; /* palette contains pal_bpp bit entries */ |
122 | 2.48k | pkt->data[16] = 8; /* bpp */ |
123 | 639k | for (i = 0; i < 256; i++) |
124 | 636k | if (pal_bpp == 32) { |
125 | 306k | AV_WL32(pkt->data + 18 + 4 * i, *(uint32_t *)(p->data[1] + i * 4)); |
126 | 330k | } else { |
127 | 330k | AV_WL24(pkt->data + 18 + 3 * i, *(uint32_t *)(p->data[1] + i * 4)); |
128 | 330k | } |
129 | 2.48k | out += 32 * pal_bpp; /* skip past the palette we just output */ |
130 | 2.48k | av_assert0(32 * pal_bpp <= maxpal); |
131 | 2.48k | break; |
132 | 2.48k | } |
133 | 4.37k | case AV_PIX_FMT_GRAY8: |
134 | 4.37k | pkt->data[2] = TGA_BW; /* uncompressed grayscale image */ |
135 | 4.37k | avctx->bits_per_coded_sample = 0x28; |
136 | 4.37k | pkt->data[16] = 8; /* bpp */ |
137 | 4.37k | break; |
138 | 1.10k | case AV_PIX_FMT_RGB555LE: |
139 | 1.10k | pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ |
140 | 1.10k | avctx->bits_per_coded_sample = |
141 | 1.10k | pkt->data[16] = 16; /* bpp */ |
142 | 1.10k | break; |
143 | 475 | case AV_PIX_FMT_BGR24: |
144 | 475 | pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ |
145 | 475 | pkt->data[16] = 24; /* bpp */ |
146 | 475 | break; |
147 | 2.27k | case AV_PIX_FMT_BGRA: |
148 | 2.27k | pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ |
149 | 2.27k | pkt->data[16] = 32; /* bpp */ |
150 | 2.27k | break; |
151 | 0 | default: |
152 | 0 | av_log(avctx, AV_LOG_ERROR, "Pixel format '%s' not supported.\n", |
153 | 0 | av_get_pix_fmt_name(avctx->pix_fmt)); |
154 | 0 | return AVERROR(EINVAL); |
155 | 10.7k | } |
156 | 10.7k | bpp = pkt->data[16] >> 3; |
157 | | |
158 | | |
159 | | /* try RLE compression */ |
160 | 10.7k | if (s->rle) |
161 | 10.7k | datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height); |
162 | | |
163 | | /* if that worked well, mark the picture as RLE compressed */ |
164 | 10.7k | if(datasize >= 0) |
165 | 6.05k | pkt->data[2] |= TGA_RLE; |
166 | | |
167 | | /* if RLE didn't make it smaller, go back to no compression */ |
168 | 4.65k | else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height); |
169 | | |
170 | 10.7k | out += datasize; |
171 | | |
172 | | /* The standard recommends including this section, even if we don't use |
173 | | * any of the features it affords. TODO: take advantage of the pixel |
174 | | * aspect ratio and encoder ID fields available? */ |
175 | 10.7k | memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26); |
176 | | |
177 | 10.7k | pkt->size = out + 26 - pkt->data; |
178 | 10.7k | *got_packet = 1; |
179 | | |
180 | 10.7k | return 0; |
181 | 10.7k | } |
182 | | |
183 | | static av_cold int targa_encode_init(AVCodecContext *avctx) |
184 | 375 | { |
185 | 375 | if (avctx->width > 0xffff || avctx->height > 0xffff) { |
186 | 0 | av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n"); |
187 | 0 | return AVERROR(EINVAL); |
188 | 0 | } |
189 | | |
190 | 375 | return 0; |
191 | 375 | } |
192 | | |
193 | | #define OFFSET(x) offsetof(TargaContext, x) |
194 | | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
195 | | static const AVOption options[] = { |
196 | | { "rle", "Use run-length compression", OFFSET(rle), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, |
197 | | |
198 | | { NULL }, |
199 | | }; |
200 | | |
201 | | static const AVClass targa_class = { |
202 | | .class_name = "targa", |
203 | | .item_name = av_default_item_name, |
204 | | .option = options, |
205 | | .version = LIBAVUTIL_VERSION_INT, |
206 | | }; |
207 | | |
208 | | const FFCodec ff_targa_encoder = { |
209 | | .p.name = "targa", |
210 | | CODEC_LONG_NAME("Truevision Targa image"), |
211 | | .p.type = AVMEDIA_TYPE_VIDEO, |
212 | | .p.id = AV_CODEC_ID_TARGA, |
213 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
214 | | .priv_data_size = sizeof(TargaContext), |
215 | | .p.priv_class = &targa_class, |
216 | | .init = targa_encode_init, |
217 | | FF_CODEC_ENCODE_CB(targa_encode_frame), |
218 | | CODEC_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, |
219 | | AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8), |
220 | | }; |