1/* 2 * SGI image encoder 3 * Todd Kirby <doubleshot@pacbell.net> 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "avcodec.h" 23#include "bytestream.h" 24#include "sgi.h" 25#include "rle.h" 26 27#define SGI_SINGLE_CHAN 2 28#define SGI_MULTI_CHAN 3 29 30typedef struct SgiContext { 31 AVFrame picture; 32} SgiContext; 33 34static av_cold int encode_init(AVCodecContext *avctx){ 35 SgiContext *s = avctx->priv_data; 36 37 avcodec_get_frame_defaults(&s->picture); 38 avctx->coded_frame = &s->picture; 39 40 return 0; 41} 42 43static int encode_frame(AVCodecContext *avctx, unsigned char *buf, 44 int buf_size, void *data) { 45 SgiContext *s = avctx->priv_data; 46 AVFrame * const p = &s->picture; 47 uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf; 48 int x, y, z, length, tablesize; 49 unsigned int width, height, depth, dimension; 50 unsigned char *orig_buf = buf, *end_buf = buf + buf_size; 51 52 *p = *(AVFrame*)data; 53 p->pict_type = FF_I_TYPE; 54 p->key_frame = 1; 55 56 width = avctx->width; 57 height = avctx->height; 58 59 switch (avctx->pix_fmt) { 60 case PIX_FMT_GRAY8: 61 dimension = SGI_SINGLE_CHAN; 62 depth = SGI_GRAYSCALE; 63 break; 64 case PIX_FMT_RGB24: 65 dimension = SGI_MULTI_CHAN; 66 depth = SGI_RGB; 67 break; 68 case PIX_FMT_RGBA: 69 dimension = SGI_MULTI_CHAN; 70 depth = SGI_RGBA; 71 break; 72 default: 73 return AVERROR_INVALIDDATA; 74 } 75 76 tablesize = depth * height * 4; 77 length = tablesize * 2 + SGI_HEADER_SIZE; 78 79 if (buf_size < length) { 80 av_log(avctx, AV_LOG_ERROR, "buf_size too small(need %d, got %d)\n", length, buf_size); 81 return -1; 82 } 83 84 /* Encode header. */ 85 bytestream_put_be16(&buf, SGI_MAGIC); 86 bytestream_put_byte(&buf, 1); /* RLE */ 87 bytestream_put_byte(&buf, 1); /* bytes_per_channel */ 88 bytestream_put_be16(&buf, dimension); 89 bytestream_put_be16(&buf, width); 90 bytestream_put_be16(&buf, height); 91 bytestream_put_be16(&buf, depth); 92 93 /* The rest are constant in this implementation. */ 94 bytestream_put_be32(&buf, 0L); /* pixmin */ 95 bytestream_put_be32(&buf, 255L); /* pixmax */ 96 bytestream_put_be32(&buf, 0L); /* dummy */ 97 98 /* name */ 99 memset(buf, 0, SGI_HEADER_SIZE); 100 buf += 80; 101 102 /* colormap */ 103 bytestream_put_be32(&buf, 0L); 104 105 /* The rest of the 512 byte header is unused. */ 106 buf += 404; 107 offsettab = buf; 108 109 /* Skip RLE offset table. */ 110 buf += tablesize; 111 lengthtab = buf; 112 113 /* Skip RLE length table. */ 114 buf += tablesize; 115 116 /* Make an intermediate consecutive buffer. */ 117 if ((encode_buf = av_malloc(width)) == NULL) 118 return -1; 119 120 for (z = 0; z < depth; z++) { 121 in_buf = p->data[0] + p->linesize[0] * (height - 1) + z; 122 123 for (y = 0; y < height; y++) { 124 bytestream_put_be32(&offsettab, buf - orig_buf); 125 126 for (x = 0; x < width; x++) 127 encode_buf[x] = in_buf[depth * x]; 128 129 if((length = ff_rle_encode(buf, end_buf - buf - 1, encode_buf, 1, width, 0, 0, 0x80, 0)) < 1) { 130 av_free(encode_buf); 131 return -1; 132 } 133 134 buf += length; 135 bytestream_put_byte(&buf, 0); 136 bytestream_put_be32(&lengthtab, length + 1); 137 in_buf -= p->linesize[0]; 138 } 139 } 140 141 av_free(encode_buf); 142 /* total length */ 143 return buf - orig_buf; 144} 145 146AVCodec sgi_encoder = { 147 "sgi", 148 CODEC_TYPE_VIDEO, 149 CODEC_ID_SGI, 150 sizeof(SgiContext), 151 encode_init, 152 encode_frame, 153 NULL, 154 .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA, PIX_FMT_PAL8, PIX_FMT_GRAY8, PIX_FMT_NONE}, 155 .long_name= NULL_IF_CONFIG_SMALL("SGI image"), 156}; 157 158