Mercurial > mplayer.hg
comparison libmpcodecs/vd_sgi.c @ 9534:87e03d96a4cd
add support for sgi files to mencoder patch by (Todd Kirby <slapcat at pacbell dot net>)
author | michael |
---|---|
date | Wed, 05 Mar 2003 10:38:56 +0000 |
parents | |
children | 8f3099900d8c |
comparison
equal
deleted
inserted
replaced
9533:9c596857cbe0 | 9534:87e03d96a4cd |
---|---|
1 /* | |
2 * author: Todd Kirby <slapcat@pacbell.net> | |
3 */ | |
4 | |
5 #include <stdio.h> | |
6 #include <stdlib.h> | |
7 | |
8 #include "config.h" | |
9 #include "mp_msg.h" | |
10 #include "bswap.h" | |
11 #include "vd_internal.h" | |
12 | |
13 #define SGI_HEADER_LEN 512 | |
14 #define SGI_MAGIC 474 | |
15 | |
16 #define SGI_GRAYSCALE_IMAGE 1 | |
17 #define SGI_RGB_IMAGE 3 | |
18 #define SGI_RGBA_IMAGE 4 | |
19 | |
20 #define OUT_PIXEL_STRIDE 3 /* RGB */ | |
21 | |
22 | |
23 static vd_info_t info = | |
24 { | |
25 "SGI Image decoder", | |
26 "sgi", | |
27 "Todd Kirby", | |
28 "Todd Kirby", | |
29 "" | |
30 }; | |
31 | |
32 LIBVD_EXTERN(sgi) | |
33 | |
34 typedef struct { | |
35 short magic; | |
36 char rle; | |
37 char bytes_per_channel; | |
38 unsigned short dimension; | |
39 unsigned short xsize; | |
40 unsigned short ysize; | |
41 unsigned short zsize; | |
42 } SGIInfo; | |
43 | |
44 static unsigned int outfmt = IMGFMT_BGR24; | |
45 | |
46 static unsigned short last_x = -1; | |
47 static unsigned short last_y = -1; | |
48 | |
49 | |
50 /* to set/get/query special features/parameters */ | |
51 static int | |
52 control(sh_video_t* sh, int cmd, void *arg, ...) | |
53 { | |
54 switch (cmd) | |
55 { | |
56 case VDCTRL_QUERY_FORMAT: | |
57 if (*((unsigned int *) arg) == outfmt) { | |
58 return CONTROL_TRUE; | |
59 } | |
60 return CONTROL_FALSE; | |
61 } | |
62 return CONTROL_UNKNOWN; | |
63 } | |
64 | |
65 | |
66 /* init driver */ | |
67 static int | |
68 init(sh_video_t *sh) | |
69 { | |
70 sh->context = (SGIInfo *) calloc(1, sizeof(SGIInfo)); | |
71 last_x = -1; | |
72 | |
73 return 1; | |
74 } | |
75 | |
76 | |
77 /* uninit driver */ | |
78 static void | |
79 uninit(sh_video_t *sh) | |
80 { | |
81 SGIInfo *info = sh->context; | |
82 free(info); | |
83 } | |
84 | |
85 | |
86 /* expand an rle row into a channel */ | |
87 static void | |
88 expandrow(unsigned char *optr, unsigned char *iptr, int chan_offset) | |
89 { | |
90 unsigned char pixel, count; | |
91 optr += chan_offset; | |
92 | |
93 while (1) { | |
94 pixel = *iptr++; | |
95 | |
96 if (!(count = (pixel & 0x7f))) { | |
97 return; | |
98 } | |
99 if(pixel & 0x80) { | |
100 while (count--) { | |
101 *optr = *iptr; | |
102 optr += OUT_PIXEL_STRIDE; | |
103 iptr++; | |
104 } | |
105 } else { | |
106 pixel = *iptr++; | |
107 | |
108 while (count--) { | |
109 *optr = pixel; | |
110 optr += OUT_PIXEL_STRIDE; | |
111 } | |
112 } | |
113 } | |
114 } | |
115 | |
116 | |
117 /* expand an rle row into all 3 channels. | |
118 a separate function for grayscale so we don't slow down the | |
119 more common case rgb function with a bunch of ifs. */ | |
120 static void | |
121 expandrow_gs(unsigned char *optr, unsigned char *iptr) | |
122 { | |
123 unsigned char pixel, count; | |
124 | |
125 while (1) { | |
126 pixel = *iptr++; | |
127 | |
128 if (!(count = (pixel & 0x7f))) { | |
129 return; | |
130 } | |
131 if(pixel & 0x80) { | |
132 while (count--) { | |
133 optr[0] = *iptr; | |
134 optr[1] = *iptr; | |
135 optr[2] = *iptr; | |
136 optr += OUT_PIXEL_STRIDE; | |
137 iptr++; | |
138 } | |
139 } else { | |
140 pixel = *iptr++; | |
141 | |
142 while (count--) { | |
143 optr[0] = pixel; | |
144 optr[1] = pixel; | |
145 optr[2] = pixel; | |
146 optr += OUT_PIXEL_STRIDE; | |
147 } | |
148 } | |
149 } | |
150 } | |
151 | |
152 | |
153 /* decode a run length encoded sgi image */ | |
154 static void | |
155 decode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi) | |
156 { | |
157 unsigned char *rle_data, *dest_row; | |
158 unsigned long *starttab; | |
159 int y, z, xsize, ysize, zsize, chan_offset; | |
160 long start_offset; | |
161 | |
162 xsize = info->xsize; | |
163 ysize = info->ysize; | |
164 zsize = info->zsize; | |
165 | |
166 /* rle offset table is right after the header */ | |
167 starttab = (long*)(data + SGI_HEADER_LEN); | |
168 | |
169 for (z = 0; z < zsize; z++) { | |
170 | |
171 /* set chan_offset so RGB ends up BGR */ | |
172 chan_offset = (zsize - 1) - z; | |
173 | |
174 /* The origin for SGI images is the lower-left corner | |
175 so read scan lines from bottom to top */ | |
176 for (y = ysize - 1; y >= 0; y--) { | |
177 dest_row = mpi->planes[0] + mpi->stride[0] * (ysize - 1 - y); | |
178 | |
179 /* set start of next run (offsets are from start of header) */ | |
180 start_offset = be2me_32(*(unsigned long*) &starttab[y + z * ysize]); | |
181 | |
182 rle_data = &data[start_offset]; | |
183 | |
184 if(info->zsize == SGI_GRAYSCALE_IMAGE) { | |
185 expandrow_gs(dest_row, rle_data); | |
186 } else { | |
187 expandrow(dest_row, rle_data, chan_offset); | |
188 } | |
189 } | |
190 } | |
191 } | |
192 | |
193 | |
194 /* decode an sgi image */ | |
195 static void | |
196 decode_uncompressed_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi) | |
197 { | |
198 unsigned char *src_row, *dest_row; | |
199 int x, y, z, xsize, ysize, zsize, chan_offset; | |
200 | |
201 xsize = info->xsize; | |
202 ysize = info->ysize; | |
203 zsize = info->zsize; | |
204 | |
205 /* skip header */ | |
206 data += SGI_HEADER_LEN; | |
207 | |
208 for (z = 0; z < zsize; z++) { | |
209 | |
210 /* set row ptr to start of current plane */ | |
211 src_row = data + (xsize * ysize * z); | |
212 | |
213 /* set chan_offset for RGB -> BGR */ | |
214 chan_offset = (zsize - 1) - z; | |
215 | |
216 /* the origin for SGI images is the lower-left corner | |
217 so read scan lines from bottom to top. */ | |
218 for (y = ysize - 1; y >= 0; y--) { | |
219 dest_row = mpi->planes[0] + mpi->stride[0] * y; | |
220 for (x = 0; x < xsize; x++) { | |
221 | |
222 /* we only do 24 bit output so promote 8 bit pixels to 24 */ | |
223 if (zsize == SGI_GRAYSCALE_IMAGE) { | |
224 /* write greyscale value into all channels */ | |
225 dest_row[0] = src_row[x]; | |
226 dest_row[1] = src_row[x]; | |
227 dest_row[2] = src_row[x]; | |
228 } else { | |
229 dest_row[chan_offset] = src_row[x]; | |
230 } | |
231 | |
232 dest_row += OUT_PIXEL_STRIDE; | |
233 } | |
234 | |
235 /* move to next row of the current source plane */ | |
236 src_row += xsize; | |
237 } | |
238 } | |
239 } | |
240 | |
241 | |
242 /* read sgi header fields */ | |
243 static void | |
244 read_sgi_header(unsigned char *buf, SGIInfo *info) | |
245 { | |
246 /* sgi data is always stored in big endian byte order */ | |
247 info->magic = be2me_16(*(unsigned short *) &buf[0]); | |
248 info->rle = buf[2]; | |
249 info->bytes_per_channel = buf[3]; | |
250 info->dimension = be2me_16(*(unsigned short *) &buf[4]); | |
251 info->xsize = be2me_16(*(unsigned short *) &buf[6]); | |
252 info->ysize = be2me_16(*(unsigned short *) &buf[8]); | |
253 info->zsize = be2me_16(*(unsigned short *) &buf[10]); | |
254 } | |
255 | |
256 | |
257 /* decode a frame */ | |
258 static | |
259 mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags) | |
260 { | |
261 SGIInfo *info = sh->context; | |
262 unsigned char *data = raw; | |
263 mp_image_t *mpi; | |
264 | |
265 if (len <= 0) { | |
266 return NULL; /* skip frame */ | |
267 } | |
268 | |
269 read_sgi_header(data, info); | |
270 | |
271 /* make sure this is an SGI image file */ | |
272 if (info->magic != SGI_MAGIC) { | |
273 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Bad magic number in image.\n"); | |
274 return NULL; | |
275 } | |
276 | |
277 /* check image depth */ | |
278 if (info->bytes_per_channel != 1) { | |
279 mp_msg(MSGT_DECVIDEO, MSGL_INFO, | |
280 "Unsupported bytes per channel value %i.\n", info->bytes_per_channel); | |
281 return NULL; | |
282 } | |
283 | |
284 /* check image dimension */ | |
285 if (info->dimension != 2 && info->dimension != 3) { | |
286 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image dimension %i.\n", | |
287 info->dimension); | |
288 return NULL; | |
289 } | |
290 | |
291 /* change rgba images to rgb so alpha channel will be ignored */ | |
292 if (info->zsize == SGI_RGBA_IMAGE) { | |
293 info->zsize = SGI_RGB_IMAGE; | |
294 } | |
295 | |
296 /* check image depth */ | |
297 if (info->zsize != SGI_RGB_IMAGE && info->zsize != SGI_GRAYSCALE_IMAGE) { | |
298 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image depth.\n"); | |
299 return NULL; | |
300 } | |
301 | |
302 /* (re)init libvo if image size is changed */ | |
303 if (last_x != info->xsize || last_y != info->ysize) | |
304 { | |
305 last_x = info->xsize; | |
306 last_y = info->ysize; | |
307 | |
308 if (!mpcodecs_config_vo(sh, info->xsize, info->ysize, outfmt)) { | |
309 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Config vo failed:\n"); | |
310 return NULL; | |
311 } | |
312 } | |
313 | |
314 if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |
315 info->xsize, info->ysize))) { | |
316 return NULL; | |
317 } | |
318 | |
319 if (info->rle) { | |
320 decode_rle_sgi(info, data, mpi); | |
321 } else { | |
322 decode_uncompressed_sgi(info, data, mpi); | |
323 } | |
324 | |
325 return mpi; | |
326 } | |
327 |