2 * author: Todd Kirby <slapcat@pacbell.net>
11 #include "vd_internal.h"
13 #define SGI_HEADER_LEN 512
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
=
37 char bytes_per_channel
;
38 unsigned short dimension
;
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 */
52 control(sh_video_t
* sh
, int cmd
, void *arg
, ...)
56 case VDCTRL_QUERY_FORMAT
:
57 if (*((unsigned int *) arg
) == outfmt
) {
62 return CONTROL_UNKNOWN
;
70 sh
->context
= (SGIInfo
*) calloc(1, sizeof(SGIInfo
));
79 uninit(sh_video_t
*sh
)
81 SGIInfo
*info
= sh
->context
;
86 /* expand an rle row into a channel */
88 expandrow(unsigned char *optr
, unsigned char *iptr
, int chan_offset
)
90 unsigned char pixel
, count
;
96 if (!(count
= (pixel
& 0x7f))) {
102 optr
+= OUT_PIXEL_STRIDE
;
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. */
121 expandrow_gs(unsigned char *optr
, unsigned char *iptr
)
123 unsigned char pixel
, count
;
128 if (!(count
= (pixel
& 0x7f))) {
136 optr
+= OUT_PIXEL_STRIDE
;
146 optr
+= OUT_PIXEL_STRIDE
;
153 /* decode a run length encoded sgi image */
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
;
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
);
187 expandrow(dest_row
, rle_data
, chan_offset
);
194 /* decode an sgi image */
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
;
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
];
229 dest_row
[chan_offset
] = src_row
[x
];
232 dest_row
+= OUT_PIXEL_STRIDE
;
235 /* move to next row of the current source plane */
242 /* read sgi header fields */
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]);
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]);
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
;
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");
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
);
284 /* check image dimension */
285 if (info
->dimension
!= 2 && info
->dimension
!= 3) {
286 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Unsupported image dimension %i.\n",
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");
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");
314 if (!(mpi
= mpcodecs_get_image(sh
, MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
315 info
->xsize
, info
->ysize
))) {
320 decode_rle_sgi(info
, data
, mpi
);
322 decode_uncompressed_sgi(info
, data
, mpi
);