vd_sgi.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 329 行

C
329
字号
/* * author: Todd Kirby <slapcat@pacbell.net> */#include <uclib.h>#include <uclib.h>#include "config.h"#include "mp_msg.h"#include "libavutil/common.h"#include "mpbswap.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 intcontrol(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 intinit(sh_video_t *sh){  sh->context = (SGIInfo *) calloc(1, sizeof(SGIInfo));  last_x = -1;  return 1;}/* uninit driver */static voiduninit(sh_video_t *sh){  SGIInfo	*info = sh->context;  free(info);}/* expand an rle row into a channel */static voidexpandrow(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 voidexpandrow_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 voiddecode_rle_sgi(SGIInfo *info, unsigned char *data, mp_image_t *mpi){  unsigned char *rle_data, *dest_row;  uint32_t *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 = (uint32_t*)(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(*(uint32_t*) &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 voiddecode_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 voidread_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 */staticmp_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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?