3 * Todd Kirby <doubleshot@pacbell.net>
5 * This file is part of Libav.
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.
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.
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
22 #include "libavutil/opt.h"
25 #include "bytestream.h"
30 #define SGI_SINGLE_CHAN 2
31 #define SGI_MULTI_CHAN 3
33 typedef struct SgiContext
{
39 static av_cold
int encode_init(AVCodecContext
*avctx
)
41 if (avctx
->width
> 65535 || avctx
->height
> 65535) {
42 av_log(avctx
, AV_LOG_ERROR
,
43 "Unsupported resolution %dx%d.\n", avctx
->width
, avctx
->height
);
44 return AVERROR_INVALIDDATA
;
50 static int sgi_rle_encode(PutByteContext
*pbc
, const uint8_t *src
,
53 int val
, count
, x
, start
= bytestream2_tell_p(pbc
);
54 void (*bytestream2_put
)(PutByteContext
*, unsigned int);
57 bytestream2_put
= bytestream2_put_byte
;
59 bytestream2_put
= bytestream2_put_be16
;
61 for (x
= 0; x
< w
; x
+= count
) {
62 /* see if we can encode the next set of pixels with RLE */
63 count
= ff_rle_count_pixels(src
, w
- x
, bpp
, 1);
65 if (bytestream2_get_bytes_left_p(pbc
) < bpp
* 2)
66 return AVERROR_INVALIDDATA
;
68 val
= bpp
== 1 ? *src
: AV_RB16(src
);
69 bytestream2_put(pbc
, count
);
70 bytestream2_put(pbc
, val
);
73 /* fall back on uncompressed */
74 count
= ff_rle_count_pixels(src
, w
- x
, bpp
, 0);
75 if (bytestream2_get_bytes_left_p(pbc
) < bpp
* (count
+ 1))
76 return AVERROR_INVALIDDATA
;
78 bytestream2_put(pbc
, count
+ 0x80);
79 for (i
= 0; i
< count
; i
++) {
80 val
= bpp
== 1 ? src
[i
] : AV_RB16(src
+ i
* bpp
);
81 bytestream2_put(pbc
, val
);
88 return bytestream2_tell_p(pbc
) - start
;
91 static int encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
92 const AVFrame
*frame
, int *got_packet
)
94 SgiContext
*s
= avctx
->priv_data
;
95 const AVFrame
* const p
= frame
;
97 uint8_t *in_buf
, *encode_buf
;
98 int x
, y
, z
, length
, tablesize
, ret
, i
;
99 unsigned int width
, height
, depth
, dimension
;
100 unsigned int bytes_per_channel
, pixmax
, put_be
;
102 #if FF_API_CODED_FRAME
103 FF_DISABLE_DEPRECATION_WARNINGS
104 avctx
->coded_frame
->pict_type
= AV_PICTURE_TYPE_I
;
105 avctx
->coded_frame
->key_frame
= 1;
106 FF_ENABLE_DEPRECATION_WARNINGS
109 #if FF_API_CODER_TYPE
110 FF_DISABLE_DEPRECATION_WARNINGS
111 if (avctx
->coder_type
== FF_CODER_TYPE_RAW
)
113 FF_ENABLE_DEPRECATION_WARNINGS
116 width
= avctx
->width
;
117 height
= avctx
->height
;
118 bytes_per_channel
= 1;
120 put_be
= HAVE_BIGENDIAN
;
122 switch (avctx
->pix_fmt
) {
123 case AV_PIX_FMT_GRAY8
:
124 dimension
= SGI_SINGLE_CHAN
;
125 depth
= SGI_GRAYSCALE
;
127 case AV_PIX_FMT_RGB24
:
128 dimension
= SGI_MULTI_CHAN
;
131 case AV_PIX_FMT_RGBA
:
132 dimension
= SGI_MULTI_CHAN
;
135 case AV_PIX_FMT_GRAY16LE
:
136 put_be
= !HAVE_BIGENDIAN
;
137 case AV_PIX_FMT_GRAY16BE
:
138 bytes_per_channel
= 2;
140 dimension
= SGI_SINGLE_CHAN
;
141 depth
= SGI_GRAYSCALE
;
143 case AV_PIX_FMT_RGB48LE
:
144 put_be
= !HAVE_BIGENDIAN
;
145 case AV_PIX_FMT_RGB48BE
:
146 bytes_per_channel
= 2;
148 dimension
= SGI_MULTI_CHAN
;
151 case AV_PIX_FMT_RGBA64LE
:
152 put_be
= !HAVE_BIGENDIAN
;
153 case AV_PIX_FMT_RGBA64BE
:
154 bytes_per_channel
= 2;
156 dimension
= SGI_MULTI_CHAN
;
160 return AVERROR_INVALIDDATA
;
163 tablesize
= depth
* height
* 4;
164 length
= SGI_HEADER_SIZE
;
166 length
+= depth
* height
* width
;
167 else // assume sgi_rle_encode() produces at most 2x size of input
168 length
+= tablesize
* 2 + depth
* height
* (2 * width
+ 1);
170 if ((ret
= ff_alloc_packet(pkt
, bytes_per_channel
* length
)) < 0) {
171 av_log(avctx
, AV_LOG_ERROR
, "Error getting output packet of size %d.\n", length
);
175 bytestream2_init_writer(&pbc
, pkt
->data
, pkt
->size
);
178 bytestream2_put_be16(&pbc
, SGI_MAGIC
);
179 bytestream2_put_byte(&pbc
, s
->rle
); /* RLE 1 - VERBATIM 0 */
180 bytestream2_put_byte(&pbc
, bytes_per_channel
);
181 bytestream2_put_be16(&pbc
, dimension
);
182 bytestream2_put_be16(&pbc
, width
);
183 bytestream2_put_be16(&pbc
, height
);
184 bytestream2_put_be16(&pbc
, depth
);
186 bytestream2_put_be32(&pbc
, 0L); /* pixmin */
187 bytestream2_put_be32(&pbc
, pixmax
);
188 bytestream2_put_be32(&pbc
, 0L); /* dummy */
191 for (i
= 0; i
< 80; i
++)
192 bytestream2_put_byte(&pbc
, 0L);
195 bytestream2_put_be32(&pbc
, 0L);
197 /* The rest of the 512 byte header is unused. */
198 for (i
= 0; i
< 404; i
++)
199 bytestream2_put_byte(&pbc
, 0L);
202 PutByteContext taboff_pcb
, tablen_pcb
;
204 /* Skip RLE offset table. */
205 bytestream2_init_writer(&taboff_pcb
, pbc
.buffer
, tablesize
);
206 bytestream2_skip_p(&pbc
, tablesize
);
208 /* Skip RLE length table. */
209 bytestream2_init_writer(&tablen_pcb
, pbc
.buffer
, tablesize
);
210 bytestream2_skip_p(&pbc
, tablesize
);
212 /* Make an intermediate consecutive buffer. */
213 if (!(encode_buf
= av_malloc(width
* bytes_per_channel
)))
214 return AVERROR(ENOMEM
);
216 for (z
= 0; z
< depth
; z
++) {
217 in_buf
= p
->data
[0] + p
->linesize
[0] * (height
- 1) + z
* bytes_per_channel
;
219 for (y
= 0; y
< height
; y
++) {
220 bytestream2_put_be32(&taboff_pcb
, bytestream2_tell_p(&pbc
));
222 for (x
= 0; x
< width
* bytes_per_channel
; x
+= bytes_per_channel
)
223 encode_buf
[x
] = in_buf
[depth
* x
];
225 length
= sgi_rle_encode(&pbc
, encode_buf
, width
,
229 return AVERROR_INVALIDDATA
;
232 bytestream2_put_be32(&tablen_pcb
, length
);
233 in_buf
-= p
->linesize
[0];
239 for (z
= 0; z
< depth
; z
++) {
240 in_buf
= p
->data
[0] + p
->linesize
[0] * (height
- 1) + z
* bytes_per_channel
;
242 for (y
= 0; y
< height
; y
++) {
243 for (x
= 0; x
< width
* depth
; x
+= depth
)
244 if (bytes_per_channel
== 1)
245 bytestream2_put_byte(&pbc
, in_buf
[x
]);
248 bytestream2_put_be16(&pbc
, ((uint16_t *)in_buf
)[x
]);
250 bytestream2_put_le16(&pbc
, ((uint16_t *)in_buf
)[x
]);
252 in_buf
-= p
->linesize
[0];
258 pkt
->size
= bytestream2_tell_p(&pbc
);
259 pkt
->flags
|= AV_PKT_FLAG_KEY
;
265 #define OFFSET(x) offsetof(SgiContext, x)
266 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
267 static const AVOption options
[] = {
268 { "rle", "Use run-length compression", OFFSET(rle
), AV_OPT_TYPE_INT
, { .i64
= 1 }, 0, 1, VE
},
273 static const AVClass sgi_class
= {
275 .item_name
= av_default_item_name
,
277 .version
= LIBAVUTIL_VERSION_INT
,
280 AVCodec ff_sgi_encoder
= {
282 .long_name
= NULL_IF_CONFIG_SMALL("SGI image"),
283 .type
= AVMEDIA_TYPE_VIDEO
,
284 .id
= AV_CODEC_ID_SGI
,
285 .priv_data_size
= sizeof(SgiContext
),
286 .priv_class
= &sgi_class
,
288 .encode2
= encode_frame
,
289 .pix_fmts
= (const enum AVPixelFormat
[]) {
290 AV_PIX_FMT_RGB24
, AV_PIX_FMT_RGBA
,
291 AV_PIX_FMT_RGB48LE
, AV_PIX_FMT_RGB48BE
,
292 AV_PIX_FMT_RGBA64LE
, AV_PIX_FMT_RGBA64BE
,
293 AV_PIX_FMT_GRAY16LE
, AV_PIX_FMT_GRAY16BE
, AV_PIX_FMT_GRAY8
,