~ubuntu-dev/mplayer/upstream-ubuntu

1 by Reinhard Tartler
imported mplayer_0.99+1.0pre7try2+cvs20060117
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"
4 by Mario Limonciello
Update to 1.0rc2
10
#include "libavutil/common.h"
11
#include "mpbswap.h"
1 by Reinhard Tartler
imported mplayer_0.99+1.0pre7try2+cvs20060117
12
#include "vd_internal.h"
13
14
#define SGI_HEADER_LEN 512
15
#define SGI_MAGIC 474
16
17
#define SGI_GRAYSCALE_IMAGE 1
18
#define SGI_RGB_IMAGE 3
19
#define SGI_RGBA_IMAGE 4
20
21
#define OUT_PIXEL_STRIDE 3 /* RGB */
22
23
24
static vd_info_t info =
25
{
26
  "SGI Image decoder",
27
  "sgi",
28
  "Todd Kirby",
29
  "Todd Kirby",
30
  ""
31
};
32
33
LIBVD_EXTERN(sgi)
34
35
typedef struct {
36
  short magic;
37
  char rle;
38
  char bytes_per_channel;
39
  unsigned short dimension;
40
  unsigned short xsize;
41
  unsigned short ysize;
42
  unsigned short zsize;
43
} SGIInfo;
44
45
static unsigned int outfmt = IMGFMT_BGR24;
46
47
static unsigned short last_x = -1;
48
static unsigned short last_y = -1;
49
50
51
/* to set/get/query special features/parameters */
52
static int
53
control(sh_video_t* sh, int cmd, void *arg, ...)
54
{ 
55
  switch (cmd)
56
  {
57
    case VDCTRL_QUERY_FORMAT:
58
      if (*((unsigned int *) arg) == outfmt) {
59
        return CONTROL_TRUE;
60
      }
61
      return CONTROL_FALSE;
62
  }
63
  return CONTROL_UNKNOWN;
64
}
65
66
67
/* init driver */
68
static int
69
init(sh_video_t *sh)
70
{
71
  sh->context = (SGIInfo *) calloc(1, sizeof(SGIInfo));
72
  last_x = -1;
73
74
  return 1;
75
}
76
77
78
/* uninit driver */
79
static void
80
uninit(sh_video_t *sh)
81
{
82
  SGIInfo	*info = sh->context;
83
  free(info);
84
}
85
86
87
/* expand an rle row into a channel */
88
static void
89
expandrow(unsigned char *optr, unsigned char *iptr, int chan_offset)
90
{
91
  unsigned char pixel, count;
92
  optr += chan_offset;
93
  
94
  while (1) {
95
    pixel = *iptr++;
96
    
97
    if (!(count = (pixel & 0x7f))) {
98
      return;
99
    }
100
    if(pixel & 0x80) {
101
      while (count--) {
102
        *optr = *iptr;
103
        optr += OUT_PIXEL_STRIDE;
104
        iptr++;
105
      }
106
    } else {
107
      pixel = *iptr++;
108
      
109
      while (count--) {
110
        *optr = pixel;
111
        optr += OUT_PIXEL_STRIDE;
112
      }
113
    }
114
  }
115
}
116
117
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. */
121
static void
122
expandrow_gs(unsigned char *optr, unsigned char *iptr)
123
{
124
  unsigned char pixel, count;
125
  
126
  while (1) {
127
    pixel = *iptr++;
128
    
129
    if (!(count = (pixel & 0x7f))) {
130
      return;
131
    }
132
    if(pixel & 0x80) {
133
      while (count--) {
134
        optr[0] = *iptr;
135
        optr[1] = *iptr;
136
        optr[2] = *iptr;
137
        optr += OUT_PIXEL_STRIDE;
138
        iptr++;
139
      }
140
    } else {
141
      pixel = *iptr++;
142
      
143
      while (count--) {
144
        optr[0] = pixel;
145
        optr[1] = pixel;
146
        optr[2] = pixel;
147
        optr += OUT_PIXEL_STRIDE;
148
      }
149
    }
150
  }
151
}
152
153
154
/* decode a run length encoded sgi image */
155
static void
156
decode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
157
{
158
  unsigned char *rle_data, *dest_row;
3 by William Grant
Update to 1.0rc1.
159
  uint32_t *starttab;
1 by Reinhard Tartler
imported mplayer_0.99+1.0pre7try2+cvs20060117
160
  int y, z, xsize, ysize, zsize, chan_offset;
161
  long start_offset;
162
  
163
  xsize = info->xsize;
164
  ysize = info->ysize;
165
  zsize = info->zsize;
166
167
  /* rle offset table is right after the header */
3 by William Grant
Update to 1.0rc1.
168
  starttab = (uint32_t*)(data + SGI_HEADER_LEN); 
1 by Reinhard Tartler
imported mplayer_0.99+1.0pre7try2+cvs20060117
169
  
170
   for (z = 0; z < zsize; z++) {
171
172
     /* set chan_offset so RGB ends up BGR */
173
     chan_offset = (zsize - 1) - z;
174
     
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);
179
    
180
      /* set start of next run (offsets are from start of header) */
3 by William Grant
Update to 1.0rc1.
181
      start_offset = be2me_32(*(uint32_t*) &starttab[y + z * ysize]);
1 by Reinhard Tartler
imported mplayer_0.99+1.0pre7try2+cvs20060117
182
      
183
      rle_data = &data[start_offset];
184
    
185
      if(info->zsize == SGI_GRAYSCALE_IMAGE) {
186
        expandrow_gs(dest_row, rle_data);
187
      } else {
188
        expandrow(dest_row, rle_data, chan_offset);
189
      }
190
    }
