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