00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avcodec.h"
00023 #include "bytestream.h"
00024 #include "internal.h"
00025 #include "sgi.h"
00026 #include "rle.h"
00027
00028 #define SGI_SINGLE_CHAN 2
00029 #define SGI_MULTI_CHAN 3
00030
00031 typedef struct SgiContext {
00032 AVFrame picture;
00033 } SgiContext;
00034
00035 static av_cold int encode_init(AVCodecContext *avctx)
00036 {
00037 SgiContext *s = avctx->priv_data;
00038
00039 avcodec_get_frame_defaults(&s->picture);
00040 avctx->coded_frame = &s->picture;
00041
00042 return 0;
00043 }
00044
00045 static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
00046 const AVFrame *frame, int *got_packet)
00047 {
00048 SgiContext *s = avctx->priv_data;
00049 AVFrame * const p = &s->picture;
00050 uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf, *buf;
00051 int x, y, z, length, tablesize, ret;
00052 unsigned int width, height, depth, dimension, bytes_per_channel, pixmax, put_be;
00053 unsigned char *end_buf;
00054
00055 *p = *frame;
00056 p->pict_type = AV_PICTURE_TYPE_I;
00057 p->key_frame = 1;
00058
00059 width = avctx->width;
00060 height = avctx->height;
00061 bytes_per_channel = 1;
00062 pixmax = 0xFF;
00063 put_be = HAVE_BIGENDIAN;
00064
00065 switch (avctx->pix_fmt) {
00066 case PIX_FMT_GRAY8:
00067 dimension = SGI_SINGLE_CHAN;
00068 depth = SGI_GRAYSCALE;
00069 break;
00070 case PIX_FMT_RGB24:
00071 dimension = SGI_MULTI_CHAN;
00072 depth = SGI_RGB;
00073 break;
00074 case PIX_FMT_RGBA:
00075 dimension = SGI_MULTI_CHAN;
00076 depth = SGI_RGBA;
00077 break;
00078 case PIX_FMT_GRAY16LE:
00079 put_be = !HAVE_BIGENDIAN;
00080 case PIX_FMT_GRAY16BE:
00081 avctx->coder_type = FF_CODER_TYPE_RAW;
00082 bytes_per_channel = 2;
00083 pixmax = 0xFFFF;
00084 dimension = SGI_SINGLE_CHAN;
00085 depth = SGI_GRAYSCALE;
00086 break;
00087 case PIX_FMT_RGB48LE:
00088 put_be = !HAVE_BIGENDIAN;
00089 case PIX_FMT_RGB48BE:
00090 avctx->coder_type = FF_CODER_TYPE_RAW;
00091 bytes_per_channel = 2;
00092 pixmax = 0xFFFF;
00093 dimension = SGI_MULTI_CHAN;
00094 depth = SGI_RGB;
00095 break;
00096 case PIX_FMT_RGBA64LE:
00097 put_be = !HAVE_BIGENDIAN;
00098 case PIX_FMT_RGBA64BE:
00099 avctx->coder_type = FF_CODER_TYPE_RAW;
00100 bytes_per_channel = 2;
00101 pixmax = 0xFFFF;
00102 dimension = SGI_MULTI_CHAN;
00103 depth = SGI_RGBA;
00104 break;
00105 default:
00106 return AVERROR_INVALIDDATA;
00107 }
00108
00109 tablesize = depth * height * 4;
00110 length = SGI_HEADER_SIZE;
00111 if (avctx->coder_type == FF_CODER_TYPE_RAW)
00112 length += depth * height * width;
00113 else
00114 length += tablesize * 2 + depth * height * (2 * width + 1);
00115
00116 if ((ret = ff_alloc_packet2(avctx, pkt, bytes_per_channel * length)) < 0)
00117 return ret;
00118 buf = pkt->data;
00119 end_buf = pkt->data + pkt->size;
00120
00121
00122 bytestream_put_be16(&buf, SGI_MAGIC);
00123 bytestream_put_byte(&buf, avctx->coder_type != FF_CODER_TYPE_RAW);
00124 bytestream_put_byte(&buf, bytes_per_channel);
00125 bytestream_put_be16(&buf, dimension);
00126 bytestream_put_be16(&buf, width);
00127 bytestream_put_be16(&buf, height);
00128 bytestream_put_be16(&buf, depth);
00129
00130 bytestream_put_be32(&buf, 0L);
00131 bytestream_put_be32(&buf, pixmax);
00132 bytestream_put_be32(&buf, 0L);
00133
00134
00135 memset(buf, 0, SGI_HEADER_SIZE);
00136 buf += 80;
00137
00138
00139 bytestream_put_be32(&buf, 0L);
00140
00141
00142 buf += 404;
00143 offsettab = buf;
00144
00145 if (avctx->coder_type != FF_CODER_TYPE_RAW) {
00146
00147 buf += tablesize;
00148 lengthtab = buf;
00149
00150
00151 buf += tablesize;
00152
00153
00154 if (!(encode_buf = av_malloc(width)))
00155 return -1;
00156
00157 for (z = 0; z < depth; z++) {
00158 in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
00159
00160 for (y = 0; y < height; y++) {
00161 bytestream_put_be32(&offsettab, buf - pkt->data);
00162
00163 for (x = 0; x < width; x++)
00164 encode_buf[x] = in_buf[depth * x];
00165
00166 if ((length = ff_rle_encode(buf, end_buf - buf - 1, encode_buf, 1, width, 0, 0, 0x80, 0)) < 1) {
00167 av_free(encode_buf);
00168 return -1;
00169 }
00170
00171 buf += length;
00172 bytestream_put_byte(&buf, 0);
00173 bytestream_put_be32(&lengthtab, length + 1);
00174 in_buf -= p->linesize[0];
00175 }
00176 }
00177
00178 av_free(encode_buf);
00179 } else {
00180 for (z = 0; z < depth; z++) {
00181 in_buf = p->data[0] + p->linesize[0] * (height - 1) + z * bytes_per_channel;
00182
00183 for (y = 0; y < height; y++) {
00184 for (x = 0; x < width * depth; x += depth)
00185 if (bytes_per_channel == 1) {
00186 bytestream_put_byte(&buf, in_buf[x]);
00187 } else {
00188 if (put_be) {
00189 bytestream_put_be16(&buf, ((uint16_t *)in_buf)[x]);
00190 } else {
00191 bytestream_put_le16(&buf, ((uint16_t *)in_buf)[x]);
00192 }
00193 }
00194
00195 in_buf -= p->linesize[0];
00196 }
00197 }
00198 }
00199
00200
00201 pkt->size = buf - pkt->data;
00202 pkt->flags |= AV_PKT_FLAG_KEY;
00203 *got_packet = 1;
00204
00205 return 0;
00206 }
00207
00208 AVCodec ff_sgi_encoder = {
00209 .name = "sgi",
00210 .type = AVMEDIA_TYPE_VIDEO,
00211 .id = CODEC_ID_SGI,
00212 .priv_data_size = sizeof(SgiContext),
00213 .init = encode_init,
00214 .encode2 = encode_frame,
00215 .pix_fmts = (const enum PixelFormat[]){
00216 PIX_FMT_RGB24, PIX_FMT_RGBA,
00217 PIX_FMT_RGB48LE, PIX_FMT_RGB48BE,
00218 PIX_FMT_RGBA64LE, PIX_FMT_RGBA64BE,
00219 PIX_FMT_GRAY16LE, PIX_FMT_GRAY16BE,
00220 PIX_FMT_GRAY8, PIX_FMT_NONE
00221 },
00222 .long_name = NULL_IF_CONFIG_SMALL("SGI image"),
00223 };