191
  }
192
}
193
194
  
195
/* decode an sgi image */
196
static void
197
decode_uncompressed_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
198
{
199
  unsigned char *src_row, *dest_row;
200
  int x, y, z, xsize, ysize, zsize, chan_offset;
201
  
202
  xsize = info->xsize;
203
  ysize = info->ysize;
204
  zsize = info->zsize;
205
  
206
  /* skip header */ 
207
  data += SGI_HEADER_LEN;
208
  
209
  for (z = 0; z < zsize; z++) {
210
211
    /* set row ptr to start of current plane */
212
    src_row = data + (xsize * ysize * z);
213
214
    /* set chan_offset for RGB -> BGR */
215
    chan_offset = (zsize - 1) - z;
216
    
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++) {
222
        
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];
229
        } else {
230
          dest_row[chan_offset] = src_row[x];
231
        }
232
        
233
        dest_row += OUT_PIXEL_STRIDE;
234
      }
235
236
      /* move to next row of the current source plane */
237
      src_row += xsize;
238
    }
239
  }
240
}
241
242
243
/* read sgi header fields */
244
static void
245
read_sgi_header(unsigned char *buf, SGIInfo *info)
246
{
247
  /* sgi data is always stored in big endian byte order */
248
  info->magic = be2me_16(*(unsigned short *) &buf[0]);     
249
  info->rle = buf[2];
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]);     
255
}
256
257
258
/* decode a frame */
259
static
260
mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags)
261
{
262
  SGIInfo *info = sh->context;
263
  unsigned char *data = raw;
264
  mp_image_t *mpi;
265
266
  if (len <= 0) {
267
    return NULL; /* skip frame */
268
  }
269
    
270
  read_sgi_header(data, info); 
271
  
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");
275
    return NULL;
276
  }
277
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);
282
    return NULL;
283
  }
284
285
  /* check image dimension */
286
  if (info->dimension != 2 && info->dimension != 3) {
287
    mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image dimension %i.\n", 
288
        info->dimension);
289
    return NULL;
290
  }
291
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;
295
  }
296
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");
300
    return NULL;
301
  }
302
  
303
  /* (re)init libvo if image size is changed */
304
  if (last_x != info->xsize || last_y != info->ysize)
305
  {
306
    last_x = info->xsize;
307
    last_y = info->ysize;
308
    
309
    if (!mpcodecs_config_vo(sh, info->xsize, info->ysize, outfmt)) {
310
      mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Config vo failed:\n");
311
      return NULL;
312
    }
313
  }
314
   
315
  if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, 
316
          info->xsize, info->ysize))) {
317
    return NULL;
318
  }
319
 
320
  if (info->rle) {
321
    decode_rle_sgi(info, data, mpi);
322
  } else {
323
    decode_uncompressed_sgi(info, data, mpi);
324
  }
325
  
326
  return mpi;
327
}
328