targa.c
Go to the documentation of this file.
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 "libavutil/intreadwrite.h"
23 #include "libavutil/imgutils.h"
24 #include "avcodec.h"
25 #include "bytestream.h"
26 #include "internal.h"
27 #include "targa.h"
28 
29 typedef struct TargaContext {
31 } TargaContext;
32 
33 static uint8_t *advance_line(uint8_t *start, uint8_t *line,
34  int stride, int *y, int h, int interleave)
35 {
36  *y += interleave;
37 
38  if (*y < h) {
39  return line + interleave * stride;
40  } else {
41  *y = (*y + 1) & (interleave - 1);
42  if (*y && *y < h) {
43  return start + *y * stride;
44  } else {
45  return NULL;
46  }
47  }
48 }
49 
51  uint8_t *start, int w, int h, int stride,
52  int bpp, int interleave)
53 {
54  int x, y;
55  int depth = (bpp + 1) >> 3;
56  int type, count;
57  uint8_t *line = start;
58  uint8_t *dst = line;
59 
60  x = y = count = 0;
61  while (dst) {
62  if (bytestream2_get_bytes_left(&s->gb) <= 0) {
63  av_log(avctx, AV_LOG_ERROR,
64  "Ran ouf of data before end-of-image\n");
65  return AVERROR_INVALIDDATA;
66  }
67  type = bytestream2_get_byteu(&s->gb);
68  count = (type & 0x7F) + 1;
69  type &= 0x80;
70  if (!type) {
71  do {
72  int n = FFMIN(count, w - x);
73  bytestream2_get_buffer(&s->gb, dst, n * depth);
74  count -= n;
75  dst += n * depth;
76  x += n;
77  if (x == w) {
78  x = 0;
79  dst = line = advance_line(start, line, stride, &y, h, interleave);
80  }
81  } while (dst && count > 0);
82  } else {
83  uint8_t tmp[4];
84  bytestream2_get_buffer(&s->gb, tmp, depth);
85  do {
86  int n = FFMIN(count, w - x);
87  count -= n;
88  x += n;
89  do {
90  memcpy(dst, tmp, depth);
91  dst += depth;
92  } while (--n);
93  if (x == w) {
94  x = 0;
95  dst = line = advance_line(start, line, stride, &y, h, interleave);
96  }
97  } while (dst && count > 0);
98  }
99  }
100 
101  if (count) {
102  av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n");
103  return AVERROR_INVALIDDATA;
104  }
105 
106  return 0;
107 }
108 
109 static int decode_frame(AVCodecContext *avctx,
110  void *data, int *got_frame,
111  AVPacket *avpkt)
112 {
113  TargaContext * const s = avctx->priv_data;
114  AVFrame * const p = data;
115  uint8_t *dst;
116  int stride;
117  int idlen, pal, compr, y, w, h, bpp, flags, ret;
118  int first_clr, colors, csize;
119  int interleave;
120 
121  bytestream2_init(&s->gb, avpkt->data, avpkt->size);
122 
123  /* parse image header */
124  idlen = bytestream2_get_byte(&s->gb);
125  pal = bytestream2_get_byte(&s->gb);
126  compr = bytestream2_get_byte(&s->gb);
127  first_clr = bytestream2_get_le16(&s->gb);
128  colors = bytestream2_get_le16(&s->gb);
129  csize = bytestream2_get_byte(&s->gb);
130  bytestream2_skip(&s->gb, 4); /* 2: x, 2: y */
131  w = bytestream2_get_le16(&s->gb);
132  h = bytestream2_get_le16(&s->gb);
133  bpp = bytestream2_get_byte(&s->gb);
134 
135  if (bytestream2_get_bytes_left(&s->gb) <= idlen) {
136  av_log(avctx, AV_LOG_ERROR,
137  "Not enough data to read header\n");
138  return AVERROR_INVALIDDATA;
139  }
140 
141  flags = bytestream2_get_byte(&s->gb);
142 
143  if (!pal && (first_clr || colors || csize)) {
144  av_log(avctx, AV_LOG_WARNING, "File without colormap has colormap information set.\n");
145  // specification says we should ignore those value in this case
146  first_clr = colors = csize = 0;
147  }
148 
149  // skip identifier if any
150  bytestream2_skip(&s->gb, idlen);
151 
152  switch (bpp) {
153  case 8:
154  avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_PAL8;
155  break;
156  case 15:
157  case 16:
158  avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
159  break;
160  case 24:
161  avctx->pix_fmt = AV_PIX_FMT_BGR24;
162  break;
163  case 32:
164  avctx->pix_fmt = AV_PIX_FMT_BGRA;
165  break;
166  default:
167  av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", bpp);
168  return AVERROR_INVALIDDATA;
169  }
170 
171  if (colors && (colors + first_clr) > 256) {
172  av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
173  return AVERROR_INVALIDDATA;
174  }
175 
176  if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
177  return ret;
178  if (w != avctx->width || h != avctx->height)
179  avcodec_set_dimensions(avctx, w, h);
180  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
181  return ret;
182 
183  if (flags & TGA_TOPTOBOTTOM) {
184  dst = p->data[0];
185  stride = p->linesize[0];
186  } else { //image is upside-down
187  dst = p->data[0] + p->linesize[0] * (h - 1);
188  stride = -p->linesize[0];
189  }
190 
191  interleave = flags & TGA_INTERLEAVE2 ? 2 :
192  flags & TGA_INTERLEAVE4 ? 4 : 1;
193 
194  if (colors) {
195  int pal_size, pal_sample_size;
196 
197  switch (csize) {
198  case 32: pal_sample_size = 4; break;
199  case 24: pal_sample_size = 3; break;
200  case 16:
201  case 15: pal_sample_size = 2; break;
202  default:
203  av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize);
204  return AVERROR_INVALIDDATA;
205  }
206  pal_size = colors * pal_sample_size;
207  if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway
208  bytestream2_skip(&s->gb, pal_size);
209  else {
210  int t;
211  uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr;
212 
213  if (bytestream2_get_bytes_left(&s->gb) < pal_size) {
214  av_log(avctx, AV_LOG_ERROR,
215  "Not enough data to read palette\n");
216  return AVERROR_INVALIDDATA;
217  }
218  switch (pal_sample_size) {
219  case 4:
220  for (t = 0; t < colors; t++)
221  *pal++ = bytestream2_get_le32u(&s->gb);
222  break;
223  case 3:
224  /* RGB24 */
225  for (t = 0; t < colors; t++)
226  *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
227  break;
228  case 2:
229  /* RGB555 */
230  for (t = 0; t < colors; t++) {
231  uint32_t v = bytestream2_get_le16u(&s->gb);
232  v = ((v & 0x7C00) << 9) |
233  ((v & 0x03E0) << 6) |
234  ((v & 0x001F) << 3);
235  /* left bit replication */
236  v |= (v & 0xE0E0E0U) >> 5;
237  *pal++ = (0xffU<<24) | v;
238  }
239  break;
240  }
241  p->palette_has_changed = 1;
242  }
243  }
244 
245  if ((compr & (~TGA_RLE)) == TGA_NODATA) {
246  memset(p->data[0], 0, p->linesize[0] * h);
247  } else {
248  if (compr & TGA_RLE) {
249  int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
250  if (res < 0)
251  return res;
252  } else {
253  size_t img_size = w * ((bpp + 1) >> 3);
254  uint8_t *line;
255  if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
256  av_log(avctx, AV_LOG_ERROR,
257  "Not enough data available for image\n");
258  return AVERROR_INVALIDDATA;
259  }
260 
261  line = dst;
262  y = 0;
263  do {
264  bytestream2_get_buffer(&s->gb, line, img_size);
265  line = advance_line(dst, line, stride, &y, h, interleave);
266  } while (line);
267  }
268  }
269 
270  if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
271  int x;
272  for (y = 0; y < h; y++) {
273  void *line = &p->data[0][y * p->linesize[0]];
274  for (x = 0; x < w >> 1; x++) {
275  switch (bpp) {
276  case 32:
277  FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
278  break;
279  case 24:
280  FFSWAP(uint8_t, ((uint8_t *)line)[3 * x ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
281  FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
282  FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
283  break;
284  case 16:
285  FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
286  break;
287  case 8:
288  FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
289  }
290  }
291  }
292  }
293 
294  *got_frame = 1;
295 
296  return avpkt->size;
297 }
298 
300  .name = "targa",
301  .type = AVMEDIA_TYPE_VIDEO,
302  .id = AV_CODEC_ID_TARGA,
303  .priv_data_size = sizeof(TargaContext),
304  .decode = decode_frame,
305  .capabilities = CODEC_CAP_DR1,
306  .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
307 };
Definition: start.py:1
float v
const char * s
Definition: avisynth_c.h:668
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
Definition: targa.h:37
misc image utilities
Definition: targa.h:38
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 ...
Definition: pixfmt.h:117
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:130
static av_always_inline void interleave(IDWTELEM *dst, IDWTELEM *src0, IDWTELEM *src1, int w2, int add, int shift)
Definition: dirac_dwt.c:51
int stride
Definition: mace.c:144
output residual component w
targa file common definitions
static uint8_t * advance_line(uint8_t *start, uint8_t *line, int stride, int *y, int h, int interleave)
Definition: targa.c:33
8 bit with PIX_FMT_RGB32 palette
Definition: pixfmt.h:79
static av_always_inline unsigned int bytestream2_get_le32u(GetByteContext *g)
Definition: bytestream.h:85
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
uint8_t * data
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: targa.c:109
uint8_t * data[8]
pointer to the picture/channel planes.
Definition: frame.h:87
Discrete Time axis x
#define U(x)
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:159
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:99
Spectrum Plot time data
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:258
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:149
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Send the specified message to the log if the level is less than or equal to the current av_log_level...
Definition: log.c:246
const char * name
Name of the codec implementation.
external API header
int depth
Definition: v4l.c:62
GetByteContext gb
Definition: targa.c:30
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:231
static av_always_inline unsigned int bytestream2_get_le16(GetByteContext *g)
Definition: bytestream.h:87
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
int width
picture width / height.
t
Definition: genspecsines3.m:6
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:71
NULL
Definition: eval.c:55
AVCodec ff_targa_decoder
Definition: targa.c:299
main external API structure.
static av_always_inline unsigned int bytestream2_get_le16u(GetByteContext *g)
Definition: bytestream.h:87
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:280
const uint8_t ptrdiff_t int h
Definition: hpel_template.c:97
static av_always_inline unsigned int bytestream2_get_byteu(GetByteContext *g)
Definition: bytestream.h:92
#define type
static int flags
Definition: cpu.c:23
struct TargaContext TargaContext
static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s, uint8_t *start, int w, int h, int stride, int bpp, int interleave)
Definition: targa.c:50
Y , 8bpp.
Definition: pixfmt.h:76
common internal api header.
function y
Definition: D.m:1
int linesize[8]
For video, size in bytes of each picture line.
Definition: frame.h:101
static av_always_inline unsigned int bytestream2_get_le24u(GetByteContext *g)
Definition: bytestream.h:86
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip please avoid problems through this extra level of scrutiny For cosmetics only commits you should e g by running git config global user name My Name git config global user email my email which is either set in your personal configuration file through git config core editor or set by one of the following environment VISUAL or EDITOR Log messages should be concise but descriptive Explain why you made a what you did will be obvious from the changes themselves most of the time Saying just bug fix or is bad Remember that people of varying skill levels look at and educate themselves while reading through your code Don t include filenames in log Git provides that information Possibly make the commit message have a descriptive first line
Definition: git-howto.txt:153
void INT64 INT64 count
Definition: avisynth_c.h:594
void INT64 start
Definition: avisynth_c.h:594
static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: crystalhd.c:868
#define FFSWAP(type, a, b)
Definition: common.h:61
This structure stores compressed data.
static av_always_inline unsigned int bytestream2_get_byte(GetByteContext *g)
Definition: bytestream.h:92