2 * author: Todd Kirby <slapcat@pacbell.net>
10 #include "libavutil/common.h"
12 #include "vd_internal.h"
14 #define SGI_HEADER_LEN 512
17 #define SGI_GRAYSCALE_IMAGE 1
18 #define SGI_RGB_IMAGE 3
19 #define SGI_RGBA_IMAGE 4
21 #define OUT_PIXEL_STRIDE 3 /* RGB */
24 static vd_info_t info
=
38 char bytes_per_channel
;
39 unsigned short dimension
;
45 static unsigned int outfmt
= IMGFMT_BGR24
;
47 static unsigned short last_x
= -1;
48 static unsigned short last_y
= -1;
51 /* to set/get/query special features/parameters */
53 control(sh_video_t
* sh
, int cmd
, void *arg
, ...)
57 case VDCTRL_QUERY_FORMAT
:
58 if (*((unsigned int *) arg
) == outfmt
) {
63 return CONTROL_UNKNOWN
;
71 sh
->context
= (SGIInfo
*) calloc(1, sizeof(SGIInfo
));
80 uninit(sh_video_t
*sh
)
82 SGIInfo
*info
= sh
->context
;
87 /* expand an rle row into a channel */
89 expandrow(unsigned char *optr
, unsigned char *iptr
, int chan_offset
)
91 unsigned char pixel
, count
;
97 if (!(count
= (pixel
& 0x7f))) {
103 optr
+= OUT_PIXEL_STRIDE
;
111 optr
+= OUT_PIXEL_STRIDE
;
118 /* expand an rle row into all 3 channels.
119 a separate function for grayscale so we don't slow down the
120 more common case rgb function with a bunch of ifs. */
122 expandrow_gs(unsigned char *optr
, unsigned char *iptr
)
124 unsigned char pixel
, count
;
129 if (!(count
= (pixel
& 0x7f))) {
137 optr
+= OUT_PIXEL_STRIDE
;
147 optr
+= OUT_PIXEL_STRIDE
;
154 /* decode a run length encoded sgi image */
156 decode_rle_sgi(SGIInfo
*info
, unsigned char *data
, mp_image_t
*mpi
)
158 unsigned char *rle_data
, *dest_row
;
160 int y
, z
, xsize
, ysize
, zsize
, chan_offset
;
167 /* rle offset table is right after the header */
168 starttab
= (uint32_t*)(data
+ SGI_HEADER_LEN
);
170 for (z
= 0; z
< zsize
; z
++) {
172 /* set chan_offset so RGB ends up BGR */
173 chan_offset
= (zsize
- 1) - z
;
175 /* The origin for SGI images is the lower-left corner
176 so read scan lines from bottom to top */
177 for (y
= ysize
- 1; y
>= 0; y
--) {
178 dest_row
= mpi
->planes
[0] + mpi
->stride
[0] * (ysize
- 1 - y
);
180 /* set start of next run (offsets are from start of header) */
181 start_offset
= be2me_32(*(uint32_t*) &starttab
[y
+ z
* ysize
]);
183 rle_data
= &data
[start_offset
];
185 if(info
->zsize
== SGI_GRAYSCALE_IMAGE
) {
186 expandrow_gs(dest_row
, rle_data
);
188 expandrow(dest_row
, rle_data
, chan_offset
);
195 /* decode an sgi image */
197 decode_uncompressed_sgi(SGIInfo
*info
, unsigned char *data
, mp_image_t
*mpi
)
199 unsigned char *src_row
, *dest_row
;
200 int x
, y
, z
, xsize
, ysize
, zsize
, chan_offset
;
207 data
+= SGI_HEADER_LEN
;
209 for (z
= 0; z
< zsize
; z
++) {
211 /* set row ptr to start of current plane */
212 src_row
= data
+ (xsize
* ysize
* z
);
214 /* set chan_offset for RGB -> BGR */
215 chan_offset
= (zsize
- 1) - z
;
217 /* the origin for SGI images is the lower-left corner
218 so read scan lines from bottom to top. */
219 for (y
= ysize
- 1; y
>= 0; y
--) {
220 dest_row
= mpi
->planes
[0] + mpi
->stride
[0] * y
;
221 for (x
= 0; x
< xsize
; x
++) {
223 /* we only do 24 bit output so promote 8 bit pixels to 24 */
224 if (zsize
== SGI_GRAYSCALE_IMAGE
) {
225 /* write greyscale value into all channels */
226 dest_row
[0] = src_row
[x
];
227 dest_row
[1] = src_row
[x
];
228 dest_row
[2] = src_row
[x
];
230 dest_row
[chan_offset
] = src_row
[x
];
233 dest_row
+= OUT_PIXEL_STRIDE
;
236 /* move to next row of the current source plane */
243 /* read sgi header fields */
245 read_sgi_header(unsigned char *buf
, SGIInfo
*info
)
247 /* sgi data is always stored in big endian byte order */
248 info
->magic
= be2me_16(*(unsigned short *) &buf
[0]);
250 info
->bytes_per_channel
= buf
[3];
251 info
->dimension
= be2me_16(*(unsigned short *) &buf
[4]);
252 info
->xsize
= be2me_16(*(unsigned short *) &buf
[6]);
253 info
->ysize
= be2me_16(*(unsigned short *) &buf
[8]);
254 info
->zsize
= be2me_16(*(unsigned short *) &buf
[10]);
260 mp_image_t
*decode(sh_video_t
*sh
, void *raw
, int len
, int flags
)
262 SGIInfo
*info
= sh
->context
;
263 unsigned char *data
= raw
;
267 return NULL
; /* skip frame */
270 read_sgi_header(data
, info
);
272 /* make sure this is an SGI image file */
273 if (info
->magic
!= SGI_MAGIC
) {
274 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Bad magic number in image.\n");
278 /* check image depth */
279 if (info
->bytes_per_channel
!= 1) {
280 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
,
281 "Unsupported bytes per channel value %i.\n", info
->bytes_per_channel
);
285 /* check image dimension */
286 if (info
->dimension
!= 2 && info
->dimension
!= 3) {
287 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Unsupported image dimension %i.\n",
292 /* change rgba images to rgb so alpha channel will be ignored */
293 if (info
->zsize
== SGI_RGBA_IMAGE
) {
294 info
->zsize
= SGI_RGB_IMAGE
;
297 /* check image depth */
298 if (info
->zsize
!= SGI_RGB_IMAGE
&& info
->zsize
!= SGI_GRAYSCALE_IMAGE
) {
299 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Unsupported image depth.\n");
303 /* (re)init libvo if image size is changed */
304 if (last_x
!= info
->xsize
|| last_y
!= info
->ysize
)
306 last_x
= info
->xsize
;
307 last_y
= info
->ysize
;
309 if (!mpcodecs_config_vo(sh
, info
->xsize
, info
->ysize
, outfmt
)) {
310 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Config vo failed:\n");
315 if (!(mpi
= mpcodecs_get_image(sh
, MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
316 info
->xsize
, info
->ysize
))) {
321 decode_rle_sgi(info
, data
, mpi
);
323 decode_uncompressed_sgi(info
, data
, mpi
);