summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/codecs.conf9
-rw-r--r--libmpcodecs/Makefile2
-rw-r--r--libmpcodecs/vd.c2
-rw-r--r--libmpcodecs/vd_sgi.c327
-rw-r--r--libmpdemux/demux_mf.c4
5 files changed, 342 insertions, 2 deletions
diff --git a/etc/codecs.conf b/etc/codecs.conf
index 8b802c5398..657b2b6c0b 100644
--- a/etc/codecs.conf
+++ b/etc/codecs.conf
@@ -68,6 +68,15 @@ videocodec mtga
driver mtga
out BGR32,BGR24
+videocodec sgi
+ info "SGI images decoder"
+ status working
+ comment "SGI1 is an internal MPlayer FOURCC"
+ fourcc SGI1
+ driver sgi
+ out BGR24
+
+
videocodec fli
info "Autodesk FLI/FLC Animation"
status working
diff --git a/libmpcodecs/Makefile b/libmpcodecs/Makefile
index ed2c17ab43..cd52c1d116 100644
--- a/libmpcodecs/Makefile
+++ b/libmpcodecs/Makefile
@@ -10,7 +10,7 @@ AUDIO_SRCS_OPT=ad_acm.c ad_dshow.c ad_dmo.c ad_qtaudio.c ad_ffmpeg.c ad_faad.c a
AUDIO_SRCS=dec_audio.c ad.c $(AUDIO_SRCS_LIB) $(AUDIO_SRCS_NAT) $(AUDIO_SRCS_OPT)
VIDEO_SRCS_LIB=vd_libmpeg2.c vd_nuv.c vd_lzo.c
-VIDEO_SRCS_NAT=vd_null.c vd_cinepak.c vd_qtrpza.c vd_raw.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_msrle.c vd_huffyuv.c vd_mpegpes.c vd_svq1.c vd_lcl.c vd_mtga.c
+VIDEO_SRCS_NAT=vd_null.c vd_cinepak.c vd_qtrpza.c vd_raw.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_msrle.c vd_huffyuv.c vd_mpegpes.c vd_svq1.c vd_lcl.c vd_mtga.c vd_sgi.c
VIDEO_SRCS_OPT=vd_realvid.c vd_ffmpeg.c vd_dshow.c vd_dmo.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_xanim.c vd_xvid.c vd_libdv.c vd_qtvideo.c
VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT)
diff --git a/libmpcodecs/vd.c b/libmpcodecs/vd.c
index a97ae0b33c..8a14f4ec8b 100644
--- a/libmpcodecs/vd.c
+++ b/libmpcodecs/vd.c
@@ -48,6 +48,7 @@ extern vd_functions_t mpcodecs_vd_nuv;
extern vd_functions_t mpcodecs_vd_mpng;
extern vd_functions_t mpcodecs_vd_ijpg;
extern vd_functions_t mpcodecs_vd_mtga;
+extern vd_functions_t mpcodecs_vd_sgi;
extern vd_functions_t mpcodecs_vd_libmpeg2;
extern vd_functions_t mpcodecs_vd_huffyuv;
extern vd_functions_t mpcodecs_vd_mpegpes;
@@ -100,6 +101,7 @@ vd_functions_t* mpcodecs_vd_drivers[] = {
&mpcodecs_vd_ijpg,
#endif
&mpcodecs_vd_mtga,
+ &mpcodecs_vd_sgi,
#ifdef USE_LIBMPEG2
&mpcodecs_vd_libmpeg2,
#endif
diff --git a/libmpcodecs/vd_sgi.c b/libmpcodecs/vd_sgi.c
new file mode 100644
index 0000000000..1cc9ebb40c
--- /dev/null
+++ b/libmpcodecs/vd_sgi.c
@@ -0,0 +1,327 @@
+/*
+ * author: Todd Kirby <slapcat@pacbell.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "bswap.h"
+#include "vd_internal.h"
+
+#define SGI_HEADER_LEN 512
+#define SGI_MAGIC 474
+
+#define SGI_GRAYSCALE_IMAGE 1
+#define SGI_RGB_IMAGE 3
+#define SGI_RGBA_IMAGE 4
+
+#define OUT_PIXEL_STRIDE 3 /* RGB */
+
+
+static vd_info_t info =
+{
+ "SGI Image decoder",
+ "sgi",
+ "Todd Kirby",
+ "Todd Kirby",
+ ""
+};
+
+LIBVD_EXTERN(sgi)
+
+typedef struct {
+ short magic;
+ char rle;
+ char bytes_per_channel;
+ unsigned short dimension;
+ unsigned short xsize;
+ unsigned short ysize;
+ unsigned short zsize;
+} SGIInfo;
+
+static unsigned int outfmt = IMGFMT_BGR24;
+
+static unsigned short last_x = -1;
+static unsigned short last_y = -1;
+
+
+/* to set/get/query special features/parameters */
+static int
+control(sh_video_t* sh, int cmd, void *arg, ...)
+{
+ switch (cmd)
+ {
+ case VDCTRL_QUERY_FORMAT:
+ if (*((unsigned int *) arg) == outfmt) {
+ return CONTROL_TRUE;
+ }
+ return CONTROL_FALSE;
+ }
+ return CONTROL_UNKNOWN;
+}
+
+
+/* init driver */
+static int
+init(sh_video_t *sh)
+{
+ sh->context = (SGIInfo *) calloc(1, sizeof(SGIInfo));
+ last_x = -1;
+
+ return 1;
+}
+
+
+/* uninit driver */
+static void
+uninit(sh_video_t *sh)
+{
+ SGIInfo *info = sh->context;
+ free(info);
+}
+
+
+/* expand an rle row into a channel */
+static void
+expandrow(unsigned char *optr, unsigned char *iptr, int chan_offset)
+{
+ unsigned char pixel, count;
+ optr += chan_offset;
+
+ while (1) {
+ pixel = *iptr++;
+
+ if (!(count = (pixel & 0x7f))) {
+ return;
+ }
+ if(pixel & 0x80) {
+ while (count--) {
+ *optr = *iptr;
+ optr += OUT_PIXEL_STRIDE;
+ iptr++;
+ }
+ } else {
+ pixel = *iptr++;
+
+ while (count--) {
+ *optr = pixel;
+ optr += OUT_PIXEL_STRIDE;
+ }
+ }
+ }
+}
+
+
+/* expand an rle row into all 3 channels.
+ a separate function for grayscale so we don't slow down the
+ more common case rgb function with a bunch of ifs. */
+static void
+expandrow_gs(unsigned char *optr, unsigned char *iptr)
+{
+ unsigned char pixel, count;
+
+ while (1) {
+ pixel = *iptr++;
+
+ if (!(count = (pixel & 0x7f))) {
+ return;
+ }
+ if(pixel & 0x80) {
+ while (count--) {
+ optr[0] = *iptr;
+ optr[1] = *iptr;
+ optr[2] = *iptr;
+ optr += OUT_PIXEL_STRIDE;
+ iptr++;
+ }
+ } else {
+ pixel = *iptr++;
+
+ while (count--) {
+ optr[0] = pixel;
+ optr[1] = pixel;
+ optr[2] = pixel;
+ optr += OUT_PIXEL_STRIDE;
+ }
+ }
+ }
+}
+
+
+/* decode a run length encoded sgi image */
+static void
+decode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
+{
+ unsigned char *rle_data, *dest_row;
+ unsigned long *starttab;
+ int y, z, xsize, ysize, zsize, chan_offset;
+ long start_offset;
+
+ xsize = info->xsize;
+ ysize = info->ysize;
+ zsize = info->zsize;
+
+ /* rle offset table is right after the header */
+ starttab = (long*)(data + SGI_HEADER_LEN);
+
+ for (z = 0; z < zsize; z++) {
+
+ /* set chan_offset so RGB ends up BGR */
+ chan_offset = (zsize - 1) - z;
+
+ /* The origin for SGI images is the lower-left corner
+ so read scan lines from bottom to top */
+ for (y = ysize - 1; y >= 0; y--) {
+ dest_row = mpi->planes[0] + mpi->stride[0] * (ysize - 1 - y);
+
+ /* set start of next run (offsets are from start of header) */
+ start_offset = be2me_32(*(unsigned long*) &starttab[y + z * ysize]);
+
+ rle_data = &data[start_offset];
+
+ if(info->zsize == SGI_GRAYSCALE_IMAGE) {
+ expandrow_gs(dest_row, rle_data);
+ } else {
+ expandrow(dest_row, rle_data, chan_offset);
+ }
+ }
+ }
+}
+
+
+/* decode an sgi image */
+static void
+decode_uncompressed_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi)
+{
+ unsigned char *src_row, *dest_row;
+ int x, y, z, xsize, ysize, zsize, chan_offset;
+
+ xsize = info->xsize;
+ ysize = info->ysize;
+ zsize = info->zsize;
+
+ /* skip header */
+ data += SGI_HEADER_LEN;
+
+ for (z = 0; z < zsize; z++) {
+
+ /* set row ptr to start of current plane */
+ src_row = data + (xsize * ysize * z);
+
+ /* set chan_offset for RGB -> BGR */
+ chan_offset = (zsize - 1) - z;
+
+ /* the origin for SGI images is the lower-left corner
+ so read scan lines from bottom to top. */
+ for (y = ysize - 1; y >= 0; y--) {
+ dest_row = mpi->planes[0] + mpi->stride[0] * y;
+ for (x = 0; x < xsize; x++) {
+
+ /* we only do 24 bit output so promote 8 bit pixels to 24 */
+ if (zsize == SGI_GRAYSCALE_IMAGE) {
+ /* write greyscale value into all channels */
+ dest_row[0] = src_row[x];
+ dest_row[1] = src_row[x];
+ dest_row[2] = src_row[x];
+ } else {
+ dest_row[chan_offset] = src_row[x];
+ }
+
+ dest_row += OUT_PIXEL_STRIDE;
+ }
+
+ /* move to next row of the current source plane */
+ src_row += xsize;
+ }
+ }
+}
+
+
+/* read sgi header fields */
+static void
+read_sgi_header(unsigned char *buf, SGIInfo *info)
+{
+ /* sgi data is always stored in big endian byte order */
+ info->magic = be2me_16(*(unsigned short *) &buf[0]);
+ info->rle = buf[2];
+ info->bytes_per_channel = buf[3];
+ info->dimension = be2me_16(*(unsigned short *) &buf[4]);
+ info->xsize = be2me_16(*(unsigned short *) &buf[6]);
+ info->ysize = be2me_16(*(unsigned short *) &buf[8]);
+ info->zsize = be2me_16(*(unsigned short *) &buf[10]);
+}
+
+
+/* decode a frame */
+static
+mp_image_t *decode(sh_video_t *sh, void *raw, int len, int flags)
+{
+ SGIInfo *info = sh->context;
+ unsigned char *data = raw;
+ mp_image_t *mpi;
+
+ if (len <= 0) {
+ return NULL; /* skip frame */
+ }
+
+ read_sgi_header(data, info);
+
+ /* make sure this is an SGI image file */
+ if (info->magic != SGI_MAGIC) {
+ mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Bad magic number in image.\n");
+ return NULL;
+ }
+
+ /* check image depth */
+ if (info->bytes_per_channel != 1) {
+ mp_msg(MSGT_DECVIDEO, MSGL_INFO,
+ "Unsupported bytes per channel value %i.\n", info->bytes_per_channel);
+ return NULL;
+ }
+
+ /* check image dimension */
+ if (info->dimension != 2 && info->dimension != 3) {
+ mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image dimension %i.\n",
+ info->dimension);
+ return NULL;
+ }
+
+ /* change rgba images to rgb so alpha channel will be ignored */
+ if (info->zsize == SGI_RGBA_IMAGE) {
+ info->zsize = SGI_RGB_IMAGE;
+ }
+
+ /* check image depth */
+ if (info->zsize != SGI_RGB_IMAGE && info->zsize != SGI_GRAYSCALE_IMAGE) {
+ mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported image depth.\n");
+ return NULL;
+ }
+
+ /* (re)init libvo if image size is changed */
+ if (last_x != info->xsize || last_y != info->ysize)
+ {
+ last_x = info->xsize;
+ last_y = info->ysize;
+
+ if (!mpcodecs_config_vo(sh, info->xsize, info->ysize, outfmt)) {
+ mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Config vo failed:\n");
+ return NULL;
+ }
+ }
+
+ if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+ info->xsize, info->ysize))) {
+ return NULL;
+ }
+
+ if (info->rle) {
+ decode_rle_sgi(info, data, mpi);
+ } else {
+ decode_uncompressed_sgi(info, data, mpi);
+ }
+
+ return mpi;
+}
+
diff --git a/libmpdemux/demux_mf.c b/libmpdemux/demux_mf.c
index 159ec2a2f8..2f0acb5355 100644
--- a/libmpdemux/demux_mf.c
+++ b/libmpdemux/demux_mf.c
@@ -98,7 +98,9 @@ demuxer_t* demux_open_mf(demuxer_t* demuxer){
if ( !strcasecmp( mf_type,"png" )) sh_video->format = mmioFOURCC('M', 'P', 'N', 'G' );
else
if ( !strcasecmp( mf_type,"tga" )) sh_video->format = mmioFOURCC('M', 'T', 'G', 'A' );
- else { mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] unknow input file type.\n" ); free( mf ); return NULL; }
+ else
+ if (!strcasecmp( mf_type,"sgi" )) sh_video->format = mmioFOURCC('S', 'G', 'I', '1');
+ else { mp_msg(MSGT_DEMUX, MSGL_INFO, "[demux_mf] unknown input file type.\n" ); free( mf ); return NULL; }
sh_video->disp_w = mf_w;
sh_video->disp_h = mf_h;