Commit 2d99eed1 authored by Xiaohui Sun's avatar Xiaohui Sun Committed by Diego Biurrun

SGI image decoder ported to the new image API.

patch by Xiaohui Sun, sunxiaohui dsp.ac cn

Originally committed as revision 8635 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 0d0677fb
......@@ -126,6 +126,8 @@ OBJS-$(CONFIG_RV10_DECODER) += rv10.o
OBJS-$(CONFIG_RV10_ENCODER) += rv10.o
OBJS-$(CONFIG_RV20_DECODER) += rv10.o
OBJS-$(CONFIG_RV20_ENCODER) += rv10.o
OBJS-$(CONFIG_SGI_DECODER) += sgidec.o
OBJS-$(CONFIG_SGI_ENCODER) += sgienc.o rle.o
OBJS-$(CONFIG_SHORTEN_DECODER) += shorten.o
OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o
OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o
......
......@@ -122,6 +122,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(RPZA, rpza);
REGISTER_ENCDEC (RV10, rv10);
REGISTER_ENCDEC (RV20, rv20);
REGISTER_ENCDEC (SGI, sgi);
REGISTER_DECODER(SMACKER, smacker);
REGISTER_DECODER(SMC, smc);
REGISTER_ENCDEC (SNOW, snow);
......
......@@ -159,6 +159,7 @@ enum CodecID {
CODEC_ID_DXA,
CODEC_ID_DNXHD,
CODEC_ID_THP,
CODEC_ID_SGI,
/* various pcm "codecs" */
CODEC_ID_PCM_S16LE= 0x10000,
......@@ -2220,6 +2221,7 @@ extern AVCodec png_encoder;
extern AVCodec ppm_encoder;
extern AVCodec rv10_encoder;
extern AVCodec rv20_encoder;
extern AVCodec sgi_encoder;
extern AVCodec snow_encoder;
extern AVCodec sonic_encoder;
extern AVCodec sonic_ls_encoder;
......@@ -2322,6 +2324,7 @@ extern AVCodec rv10_decoder;
extern AVCodec rv20_decoder;
extern AVCodec rv30_decoder;
extern AVCodec rv40_decoder;
extern AVCodec sgi_decoder;
extern AVCodec shorten_decoder;
extern AVCodec smackaud_decoder;
extern AVCodec smacker_decoder;
......
/*
* SGI image encoder
* Xiaohui Sun <tjnksxh@hotmail.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SGI_H
#define SGI_H
/**
* SGI image file signature
*/
#define SGI_MAGIC 474
#define SGI_HEADER_SIZE 512
#define SGI_GRAYSCALE 1
#define SGI_RGB 3
#define SGI_RGBA 4
#endif
/*
* SGI image decoder
* Todd Kirby <doubleshot@pacbell.net>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
#include "sgi.h"
typedef struct SgiState {
AVFrame picture;
unsigned int width;
unsigned int height;
unsigned int depth;
int linesize;
} SgiState;
/**
* Expand an RLE row into a channel.
* @param in_buf input buffer
* @param in_end end of input buffer
* @param out_buf Points to one line after the output buffer.
* @param out_end end of line in output buffer
* @param pixelstride pixel stride of input buffer
* @return size of output in bytes, -1 if buffer overflows
*/
static int expand_rle_row(uint8_t *in_buf, uint8_t* in_end,
unsigned char *out_buf, uint8_t* out_end, int pixelstride)
{
unsigned char pixel, count;
unsigned char *orig = out_buf;
while (1) {
if(in_buf + 1 > in_end) return -1;
pixel = bytestream_get_byte(&in_buf);
if (!(count = (pixel & 0x7f))) {
return (out_buf - orig) / pixelstride;
}
/* Check for buffer overflow. */
if(out_buf + pixelstride * count >= out_end) return -1;
if (pixel & 0x80) {
while (count--) {
*out_buf = bytestream_get_byte(&in_buf);
out_buf += pixelstride;
}
} else {
pixel = bytestream_get_byte(&in_buf);
while (count--) {
*out_buf = pixel;
out_buf += pixelstride;
}
}
}
}
/**
* Read a run length encoded SGI image.
* @param out_buf output buffer
* @param in_buf input buffer
* @param in_end end of input buffer
* @param s the current image state
* @return 0 if no error, else return error number.
*/
static int read_rle_sgi(unsigned char* out_buf, uint8_t *in_buf,
uint8_t *in_end, SgiState* s)
{
uint8_t *dest_row;
unsigned int len = s->height * s->depth * 4;
uint8_t *start_table = in_buf;
unsigned int y, z;
unsigned int start_offset;
/* size of RLE offset and length tables */
if(len * 2 > in_end - in_buf) {
return AVERROR_INVALIDDATA;
}
in_buf -= SGI_HEADER_SIZE;
for (z = 0; z < s->depth; z++) {
dest_row = out_buf;
for (y = 0; y < s->height; y++) {
dest_row -= s->linesize;
start_offset = bytestream_get_be32(&start_table);
if(start_offset > in_end - in_buf) {
return AVERROR_INVALIDDATA;
}
if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z,
dest_row + FFABS(s->linesize), s->depth) != s->width)
return AVERROR_INVALIDDATA;
}
}
return 0;
}
/**
* Read an uncompressed SGI image.
* @param out_buf output buffer
* @param out_end end ofoutput buffer
* @param in_buf input buffer
* @param in_end end of input buffer
* @param s the current image state
* @return 0 if read success, otherwise return -1.
*/
static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end,
uint8_t *in_buf, uint8_t *in_end, SgiState* s)
{
int x, y, z;
uint8_t *ptr;
unsigned int offset = s->height * s->width;
/* Test buffer size. */
if (offset * s->depth > in_end - in_buf) {
return -1;
}
for (y = s->height - 1; y >= 0; y--) {
out_end = out_buf + (y * s->linesize);
for (x = s->width; x > 0; x--) {
ptr = in_buf++;
for(z = 0; z < s->depth; z ++) {
bytestream_put_byte(&out_end, *ptr);
ptr += offset;
}
}
}
return 0;
}
static int decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *in_buf, int buf_size)
{
SgiState *s = avctx->priv_data;
AVFrame *picture = data;
AVFrame *p = &s->picture;
uint8_t *in_end = in_buf + buf_size;
unsigned int dimension, bytes_per_channel, rle;
int ret = 0;
uint8_t *out_buf, *out_end;
if (buf_size < SGI_HEADER_SIZE){
av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size);
return -1;
}
/* Test for SGI magic. */
if (bytestream_get_be16(&in_buf) != SGI_MAGIC) {
av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
return -1;
}
rle = bytestream_get_byte(&in_buf);
bytes_per_channel = bytestream_get_byte(&in_buf);
dimension = bytestream_get_be16(&in_buf);
s->width = bytestream_get_be16(&in_buf);
s->height = bytestream_get_be16(&in_buf);
s->depth = bytestream_get_be16(&in_buf);
if (bytes_per_channel != 1) {
av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
return -1;
}
/* Check for supported image dimensions. */
if (dimension != 2 && dimension != 3) {
av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
return -1;
}
if (s->depth == SGI_GRAYSCALE) {
avctx->pix_fmt = PIX_FMT_GRAY8;
} else if (s->depth == SGI_RGB) {
avctx->pix_fmt = PIX_FMT_RGB24;
} else if (s->depth == SGI_RGBA) {
avctx->pix_fmt = PIX_FMT_RGBA;
} else {
av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
return -1;
}
if (avcodec_check_dimensions(avctx, s->width, s->height))
return -1;
avcodec_set_dimensions(avctx, s->width, s->height);
if (p->data[0])
avctx->release_buffer(avctx, p);
p->reference = 0;
if (avctx->get_buffer(avctx, p) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n");
return -1;
}
p->pict_type = FF_I_TYPE;
p->key_frame = 1;
out_buf = p->data[0];
out_end = out_buf + p->linesize[0] * s->height;
s->linesize = p->linesize[0];
/* Skip header. */
in_buf += SGI_HEADER_SIZE - 12;
if (rle) {
ret = read_rle_sgi(out_end, in_buf, in_end, s);
} else {
ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s);
}
if (ret == 0) {
*picture = s->picture;
*data_size = sizeof(AVPicture);
return buf_size;
} else {
return -1;
}
}
static int sgi_init(AVCodecContext *avctx){
SgiState *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
return 0;
}
static int sgi_end(AVCodecContext *avctx)
{
SgiState * const s = avctx->priv_data;
if (s->picture.data[0])
avctx->release_buffer(avctx, &s->picture);
return 0;
}
AVCodec sgi_decoder = {
"sgi",
CODEC_TYPE_VIDEO,
CODEC_ID_SGI,
sizeof(SgiState),
sgi_init,
NULL,
sgi_end,
decode_frame,
};
/*
* SGI image encoder
* Todd Kirby <doubleshot@pacbell.net>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
#include "sgi.h"
#include "rle.h"
#define SGI_SINGLE_CHAN 2
#define SGI_MULTI_CHAN 3
typedef struct SgiContext {
AVFrame picture;
} SgiContext;
static int encode_init(AVCodecContext *avctx){
SgiContext *s = avctx->priv_data;
avcodec_get_frame_defaults(&s->picture);
avctx->coded_frame = &s->picture;
return 0;
}
static int encode_frame(AVCodecContext *avctx, unsigned char *buf,
int buf_size, void *data) {
SgiContext *s = avctx->priv_data;
AVFrame * const p = &s->picture;
uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf;
int x, y, z, length, tablesize;
unsigned int width, height, depth, dimension;
unsigned char *orig_buf = buf, *end_buf = buf + buf_size;
*p = *(AVFrame*)data;
p->pict_type = FF_I_TYPE;
p->key_frame = 1;
width = avctx->width;
height = avctx->height;
switch (avctx->pix_fmt) {
case PIX_FMT_GRAY8:
dimension = SGI_SINGLE_CHAN;
depth = SGI_GRAYSCALE;
break;
case PIX_FMT_RGB24:
dimension = SGI_MULTI_CHAN;
depth = SGI_RGB;
break;
case PIX_FMT_RGBA:
dimension = SGI_MULTI_CHAN;
depth = SGI_RGBA;
break;
default:
return AVERROR_INVALIDDATA;
}
tablesize = depth * height * 4;
length = tablesize * 2 + SGI_HEADER_SIZE;
if (buf_size < length) {
av_log(avctx, AV_LOG_ERROR, "buf_size too small(need %d, got %d)\n", length, buf_size);
return -1;
}
/* Encode header. */
bytestream_put_be16(&buf, SGI_MAGIC);
bytestream_put_byte(&buf, 1); /* RLE */
bytestream_put_byte(&buf, 1); /* bytes_per_channel */
bytestream_put_be16(&buf, dimension);
bytestream_put_be16(&buf, width);
bytestream_put_be16(&buf, height);
bytestream_put_be16(&buf, depth);
/* The rest are constant in this implementation. */
bytestream_put_be32(&buf, 0L); /* pixmin */
bytestream_put_be32(&buf, 255L); /* pixmax */
bytestream_put_be32(&buf, 0L); /* dummy */
/* name */
memset(buf, 0, SGI_HEADER_SIZE);
buf += 80;
/* colormap */
bytestream_put_be32(&buf, 0L);
/* The rest of the 512 byte header is unused. */
buf += 404;
offsettab = buf;
/* Skip RLE offset table. */
buf += tablesize;
lengthtab = buf;
/* Skip RLE length table. */
buf += tablesize;
/* Make an intermediate consecutive buffer. */
if ((encode_buf = av_malloc(width)) == NULL)
return -1;
for (z = 0; z < depth; z++) {
in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
for (y = 0; y < height; y++) {
bytestream_put_be32(&offsettab, buf - orig_buf);
for (x = 0; x < width; x++)
encode_buf[x] = in_buf[depth * x];
if((length = ff_rle_encode(buf, end_buf - buf - 1, encode_buf, 1, width, 0, 0, 0x80, 0)) < 1) {
av_free(encode_buf);
return -1;
}
buf += length;
bytestream_put_byte(&buf, 0);
bytestream_put_be32(&lengthtab, length + 1);
in_buf -= p->linesize[0];
}
}
av_free(encode_buf);
/* total length */
return buf - orig_buf;
}
AVCodec sgi_encoder = {
"sgi",
CODEC_TYPE_VIDEO,
CODEC_ID_SGI,
sizeof(SgiContext),
encode_init,
encode_frame,
NULL,
.pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA, PIX_FMT_PAL8, PIX_FMT_GRAY8, -1},
};
......@@ -54,6 +54,7 @@ static const IdStrMap img_tags[] = {
{ CODEC_ID_GIF , "gif"},
{ CODEC_ID_TARGA , "tga"},
{ CODEC_ID_TIFF , "tiff"},
{ CODEC_ID_SGI , "sgi"},
{0, NULL}
};
......
......@@ -125,6 +125,7 @@ const AVCodecTag codec_movvideo_tags[] = {
{ CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') }, /* SMPTE RP 2025 */
{ CODEC_ID_DNXHD, MKTAG('A', 'V', 'd', 'n') }, /* AVID DNxHD */
{ CODEC_ID_SGI, MKTAG('s', 'g', 'i', ' ') }, /* SGI */
{ CODEC_ID_NONE, 0 },
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment