mirror of https://github.com/FFmpeg/FFmpeg.git
patch by Xiaohui Sun, sunxiaohui dsp.ac cn Originally committed as revision 8635 to svn://svn.ffmpeg.org/ffmpeg/trunkpull/126/head
parent
0d0677fbc7
commit
2d99eed135
8 changed files with 468 additions and 0 deletions
@ -0,0 +1,37 @@ |
||||
/*
|
||||
* 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 |
||||
|
@ -0,0 +1,267 @@ |
||||
/*
|
||||
* 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, |
||||
}; |
||||
|
@ -0,0 +1,156 @@ |
||||
/*
|
||||
* 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}, |
||||
}; |
||||
|
Loading…
Reference in new issue