3 * Todd Kirby <doubleshot@pacbell.net>
5 * This file is part of FFmpeg.
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.
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.
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
23 #include "bytestream.h"
28 #define SGI_SINGLE_CHAN 2
29 #define SGI_MULTI_CHAN 3
31 static av_cold
int encode_init(AVCodecContext
*avctx
)
33 if (avctx
->width
> 65535 || avctx
->height
> 65535) {
34 av_log(avctx
, AV_LOG_ERROR
,
35 "Unsupported resolution %dx%d.\n", avctx
->width
, avctx
->height
);
36 av_log(avctx
, AV_LOG_ERROR
, "SGI does not support resolutions above 65535x65535\n");
37 return AVERROR_INVALIDDATA
;
40 avctx
->coded_frame
= av_frame_alloc();
41 if (!avctx
->coded_frame
)
42 return AVERROR(ENOMEM
);
47 static int encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
48 const AVFrame
*frame
, int *got_packet
)
50 const AVFrame
* const p
= frame
;
51 uint8_t *offsettab
, *lengthtab
, *in_buf
, *encode_buf
, *buf
;
52 int x
, y
, z
, length
, tablesize
, ret
;
53 unsigned int width
, height
, depth
, dimension
;
54 unsigned int bytes_per_channel
, pixmax
, put_be
;
55 unsigned char *end_buf
;
57 avctx
->coded_frame
->pict_type
= AV_PICTURE_TYPE_I
;
58 avctx
->coded_frame
->key_frame
= 1;
61 height
= avctx
->height
;
62 bytes_per_channel
= 1;
64 put_be
= HAVE_BIGENDIAN
;
66 switch (avctx
->pix_fmt
) {
67 case AV_PIX_FMT_GRAY8
:
68 dimension
= SGI_SINGLE_CHAN
;
69 depth
= SGI_GRAYSCALE
;
71 case AV_PIX_FMT_RGB24
:
72 dimension
= SGI_MULTI_CHAN
;
76 dimension
= SGI_MULTI_CHAN
;
79 case AV_PIX_FMT_GRAY16LE
:
80 put_be
= !HAVE_BIGENDIAN
;
81 case AV_PIX_FMT_GRAY16BE
:
82 avctx
->coder_type
= FF_CODER_TYPE_RAW
;
83 bytes_per_channel
= 2;
85 dimension
= SGI_SINGLE_CHAN
;
86 depth
= SGI_GRAYSCALE
;
88 case AV_PIX_FMT_RGB48LE
:
89 put_be
= !HAVE_BIGENDIAN
;
90 case AV_PIX_FMT_RGB48BE
:
91 avctx
->coder_type
= FF_CODER_TYPE_RAW
;
92 bytes_per_channel
= 2;
94 dimension
= SGI_MULTI_CHAN
;
97 case AV_PIX_FMT_RGBA64LE
:
98 put_be
= !HAVE_BIGENDIAN
;
99 case AV_PIX_FMT_RGBA64BE
:
100 avctx
->coder_type
= FF_CODER_TYPE_RAW
;
101 bytes_per_channel
= 2;
103 dimension
= SGI_MULTI_CHAN
;
107 return AVERROR_INVALIDDATA
;
110 tablesize
= depth
* height
* 4;
111 length
= SGI_HEADER_SIZE
;
112 if (avctx
->coder_type
== FF_CODER_TYPE_RAW
)
113 length
+= depth
* height
* width
;
114 else // assume ff_rl_encode() produces at most 2x size of input
115 length
+= tablesize
* 2 + depth
* height
* (2 * width
+ 1);
117 if ((ret
= ff_alloc_packet2(avctx
, pkt
, bytes_per_channel
* length
)) < 0)
120 end_buf
= pkt
->data
+ pkt
->size
;
123 bytestream_put_be16(&buf
, SGI_MAGIC
);
124 bytestream_put_byte(&buf
, avctx
->coder_type
!= FF_CODER_TYPE_RAW
); /* RLE 1 - VERBATIM 0*/
125 bytestream_put_byte(&buf
, bytes_per_channel
);
126 bytestream_put_be16(&buf
, dimension
);
127 bytestream_put_be16(&buf
, width
);
128 bytestream_put_be16(&buf
, height
);
129 bytestream_put_be16(&buf
, depth
);
131 bytestream_put_be32(&buf
, 0L); /* pixmin */
132 bytestream_put_be32(&buf
, pixmax
);
133 bytestream_put_be32(&buf
, 0L); /* dummy */
136 memset(buf
, 0, SGI_HEADER_SIZE
);
140 bytestream_put_be32(&buf
, 0L);
142 /* The rest of the 512 byte header is unused. */
146 if (avctx
->coder_type
!= FF_CODER_TYPE_RAW
) {
147 /* Skip RLE offset table. */
151 /* Skip RLE length table. */
154 /* Make an intermediate consecutive buffer. */
155 if (!(encode_buf
= av_malloc(width
)))
158 for (z
= 0; z
< depth
; z
++) {
159 in_buf
= p
->data
[0] + p
->linesize
[0] * (height
- 1) + z
;
161 for (y
= 0; y
< height
; y
++) {
162 bytestream_put_be32(&offsettab
, buf
- pkt
->data
);
164 for (x
= 0; x
< width
; x
++)
165 encode_buf
[x
] = in_buf
[depth
* x
];
167 if ((length
= ff_rle_encode(buf
, end_buf
- buf
- 1, encode_buf
, 1, width
, 0, 0, 0x80, 0)) < 1) {
173 bytestream_put_byte(&buf
, 0);
174 bytestream_put_be32(&lengthtab
, length
+ 1);
175 in_buf
-= p
->linesize
[0];
181 for (z
= 0; z
< depth
; z
++) {
182 in_buf
= p
->data
[0] + p
->linesize
[0] * (height
- 1) + z
* bytes_per_channel
;
184 for (y
= 0; y
< height
; y
++) {
185 for (x
= 0; x
< width
* depth
; x
+= depth
)
186 if (bytes_per_channel
== 1) {
187 bytestream_put_byte(&buf
, in_buf
[x
]);
190 bytestream_put_be16(&buf
, ((uint16_t *)in_buf
)[x
]);
192 bytestream_put_le16(&buf
, ((uint16_t *)in_buf
)[x
]);
196 in_buf
-= p
->linesize
[0];
202 pkt
->size
= buf
- pkt
->data
;
203 pkt
->flags
|= AV_PKT_FLAG_KEY
;
209 static av_cold
int encode_close(AVCodecContext
*avctx
)
211 av_frame_free(&avctx
->coded_frame
);
215 AVCodec ff_sgi_encoder
= {
217 .long_name
= NULL_IF_CONFIG_SMALL("SGI image"),
218 .type
= AVMEDIA_TYPE_VIDEO
,
219 .id
= AV_CODEC_ID_SGI
,
221 .encode2
= encode_frame
,
222 .close
= encode_close
,
223 .pix_fmts
= (const enum AVPixelFormat
[]) {
224 AV_PIX_FMT_RGB24
, AV_PIX_FMT_RGBA
,
225 AV_PIX_FMT_RGB48LE
, AV_PIX_FMT_RGB48BE
,
226 AV_PIX_FMT_RGBA64LE
, AV_PIX_FMT_RGBA64BE
,
227 AV_PIX_FMT_GRAY16LE
, AV_PIX_FMT_GRAY16BE
, AV_PIX_FMT_GRAY8
,