small compilation fix
[mplayer/glamo.git] / libmpcodecs / vd_sgi.c
blob1cc9ebb40cc5ae2a1c86a3a08a4bba6964a9c58a
1 /*
2 * author: Todd Kirby <slapcat@pacbell.net>
3 */
5 #include <stdio.h>
6 #include <stdlib.h>
8 #include "config.h"
9 #include "mp_msg.h"
10 #include "bswap.h"
11 #include "vd_internal.h"
13 #define SGI_HEADER_LEN 512
14 #define SGI_MAGIC 474
16 #define SGI_GRAYSCALE_IMAGE 1
17 #define SGI_RGB_IMAGE 3
18 #define SGI_RGBA_IMAGE 4
20 #define OUT_PIXEL_STRIDE 3 /* RGB */
23 static vd_info_t info =
25 "SGI Image decoder",
26 "sgi",
27 "Todd Kirby",
28 "Todd Kirby",
32 LIBVD_EXTERN(sgi)
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;
44 static unsigned int outfmt = IMGFMT_BGR24;
46 static unsigned short last_x = -1;
47 static unsigned short last_y = -1;
50 /* to set/get/query special features/parameters */
51 static int
52 control(sh_video_t* sh, int cmd, void *arg, ...)
54 switch (cmd)
56 case VDCTRL_QUERY_FORMAT:
57 if (*((unsigned int *) arg) == outfmt) {
58 return CONTROL_TRUE;
60 return CONTROL_FALSE;
62 return CONTROL_UNKNOWN;
66 /* init driver */
67 static int
68 init(sh_video_t *sh)
70 sh->context = (SGIInfo *) calloc(1, sizeof(SGIInfo));
71 last_x = -1;
73 return 1;
77 /* uninit driver */
78 static void
79 uninit(sh_video_t *sh)
81 SGIInfo *info = sh->context;
82 free(info);
86 /* expand an rle row into a channel */
87 static void
88 expandrow(unsigned char *optr, unsigned char *iptr, int chan_offset)
90 unsigned char pixel, count;
91 optr += chan_offset;
93 while (1) {
94 pixel = *iptr++;
96 if (!(count = (pixel & 0x7f))) {
97 return;
99 if(pixel & 0x80) {
100 while (count--) {
101 *optr = *iptr;
102 optr += OUT_PIXEL_STRIDE;
103 iptr++;
105 } else {
106 pixel = *iptr++;
108 while (count--) {
109 *optr = pixel;
110 optr += OUT_PIXEL_STRIDE;
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)
123 unsigned char pixel, count;
125 while (1) {
126 pixel = *iptr++;
128 if (!(count = (pixel & 0x7f))) {
129 return;
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++;
139 } else {
140 pixel = *iptr++;
142 while (count--) {
143 optr[0] = pixel;
144 optr[1] = pixel;
145 optr[2] = pixel;
146 optr += OUT_PIXEL_STRIDE;
153 /* decode a run length encoded sgi image */
154 static void
155 decode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
157 unsigned char *rle_data, *dest_row;
158 unsigned long *starttab;
159 int y, z, xsize, ysize, zsize, chan_offset;
160 long start_offset;
162 xsize = info->xsize;
163 ysize = info->ysize;
164 zsize = info->zsize;
166 /* rle offset table is right after the header */
167 starttab = (long*)(data + SGI_HEADER_LEN);
169 for (z = 0; z < zsize; z++) {
171 /* set chan_offset so RGB ends up BGR */
172 chan_offset = (zsize - 1) - z;
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);
179 /* set start of next run (offsets are from start of header) */
180 start_offset = be2me_32(*(unsigned long*) &starttab[y + z * ysize]);
182 rle_data = &data[start_offset];
184 if(info->zsize == SGI_GRAYSCALE_IMAGE) {
185 expandrow_gs(dest_row, rle_data);
186 } else {
187 expandrow(dest_row, rle_data, chan_offset);
194 /* decode an sgi image */
195 static void
196 decode_uncompressed_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
198 unsigned char *src_row, *dest_row;
199 int x, y, z, xsize, ysize, zsize, chan_offset;
201 xsize = info->xsize;
202 ysize = info->ysize;
203 zsize = info->zsize;
205 /* skip header */
206 data += SGI_HEADER_LEN;
208 for (z = 0; z < zsize; z++) {
210 /* set row ptr to start of current plane */
211 src_row = data + (xsize * ysize * z);
213 /* set chan_offset for RGB -> BGR */
214 chan_offset = (zsize - 1) - z;
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++) {
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];
232 dest_row += OUT_PIXEL_STRIDE;
235 /* move to next row of the current source plane */
236 src_row += xsize;
242 /* read sgi header fields */
243 static void
244 read_sgi_header(unsigned char *buf, SGIInfo *info)
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]);
257 /* decode a frame */
258 static
259 mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags)
261 SGIInfo *info = sh->context;
262 unsigned char *data = raw;
263 mp_image_t *mpi;
265 if (len <= 0) {
266 return NULL; /* skip frame */
269 read_sgi_header(data, info);
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;
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;
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;
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;
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;
302 /* (re)init libvo if image size is changed */
303 if (last_x != info->xsize || last_y != info->ysize)
305 last_x = info->xsize;
306 last_y = info->ysize;
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;
314 if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
315 info->xsize, info->ysize))) {
316 return NULL;
319 if (info->rle) {
320 decode_rle_sgi(info, data, mpi);
321 } else {
322 decode_uncompressed_sgi(info, data, mpi);
325 return mpi;