sgi: encode images with 4 channels at 8 and 16 bits

This commit is contained in:
Vittorio Giovara 2014-03-13 01:19:12 +01:00
parent f8dea10d3f
commit 6c1df1f228
2 changed files with 48 additions and 8 deletions

View File

@ -11,7 +11,7 @@ version <next>:
- XBM decoder
- bmp standalone parser
- OpenEXR image decoder
- support decoding 4-channel SGI images
- support encoding and decoding 4-channel SGI images
version 10:

View File

@ -50,6 +50,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf, *buf;
int x, y, z, length, tablesize, ret;
unsigned int width, height, depth, dimension;
unsigned int bytes_per_channel, pixmax, put_be;
unsigned char *end_buf;
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
@ -57,6 +58,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
width = avctx->width;
height = avctx->height;
bytes_per_channel = 1;
pixmax = 0xFF;
put_be = HAVE_BIGENDIAN;
switch (avctx->pix_fmt) {
case AV_PIX_FMT_GRAY8:
@ -71,6 +75,33 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
dimension = SGI_MULTI_CHAN;
depth = SGI_RGBA;
break;
case AV_PIX_FMT_GRAY16LE:
put_be = !HAVE_BIGENDIAN;
case AV_PIX_FMT_GRAY16BE:
avctx->coder_type = FF_CODER_TYPE_RAW;
bytes_per_channel = 2;
pixmax = 0xFFFF;
dimension = SGI_SINGLE_CHAN;
depth = SGI_GRAYSCALE;
break;
case AV_PIX_FMT_RGB48LE:
put_be = !HAVE_BIGENDIAN;
case AV_PIX_FMT_RGB48BE:
avctx->coder_type = FF_CODER_TYPE_RAW;
bytes_per_channel = 2;
pixmax = 0xFFFF;
dimension = SGI_MULTI_CHAN;
depth = SGI_RGB;
break;
case AV_PIX_FMT_RGBA64LE:
put_be = !HAVE_BIGENDIAN;
case AV_PIX_FMT_RGBA64BE:
avctx->coder_type = FF_CODER_TYPE_RAW;
bytes_per_channel = 2;
pixmax = 0xFFFF;
dimension = SGI_MULTI_CHAN;
depth = SGI_RGBA;
break;
default:
return AVERROR_INVALIDDATA;
}
@ -82,7 +113,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
else // assume ff_rl_encode() produces at most 2x size of input
length += tablesize * 2 + depth * height * (2 * width + 1);
if ((ret = ff_alloc_packet(pkt, length)) < 0) {
if ((ret = ff_alloc_packet(pkt, bytes_per_channel * length)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", length);
return ret;
}
@ -92,15 +123,14 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* Encode header. */
bytestream_put_be16(&buf, SGI_MAGIC);
bytestream_put_byte(&buf, avctx->coder_type != FF_CODER_TYPE_RAW); /* RLE 1 - VERBATIM 0*/
bytestream_put_byte(&buf, 1); /* bytes_per_channel */
bytestream_put_byte(&buf, 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, pixmax);
bytestream_put_be32(&buf, 0L); /* dummy */
/* name */
@ -150,11 +180,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
av_free(encode_buf);
} else {
for (z = 0; z < depth; z++) {
in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
in_buf = p->data[0] + p->linesize[0] * (height - 1) + z * bytes_per_channel;
for (y = 0; y < height; y++) {
for (x = 0; x < width * depth; x += depth)
bytestream_put_byte(&buf, in_buf[x]);
if (bytes_per_channel == 1)
bytestream_put_byte(&buf, in_buf[x]);
else
if (put_be)
bytestream_put_be16(&buf, ((uint16_t *)in_buf)[x]);
else
bytestream_put_le16(&buf, ((uint16_t *)in_buf)[x]);
in_buf -= p->linesize[0];
}
@ -184,6 +220,10 @@ AVCodec ff_sgi_encoder = {
.encode2 = encode_frame,
.close = encode_close,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE,
AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE,
AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8,
AV_PIX_FMT_NONE
},
};