7362
|
1 /* author: Tilman Sauerbeck <tsauerbeck@users.sourceforge.net>
|
|
2 * based on: XreaL's x_r_img_tga.* (http://www.sourceforge.net/projects/xreal/)
|
|
3 * libtarga.*
|
|
4 * xli's tga.*
|
|
5 */
|
|
6
|
|
7 #include <stdio.h>
|
|
8 #include <stdlib.h>
|
|
9
|
|
10 #include "config.h"
|
|
11 #include "mp_msg.h"
|
|
12
|
|
13 #include "bswap.h"
|
|
14 #include "postproc/rgb2rgb.h"
|
|
15 #include "libvo/fastmemcpy.h"
|
|
16
|
|
17 #include "vd_internal.h"
|
|
18
|
|
19 static vd_info_t info =
|
|
20 {
|
|
21 "TGA Images decoder",
|
|
22 "mtga",
|
|
23 "Tilman Sauerbeck",
|
|
24 "Tilman Sauerbeck",
|
|
25 "only 24bpp and 32bpp RGB targa files support so far"
|
|
26 };
|
|
27
|
|
28 LIBVD_EXTERN(mtga)
|
|
29
|
|
30 typedef enum
|
|
31 {
|
|
32 TGA_NO_DATA,
|
|
33 TGA_UNCOMP_PALETTED,
|
|
34 TGA_UNCOMP_TRUECOLOR,
|
|
35 TGA_UNCOMP_GRAYSCALE,
|
|
36 TGA_RLE_PALETTED = 9,
|
|
37 TGA_RLE_TRUECOLOR,
|
|
38 TGA_RLE_GRAYSCALE
|
|
39 } TGAImageType;
|
|
40
|
|
41 typedef struct
|
|
42 {
|
|
43 unsigned char id_len;
|
|
44 unsigned short img_type;
|
|
45
|
|
46 unsigned short width;
|
|
47 unsigned short height;
|
|
48
|
|
49 unsigned char bpp;
|
|
50 unsigned char origin; /* 0 = lower left, 1 = upper left */
|
|
51 } TGAInfo;
|
|
52
|
|
53 typedef struct
|
|
54 {
|
|
55 /* red, green, blue, alpha */
|
|
56 unsigned char r;
|
|
57 unsigned char g;
|
|
58 unsigned char b;
|
|
59 unsigned char a;
|
|
60 } ColorChannels;
|
|
61
|
|
62
|
|
63 static unsigned int out_fmt = 0;
|
|
64
|
|
65 static int last_w = -1;
|
|
66 static int last_h = -1;
|
|
67 static int last_c = -1;
|
|
68
|
|
69 /* to set/get/query special features/parameters */
|
|
70 static int control(sh_video_t *sh, int cmd, void *arg, ...)
|
|
71 {
|
|
72 return CONTROL_UNKNOWN;
|
|
73 }
|
|
74
|
|
75 /* init driver */
|
|
76 static int init(sh_video_t *sh)
|
|
77 {
|
|
78 last_w = -1;
|
|
79 return 1;
|
|
80 }
|
|
81
|
|
82
|
|
83 /* uninit driver */
|
|
84 static void uninit(sh_video_t *sh)
|
|
85 {
|
|
86 }
|
|
87
|
|
88
|
|
89 /* decode a runlength-encoded tga */
|
|
90 static void decode_rle_tga(TGAInfo info, unsigned char *data, mp_image_t **mpi)
|
|
91 {
|
|
92 ColorChannels chans = {0, 0, 0, 0};
|
|
93 unsigned char repetitions, packet_header, *final;
|
|
94 unsigned short row, col, i;
|
|
95 short modifier;
|
|
96
|
|
97
|
|
98 /* if img.origin is 0, we decode from bottom to top. if it's 1, we decode from top to bottom */
|
|
99 row = (info.origin) ? 0 : info.height - 1;
|
|
100 modifier = (info.origin) ? 1 : -1;
|
|
101
|
|
102 for (;;)
|
|
103 {
|
|
104 final = (*mpi)->planes[0] + (*mpi)->stride[0] * row;
|
|
105
|
|
106 for (col = 0; col < info.width;)
|
|
107 {
|
|
108 packet_header = *data++;
|
|
109 repetitions = 1 + (packet_header & 0x7f);
|
|
110
|
|
111 if (packet_header & 0x80)
|
|
112 {
|
|
113 chans.b = *data++;
|
|
114 chans.g = *data++;
|
|
115 chans.r = *data++;
|
|
116 chans.a = (info.bpp == 32) ? *data++ : 255;
|
|
117
|
|
118 for (i = 0; i < repetitions; i++)
|
|
119 {
|
|
120 *final++ = chans.r;
|
|
121 *final++ = chans.g;
|
|
122 *final++ = chans.b;
|
|
123 *final++ = chans.a;
|
|
124
|
|
125 col++;
|
|
126 }
|
|
127 }
|
|
128 else /* raw packet */
|
|
129 {
|
|
130 for (i = 0; i < repetitions; i++)
|
|
131 {
|
|
132 chans.b = *data++;
|
|
133 chans.g = *data++;
|
|
134 chans.r = *data++;
|
|
135
|
|
136 *final++ = chans.r;
|
|
137 *final++ = chans.g;
|
|
138 *final++ = chans.b;
|
|
139 *final++ = chans.a = (info.bpp == 32) ? *data++ : 255;
|
|
140
|
|
141 col++;
|
|
142 }
|
|
143 }
|
|
144 }
|
|
145
|
|
146 row = row + modifier;
|
|
147
|
|
148 if ((!info.origin && !row) || (info.origin && row >= info.height))
|
|
149 break;
|
|
150 }
|
|
151
|
|
152
|
|
153 return;
|
|
154 }
|
|
155
|
|
156
|
|
157 static void decode_uncompressed_tga(TGAInfo info, unsigned char *data, mp_image_t **mpi)
|
|
158 {
|
|
159 ColorChannels chans;
|
|
160 unsigned short row, col;
|
|
161 unsigned char *final;
|
|
162 short modifier;
|
|
163
|
|
164
|
|
165 /* if img.origin is 0, we decode from bottom to top. if it's 1, we decode from top to bottom */
|
|
166 row = (info.origin) ? 0 : info.height - 1;
|
|
167 modifier = (info.origin) ? 1 : -1;
|
|
168
|
|
169 for (;;)
|
|
170 {
|
|
171 final = (*mpi)->planes[0] + (*mpi)->stride[0] * row;
|
|
172
|
|
173 for (col = 0; col < info.width; col++)
|
|
174 {
|
|
175 chans.b = *data++;
|
|
176 chans.g = *data++;
|
|
177 chans.r = *data++;
|
|
178
|
|
179 *final++ = chans.r;
|
|
180 *final++ = chans.g;
|
|
181 *final++ = chans.b;
|
|
182 *final++ = info.bpp == 32 ? *data++ : 255;
|
|
183
|
|
184 }
|
|
185
|
|
186 row = row + modifier;
|
|
187
|
|
188 if ((!info.origin && !row) || (info.origin && row >= info.height))
|
|
189 break;
|
|
190 }
|
|
191
|
|
192
|
|
193 return;
|
|
194 }
|
|
195
|
|
196
|
|
197 static short read_tga_header(unsigned char *buf, TGAInfo *info)
|
|
198 {
|
|
199 (*info).id_len = buf[0];
|
|
200
|
|
201 (*info).img_type = buf[2];
|
|
202
|
|
203 /* targa data is always stored in little endian byte order */
|
|
204 (*info).width = le2me_16(*(unsigned short *) &buf[12]);
|
|
205 (*info).height = le2me_16(*(unsigned short *) &buf[14]);
|
|
206
|
|
207 (*info).bpp = buf[16];
|
|
208
|
|
209 (*info).origin = (buf[17] & 0x20) >> 5;
|
|
210
|
|
211 /* FIXME check for valid targa data */
|
|
212
|
|
213 return 0;
|
|
214 }
|
|
215
|
|
216
|
|
217 /* decode a frame */
|
|
218 static mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags)
|
|
219 {
|
|
220 TGAInfo info;
|
|
221 unsigned char *data = raw;
|
|
222 mp_image_t *mpi;
|
|
223
|
|
224
|
|
225 if (len <= 0)
|
|
226 return NULL; /* skip frame */
|
|
227
|
|
228 read_tga_header(data, &info); /* read information about the file */
|
|
229
|
|
230 if (info.bpp == 24)
|
|
231 out_fmt = IMGFMT_RGB24;
|
|
232 else if (info.bpp == 32)
|
|
233 out_fmt = IMGFMT_RGB32;
|
|
234 else
|
|
235 {
|
|
236 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported TGA type!\n");
|
|
237 return NULL;
|
|
238 }
|
|
239
|
|
240 if (info.img_type != TGA_UNCOMP_TRUECOLOR && info.img_type != TGA_RLE_TRUECOLOR) /* not a true color image */
|
|
241 {
|
|
242 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported TGA type: %i!\n", info.img_type);
|
|
243 return NULL;
|
|
244 }
|
|
245
|
|
246 /* set data to the beginning of the image data */
|
|
247 data = data + 18 + info.id_len;
|
|
248
|
|
249 /* (re)init libvo if image parameters changed (width/height/colorspace) */
|
|
250 if (last_w != info.width || last_h != info.height || last_c != out_fmt)
|
|
251 {
|
|
252 last_w = info.width;
|
|
253 last_h = info.height;
|
|
254 last_c = out_fmt;
|
|
255
|
|
256 if (!out_fmt || !mpcodecs_config_vo(sh, info.width, info.height, out_fmt))
|
|
257 return NULL;
|
|
258 }
|
|
259
|
|
260 if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, info.width, info.height)))
|
|
261 return NULL;
|
|
262
|
|
263 /* finally decode the image */
|
|
264 if (info.img_type == TGA_UNCOMP_TRUECOLOR)
|
|
265 decode_uncompressed_tga(info, data, &mpi);
|
|
266 else if (info.img_type == TGA_RLE_TRUECOLOR)
|
|
267 decode_rle_tga(info, data, &mpi);
|
|
268 else
|
|
269 mpi = NULL;
|
|
270
|
|
271
|
|
272 return mpi;
|
|
273 }
|
|
274
|