Statistics
| Branch: | Revision:

ffmpeg / libavcodec / sgienc.c @ 2912e87a

History | View | Annotate | Download (4.86 KB)

1
/*
2
 * SGI image encoder
3
 * Todd Kirby <doubleshot@pacbell.net>
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; 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

    
30
typedef struct SgiContext {
31
    AVFrame picture;
32
} SgiContext;
33

    
34
static av_cold int encode_init(AVCodecContext *avctx)
35
{
36
    SgiContext *s = avctx->priv_data;
37

    
38
    avcodec_get_frame_defaults(&s->picture);
39
    avctx->coded_frame = &s->picture;
40

    
41
    return 0;
42
}
43

    
44
static int encode_frame(AVCodecContext *avctx, unsigned char *buf,
45
                        int buf_size, void *data)
46
{
47
    SgiContext *s = avctx->priv_data;
48
    AVFrame * const p = &s->picture;
49
    uint8_t *offsettab, *lengthtab, *in_buf, *encode_buf;
50
    int x, y, z, length, tablesize;
51
    unsigned int width, height, depth, dimension;
52
    unsigned char *orig_buf = buf, *end_buf = buf + buf_size;
53

    
54
    *p = *(AVFrame*)data;
55
    p->pict_type = FF_I_TYPE;
56
    p->key_frame = 1;
57

    
58
    width  = avctx->width;
59
    height = avctx->height;
60

    
61
    switch (avctx->pix_fmt) {
62
    case PIX_FMT_GRAY8:
63
        dimension = SGI_SINGLE_CHAN;
64
        depth     = SGI_GRAYSCALE;
65
        break;
66
    case PIX_FMT_RGB24:
67
        dimension = SGI_MULTI_CHAN;
68
        depth     = SGI_RGB;
69
        break;
70
    case PIX_FMT_RGBA:
71
        dimension = SGI_MULTI_CHAN;
72
        depth     = SGI_RGBA;
73
        break;
74
    default:
75
        return AVERROR_INVALIDDATA;
76
    }
77

    
78
    tablesize = depth * height * 4;
79
    length = tablesize * 2 + SGI_HEADER_SIZE;
80

    
81
    if (buf_size < length) {
82
        av_log(avctx, AV_LOG_ERROR, "buf_size too small(need %d, got %d)\n", length, buf_size);
83
        return -1;
84
    }
85

    
86
    /* Encode header. */
87
    bytestream_put_be16(&buf, SGI_MAGIC);
88
    bytestream_put_byte(&buf, avctx->coder_type != FF_CODER_TYPE_RAW); /* RLE 1 - VERBATIM 0*/
89
    bytestream_put_byte(&buf, 1); /* bytes_per_channel */
90
    bytestream_put_be16(&buf, dimension);
91
    bytestream_put_be16(&buf, width);
92
    bytestream_put_be16(&buf, height);
93
    bytestream_put_be16(&buf, depth);
94

    
95
    /* The rest are constant in this implementation. */
96
    bytestream_put_be32(&buf, 0L); /* pixmin */
97
    bytestream_put_be32(&buf, 255L); /* pixmax */
98
    bytestream_put_be32(&buf, 0L); /* dummy */
99

    
100
    /* name */
101
    memset(buf, 0, SGI_HEADER_SIZE);
102
    buf += 80;
103

    
104
     /* colormap */
105
    bytestream_put_be32(&buf, 0L);
106

    
107
    /* The rest of the 512 byte header is unused. */
108
    buf += 404;
109
    offsettab = buf;
110

    
111
    if (avctx->coder_type  != FF_CODER_TYPE_RAW) {
112
        /* Skip RLE offset table. */
113
        buf += tablesize;
114
        lengthtab = buf;
115

    
116
        /* Skip RLE length table. */
117
        buf += tablesize;
118

    
119
        /* Make an intermediate consecutive buffer. */
120
        if (!(encode_buf = av_malloc(width)))
121
            return -1;
122

    
123
        for (z = 0; z < depth; z++) {
124
            in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
125

    
126
            for (y = 0; y < height; y++) {
127
                bytestream_put_be32(&offsettab, buf - orig_buf);
128

    
129
                for (x = 0; x < width; x++)
130
                    encode_buf[x] = in_buf[depth * x];
131

    
132
                if ((length = ff_rle_encode(buf, end_buf - buf - 1, encode_buf, 1, width, 0, 0, 0x80, 0)) < 1) {
133
                    av_free(encode_buf);
134
                    return -1;
135
                }
136

    
137
                buf += length;
138
                bytestream_put_byte(&buf, 0);
139
                bytestream_put_be32(&lengthtab, length + 1);
140
                in_buf -= p->linesize[0];
141
            }
142
        }
143

    
144
        av_free(encode_buf);
145
    } else {
146
        for (z = 0; z < depth; z++) {
147
            in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
148

    
149
            for (y = 0; y < height; y++) {
150
                for (x = 0; x < width * depth; x += depth)
151
                    bytestream_put_byte(&buf, in_buf[x]);
152

    
153
                in_buf -= p->linesize[0];
154
            }
155
        }
156
    }
157

    
158
    /* total length */
159
    return buf - orig_buf;
160
}
161

    
162
AVCodec ff_sgi_encoder = {
163
    "sgi",
164
    AVMEDIA_TYPE_VIDEO,
165
    CODEC_ID_SGI,
166
    sizeof(SgiContext),
167
    encode_init,
168
    encode_frame,
169
    NULL,
170
    .pix_fmts= (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA, PIX_FMT_GRAY8, PIX_FMT_NONE},
171
    .long_name= NULL_IF_CONFIG_SMALL("SGI image"),
172
};