/src/ffmpeg/libavcodec/targa.c
Line | Count | Source |
1 | | /* |
2 | | * Targa (.tga) image decoder |
3 | | * Copyright (c) 2006 Konstantin Shishkov |
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 "avcodec.h" |
23 | | #include "bytestream.h" |
24 | | #include "codec_internal.h" |
25 | | #include "decode.h" |
26 | | #include "targa.h" |
27 | | |
28 | | typedef struct TargaContext { |
29 | | GetByteContext gb; |
30 | | } TargaContext; |
31 | | |
32 | | static uint8_t *advance_line(uint8_t *start, uint8_t *line, |
33 | | int stride, int *y, int h, int interleave) |
34 | 1.58M | { |
35 | 1.58M | *y += interleave; |
36 | | |
37 | 1.58M | if (*y < h) { |
38 | 1.58M | return line + interleave * stride; |
39 | 1.58M | } else { |
40 | 5.37k | *y = (*y + 1) & (interleave - 1); |
41 | 5.37k | if (*y && *y < h) { |
42 | 1.95k | return start + *y * stride; |
43 | 3.41k | } else { |
44 | 3.41k | return NULL; |
45 | 3.41k | } |
46 | 5.37k | } |
47 | 1.58M | } |
48 | | |
49 | | static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s, |
50 | | uint8_t *start, int w, int h, int stride, |
51 | | int bpp, int interleave) |
52 | 7.39k | { |
53 | 7.39k | int x, y; |
54 | 7.39k | int depth = (bpp + 1) >> 3; |
55 | 7.39k | int type, count; |
56 | 7.39k | uint8_t *line = start; |
57 | 7.39k | uint8_t *dst = line; |
58 | | |
59 | 7.39k | x = y = count = 0; |
60 | 1.00M | while (dst) { |
61 | 1.00M | if (bytestream2_get_bytes_left(&s->gb) <= 0) { |
62 | 5.23k | av_log(avctx, AV_LOG_ERROR, |
63 | 5.23k | "Ran ouf of data before end-of-image\n"); |
64 | 5.23k | return AVERROR_INVALIDDATA; |
65 | 5.23k | } |
66 | 997k | type = bytestream2_get_byteu(&s->gb); |
67 | 997k | count = (type & 0x7F) + 1; |
68 | 997k | type &= 0x80; |
69 | 997k | if (!type) { |
70 | 971k | do { |
71 | 971k | int n = FFMIN(count, w - x); |
72 | 971k | bytestream2_get_buffer(&s->gb, dst, n * depth); |
73 | 971k | count -= n; |
74 | 971k | dst += n * depth; |
75 | 971k | x += n; |
76 | 971k | if (x == w) { |
77 | 96.7k | x = 0; |
78 | 96.7k | dst = line = advance_line(start, line, stride, &y, h, interleave); |
79 | 96.7k | } |
80 | 971k | } while (dst && count > 0); |
81 | 931k | } else { |
82 | 65.6k | uint8_t tmp[4]; |
83 | 65.6k | bytestream2_get_buffer(&s->gb, tmp, depth); |
84 | 1.09M | do { |
85 | 1.09M | int n = FFMIN(count, w - x); |
86 | 1.09M | count -= n; |
87 | 1.09M | x += n; |
88 | 6.25M | do { |
89 | 6.25M | memcpy(dst, tmp, depth); |
90 | 6.25M | dst += depth; |
91 | 6.25M | } while (--n); |
92 | 1.09M | if (x == w) { |
93 | 1.04M | x = 0; |
94 | 1.04M | dst = line = advance_line(start, line, stride, &y, h, interleave); |
95 | 1.04M | } |
96 | 1.09M | } while (dst && count > 0); |
97 | 65.6k | } |
98 | 997k | } |
99 | | |
100 | 2.16k | if (count) { |
101 | 753 | av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n"); |
102 | 753 | return AVERROR_INVALIDDATA; |
103 | 753 | } |
104 | | |
105 | 1.40k | return 0; |
106 | 2.16k | } |
107 | | |
108 | | static int decode_frame(AVCodecContext *avctx, AVFrame *p, |
109 | | int *got_frame, AVPacket *avpkt) |
110 | 88.2k | { |
111 | 88.2k | TargaContext * const s = avctx->priv_data; |
112 | 88.2k | uint8_t *dst; |
113 | 88.2k | int stride; |
114 | 88.2k | int idlen, pal, compr, y, w, h, bpp, flags, ret; |
115 | 88.2k | int first_clr, colors, csize; |
116 | 88.2k | int interleave; |
117 | 88.2k | size_t img_size; |
118 | | |
119 | 88.2k | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
120 | | |
121 | | /* parse image header */ |
122 | 88.2k | idlen = bytestream2_get_byte(&s->gb); |
123 | 88.2k | pal = bytestream2_get_byte(&s->gb); |
124 | 88.2k | compr = bytestream2_get_byte(&s->gb); |
125 | 88.2k | first_clr = bytestream2_get_le16(&s->gb); |
126 | 88.2k | colors = bytestream2_get_le16(&s->gb); |
127 | 88.2k | csize = bytestream2_get_byte(&s->gb); |
128 | 88.2k | bytestream2_skip(&s->gb, 4); /* 2: x, 2: y */ |
129 | 88.2k | w = bytestream2_get_le16(&s->gb); |
130 | 88.2k | h = bytestream2_get_le16(&s->gb); |
131 | 88.2k | bpp = bytestream2_get_byte(&s->gb); |
132 | | |
133 | 88.2k | flags = bytestream2_get_byte(&s->gb); |
134 | | |
135 | 88.2k | if (!pal && (first_clr || colors || csize)) { |
136 | 54.2k | av_log(avctx, AV_LOG_WARNING, "File without colormap has colormap information set.\n"); |
137 | | // specification says we should ignore those value in this case |
138 | 54.2k | first_clr = colors = csize = 0; |
139 | 54.2k | } |
140 | | |
141 | 88.2k | if (bytestream2_get_bytes_left(&s->gb) < idlen + 2*colors) { |
142 | 13.2k | av_log(avctx, AV_LOG_ERROR, |
143 | 13.2k | "Not enough data to read header\n"); |
144 | 13.2k | return AVERROR_INVALIDDATA; |
145 | 13.2k | } |
146 | | |
147 | | // skip identifier if any |
148 | 75.0k | bytestream2_skip(&s->gb, idlen); |
149 | | |
150 | 75.0k | switch (bpp) { |
151 | 3.68k | case 8: |
152 | 3.68k | avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_PAL8; |
153 | 3.68k | break; |
154 | 60.8k | case 15: |
155 | 62.7k | case 16: |
156 | 62.7k | avctx->pix_fmt = AV_PIX_FMT_RGB555LE; |
157 | 62.7k | break; |
158 | 1.42k | case 24: |
159 | 1.42k | avctx->pix_fmt = AV_PIX_FMT_BGR24; |
160 | 1.42k | break; |
161 | 3.60k | case 32: |
162 | 3.60k | avctx->pix_fmt = AV_PIX_FMT_BGRA; |
163 | 3.60k | break; |
164 | 3.54k | default: |
165 | 3.54k | av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", bpp); |
166 | 3.54k | return AVERROR_INVALIDDATA; |
167 | 75.0k | } |
168 | | |
169 | 71.4k | if (colors && (colors + first_clr) > 256) { |
170 | 216 | av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); |
171 | 216 | return AVERROR_INVALIDDATA; |
172 | 216 | } |
173 | | |
174 | 71.2k | if ((ret = ff_set_dimensions(avctx, w, h)) < 0) |
175 | 1.05k | return ret; |
176 | | |
177 | 70.2k | if ((compr & (~TGA_RLE)) == TGA_NODATA) { |
178 | 59.9k | return avpkt->size; |
179 | 59.9k | } |
180 | | |
181 | 10.3k | if (!(compr & TGA_RLE)) { |
182 | 2.01k | img_size = w * ((bpp + 1) >> 3); |
183 | 2.01k | if (bytestream2_get_bytes_left(&s->gb) < img_size * h) { |
184 | 540 | av_log(avctx, AV_LOG_ERROR, |
185 | 540 | "Not enough data available for image\n"); |
186 | 540 | return AVERROR_INVALIDDATA; |
187 | 540 | } |
188 | 2.01k | } |
189 | | |
190 | 9.77k | if ((ret = ff_get_buffer(avctx, p, 0)) < 0) |
191 | 113 | return ret; |
192 | 9.65k | p->pict_type = AV_PICTURE_TYPE_I; |
193 | | |
194 | 9.65k | if (flags & TGA_TOPTOBOTTOM) { |
195 | 3.41k | dst = p->data[0]; |
196 | 3.41k | stride = p->linesize[0]; |
197 | 6.24k | } else { //image is upside-down |
198 | 6.24k | dst = p->data[0] + p->linesize[0] * (h - 1); |
199 | 6.24k | stride = -p->linesize[0]; |
200 | 6.24k | } |
201 | | |
202 | 9.65k | interleave = flags & TGA_INTERLEAVE2 ? 2 : |
203 | 9.65k | flags & TGA_INTERLEAVE4 ? 4 : 1; |
204 | | |
205 | 9.65k | if (colors) { |
206 | 3.05k | int pal_size, pal_sample_size; |
207 | | |
208 | 3.05k | switch (csize) { |
209 | 751 | case 32: pal_sample_size = 4; break; |
210 | 1.14k | case 24: pal_sample_size = 3; break; |
211 | 738 | case 16: |
212 | 950 | case 15: pal_sample_size = 2; break; |
213 | 212 | default: |
214 | 212 | av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); |
215 | 212 | return AVERROR_INVALIDDATA; |
216 | 3.05k | } |
217 | 2.84k | pal_size = colors * pal_sample_size; |
218 | 2.84k | if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway |
219 | 893 | bytestream2_skip(&s->gb, pal_size); |
220 | 1.95k | else { |
221 | 1.95k | int t; |
222 | 1.95k | uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr; |
223 | | |
224 | 1.95k | if (bytestream2_get_bytes_left(&s->gb) < pal_size) { |
225 | 576 | av_log(avctx, AV_LOG_ERROR, |
226 | 576 | "Not enough data to read palette\n"); |
227 | 576 | return AVERROR_INVALIDDATA; |
228 | 576 | } |
229 | 1.37k | switch (pal_sample_size) { |
230 | 215 | case 4: |
231 | 2.63k | for (t = 0; t < colors; t++) |
232 | 2.42k | *pal++ = bytestream2_get_le32u(&s->gb); |
233 | 215 | break; |
234 | 572 | case 3: |
235 | | /* RGB24 */ |
236 | 1.92k | for (t = 0; t < colors; t++) |
237 | 1.35k | *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb); |
238 | 572 | break; |
239 | 587 | case 2: |
240 | | /* RGB555 */ |
241 | 3.05k | for (t = 0; t < colors; t++) { |
242 | 2.46k | uint32_t v = bytestream2_get_le16u(&s->gb); |
243 | 2.46k | v = ((v & 0x7C00) << 9) | |
244 | 2.46k | ((v & 0x03E0) << 6) | |
245 | 2.46k | ((v & 0x001F) << 3); |
246 | | /* left bit replication */ |
247 | 2.46k | v |= (v & 0xE0E0E0U) >> 5; |
248 | 2.46k | *pal++ = (0xffU<<24) | v; |
249 | 2.46k | } |
250 | 587 | break; |
251 | 1.37k | } |
252 | 1.37k | } |
253 | 2.84k | } |
254 | | |
255 | 8.86k | if (compr & TGA_RLE) { |
256 | 7.39k | int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave); |
257 | 7.39k | if (res < 0) |
258 | 5.98k | return res; |
259 | 7.39k | } else { |
260 | 1.47k | uint8_t *line; |
261 | 1.47k | if (bytestream2_get_bytes_left(&s->gb) < img_size * h) { |
262 | 222 | av_log(avctx, AV_LOG_ERROR, |
263 | 222 | "Not enough data available for image\n"); |
264 | 222 | return AVERROR_INVALIDDATA; |
265 | 222 | } |
266 | | |
267 | 1.24k | line = dst; |
268 | 1.24k | y = 0; |
269 | 448k | do { |
270 | 448k | bytestream2_get_buffer(&s->gb, line, img_size); |
271 | 448k | line = advance_line(dst, line, stride, &y, h, interleave); |
272 | 448k | } while (line); |
273 | 1.24k | } |
274 | | |
275 | 2.65k | if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip |
276 | 592k | for (int y = 0; y < h; y++) { |
277 | 590k | void *line = &p->data[0][y * p->linesize[0]]; |
278 | 1.51M | for (int x = 0; x < w >> 1; x++) { |
279 | 925k | switch (bpp) { |
280 | 9.78k | case 32: |
281 | 9.78k | FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]); |
282 | 9.78k | break; |
283 | 1.53k | case 24: |
284 | 1.53k | FFSWAP(uint8_t, ((uint8_t *)line)[3 * x ], ((uint8_t *)line)[3 * w - 3 * x - 3]); |
285 | 1.53k | FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]); |
286 | 1.53k | FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]); |
287 | 1.53k | break; |
288 | 444k | case 16: |
289 | 444k | FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]); |
290 | 444k | break; |
291 | 464k | case 8: |
292 | 464k | FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]); |
293 | 925k | } |
294 | 925k | } |
295 | 590k | } |
296 | 1.74k | } |
297 | | |
298 | | |
299 | 2.65k | *got_frame = 1; |
300 | | |
301 | 2.65k | return avpkt->size; |
302 | 2.65k | } |
303 | | |
304 | | const FFCodec ff_targa_decoder = { |
305 | | .p.name = "targa", |
306 | | CODEC_LONG_NAME("Truevision Targa image"), |
307 | | .p.type = AVMEDIA_TYPE_VIDEO, |
308 | | .p.id = AV_CODEC_ID_TARGA, |
309 | | .p.capabilities = AV_CODEC_CAP_DR1, |
310 | | .priv_data_size = sizeof(TargaContext), |
311 | | FF_CODEC_DECODE_CB(decode_frame), |
312 | | }; |