2 * Copyright (c) 2003 Todd Kirby <slapcat@pacbell.net>
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "ffmpeg_files/intreadwrite.h"
28 #include "vd_internal.h"
30 #define SGI_HEADER_LEN 512
33 #define SGI_GRAYSCALE_IMAGE 1
34 #define SGI_RGB_IMAGE 3
35 #define SGI_RGBA_IMAGE 4
37 #define OUT_PIXEL_STRIDE 3 /* RGB */
40 static const vd_info_t info
=
54 char bytes_per_channel
;
55 unsigned short dimension
;
61 static unsigned int outfmt
= IMGFMT_BGR24
;
63 static unsigned short last_x
= -1;
64 static unsigned short last_y
= -1;
67 /* to set/get/query special features/parameters */
69 control(sh_video_t
* sh
, int cmd
, void *arg
, ...)
73 case VDCTRL_QUERY_FORMAT
:
74 if (*((unsigned int *) arg
) == outfmt
) {
79 return CONTROL_UNKNOWN
;
87 sh
->context
= calloc(1, sizeof(SGIInfo
));
96 uninit(sh_video_t
*sh
)
98 SGIInfo
*info
= sh
->context
;
103 /* expand an rle row into a channel */
105 expandrow(unsigned char *optr
, unsigned char *iptr
, int chan_offset
)
107 unsigned char pixel
, count
;
113 if (!(count
= (pixel
& 0x7f))) {
119 optr
+= OUT_PIXEL_STRIDE
;
127 optr
+= OUT_PIXEL_STRIDE
;
134 /* expand an rle row into all 3 channels.
135 a separate function for grayscale so we don't slow down the
136 more common case rgb function with a bunch of ifs. */
138 expandrow_gs(unsigned char *optr
, unsigned char *iptr
)
140 unsigned char pixel
, count
;
145 if (!(count
= (pixel
& 0x7f))) {
153 optr
+= OUT_PIXEL_STRIDE
;
163 optr
+= OUT_PIXEL_STRIDE
;
170 /* decode a run length encoded sgi image */
172 decode_rle_sgi(SGIInfo
*info
, unsigned char *data
, mp_image_t
*mpi
)
174 unsigned char *rle_data
, *dest_row
;
176 int y
, z
, xsize
, ysize
, zsize
, chan_offset
;
183 /* rle offset table is right after the header */
184 starttab
= (uint32_t*)(data
+ SGI_HEADER_LEN
);
186 for (z
= 0; z
< zsize
; z
++) {
188 /* set chan_offset so RGB ends up BGR */
189 chan_offset
= (zsize
- 1) - z
;
191 /* The origin for SGI images is the lower-left corner
192 so read scan lines from bottom to top */
193 for (y
= ysize
- 1; y
>= 0; y
--) {
194 dest_row
= mpi
->planes
[0] + mpi
->stride
[0] * (ysize
- 1 - y
);
196 /* set start of next run (offsets are from start of header) */
197 start_offset
= AV_RB32(&starttab
[y
+ z
* ysize
]);
199 rle_data
= &data
[start_offset
];
201 if(info
->zsize
== SGI_GRAYSCALE_IMAGE
) {
202 expandrow_gs(dest_row
, rle_data
);
204 expandrow(dest_row
, rle_data
, chan_offset
);
211 /* decode an sgi image */
213 decode_uncompressed_sgi(SGIInfo
*info
, unsigned char *data
, mp_image_t
*mpi
)
215 unsigned char *src_row
, *dest_row
;
216 int x
, y
, z
, xsize
, ysize
, zsize
, chan_offset
;
223 data
+= SGI_HEADER_LEN
;
225 for (z
= 0; z
< zsize
; z
++) {
227 /* set row ptr to start of current plane */
228 src_row
= data
+ (xsize
* ysize
* z
);
230 /* set chan_offset for RGB -> BGR */
231 chan_offset
= (zsize
- 1) - z
;
233 /* the origin for SGI images is the lower-left corner
234 so read scan lines from bottom to top. */
235 for (y
= ysize
- 1; y
>= 0; y
--) {
236 dest_row
= mpi
->planes
[0] + mpi
->stride
[0] * y
;
237 for (x
= 0; x
< xsize
; x
++) {
239 /* we only do 24 bit output so promote 8 bit pixels to 24 */
240 if (zsize
== SGI_GRAYSCALE_IMAGE
) {
241 /* write greyscale value into all channels */
242 dest_row
[0] = src_row
[x
];
243 dest_row
[1] = src_row
[x
];
244 dest_row
[2] = src_row
[x
];
246 dest_row
[chan_offset
] = src_row
[x
];
249 dest_row
+= OUT_PIXEL_STRIDE
;
252 /* move to next row of the current source plane */
259 /* read sgi header fields */
261 read_sgi_header(unsigned char *buf
, SGIInfo
*info
)
263 /* sgi data is always stored in big endian byte order */
264 info
->magic
= AV_RB16(&buf
[0]);
266 info
->bytes_per_channel
= buf
[3];
267 info
->dimension
= AV_RB16(&buf
[4]);
268 info
->xsize
= AV_RB16(&buf
[6]);
269 info
->ysize
= AV_RB16(&buf
[8]);
270 info
->zsize
= AV_RB16(&buf
[10]);
276 mp_image_t
*decode(sh_video_t
*sh
, void *raw
, int len
, int flags
)
278 SGIInfo
*info
= sh
->context
;
279 unsigned char *data
= raw
;
283 return NULL
; /* skip frame */
286 read_sgi_header(data
, info
);
288 /* make sure this is an SGI image file */
289 if (info
->magic
!= SGI_MAGIC
) {
290 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Bad magic number in image.\n");
294 /* check image depth */
295 if (info
->bytes_per_channel
!= 1) {
296 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
,
297 "Unsupported bytes per channel value %i.\n", info
->bytes_per_channel
);
301 /* check image dimension */
302 if (info
->dimension
!= 2 && info
->dimension
!= 3) {
303 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Unsupported image dimension %i.\n",
308 /* change rgba images to rgb so alpha channel will be ignored */
309 if (info
->zsize
== SGI_RGBA_IMAGE
) {
310 info
->zsize
= SGI_RGB_IMAGE
;
313 /* check image depth */
314 if (info
->zsize
!= SGI_RGB_IMAGE
&& info
->zsize
!= SGI_GRAYSCALE_IMAGE
) {
315 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Unsupported image depth.\n");
319 /* (re)init libvo if image size is changed */
320 if (last_x
!= info
->xsize
|| last_y
!= info
->ysize
)
322 last_x
= info
->xsize
;
323 last_y
= info
->ysize
;
325 if (!mpcodecs_config_vo(sh
, info
->xsize
, info
->ysize
, outfmt
)) {
326 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
, "Config vo failed:\n");
331 if (!(mpi
= mpcodecs_get_image(sh
, MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
332 info
->xsize
, info
->ysize
))) {
337 decode_rle_sgi(info
, data
, mpi
);
339 decode_uncompressed_sgi(info
, data
, mpi
);