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