/src/ffmpeg/libavcodec/sunrastenc.c
Line | Count | Source |
1 | | /* |
2 | | * Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image encoder |
3 | | * Copyright (c) 2012 Aneesh Dogra (lionaneesh) <lionaneesh@gmail.com> |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
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. |
11 | | * |
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. |
16 | | * |
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 |
20 | | */ |
21 | | |
22 | | #include "libavutil/opt.h" |
23 | | |
24 | | #include "avcodec.h" |
25 | | #include "bytestream.h" |
26 | | #include "codec_internal.h" |
27 | | #include "encode.h" |
28 | | #include "sunrast.h" |
29 | | |
30 | | typedef struct SUNRASTContext { |
31 | | AVClass *class; |
32 | | |
33 | | PutByteContext p; |
34 | | int depth; ///< depth of pixel |
35 | | int length; ///< length (bytes) of image |
36 | | int type; ///< type of file |
37 | | int maptype; ///< type of colormap |
38 | | int maplength; ///< length (bytes) of colormap |
39 | | int size; |
40 | | } SUNRASTContext; |
41 | | |
42 | | static void sunrast_image_write_header(AVCodecContext *avctx) |
43 | 8.28k | { |
44 | 8.28k | SUNRASTContext *s = avctx->priv_data; |
45 | | |
46 | 8.28k | bytestream2_put_be32u(&s->p, RAS_MAGIC); |
47 | 8.28k | bytestream2_put_be32u(&s->p, avctx->width); |
48 | 8.28k | bytestream2_put_be32u(&s->p, avctx->height); |
49 | 8.28k | bytestream2_put_be32u(&s->p, s->depth); |
50 | 8.28k | bytestream2_put_be32u(&s->p, s->length); |
51 | 8.28k | bytestream2_put_be32u(&s->p, s->type); |
52 | 8.28k | bytestream2_put_be32u(&s->p, s->maptype); |
53 | 8.28k | bytestream2_put_be32u(&s->p, s->maplength); |
54 | 8.28k | } |
55 | | |
56 | | static void sunrast_image_write_image(AVCodecContext *avctx, |
57 | | const uint8_t *pixels, |
58 | | const uint32_t *palette_data, |
59 | | int linesize) |
60 | 8.28k | { |
61 | 8.28k | SUNRASTContext *s = avctx->priv_data; |
62 | 8.28k | const uint8_t *ptr; |
63 | 8.28k | int len, alen, x, y; |
64 | | |
65 | 8.28k | if (s->maplength) { // palettized |
66 | 2.01k | PutByteContext pb_r, pb_g; |
67 | 2.01k | int len = s->maplength / 3; |
68 | | |
69 | 2.01k | pb_r = s->p; |
70 | 2.01k | bytestream2_skip_p(&s->p, len); |
71 | 2.01k | pb_g = s->p; |
72 | 2.01k | bytestream2_skip_p(&s->p, len); |
73 | | |
74 | 517k | for (x = 0; x < len; x++) { |
75 | 515k | uint32_t pixel = palette_data[x]; |
76 | | |
77 | 515k | bytestream2_put_byteu(&pb_r, (pixel >> 16) & 0xFF); |
78 | 515k | bytestream2_put_byteu(&pb_g, (pixel >> 8) & 0xFF); |
79 | 515k | bytestream2_put_byteu(&s->p, pixel & 0xFF); |
80 | 515k | } |
81 | 2.01k | } |
82 | | |
83 | 8.28k | len = (s->depth * avctx->width + 7) >> 3; |
84 | 8.28k | alen = len + (len & 1); |
85 | 8.28k | ptr = pixels; |
86 | | |
87 | 8.28k | if (s->type == RT_BYTE_ENCODED) { |
88 | 8.28k | uint8_t value, value2; |
89 | 8.28k | int run; |
90 | | |
91 | 8.28k | ptr = pixels; |
92 | | |
93 | 29.8M | #define GET_VALUE y >= avctx->height ? 0 : x >= len ? ptr[len-1] : ptr[x] |
94 | | |
95 | 8.28k | x = 0, y = 0; |
96 | 8.28k | value2 = GET_VALUE; |
97 | 3.72M | while (y < avctx->height) { |
98 | 3.71M | run = 1; |
99 | 3.71M | value = value2; |
100 | 3.71M | x++; |
101 | 3.71M | if (x >= alen) { |
102 | 24.4k | x = 0; |
103 | 24.4k | ptr += linesize, y++; |
104 | 24.4k | } |
105 | | |
106 | 3.71M | value2 = GET_VALUE; |
107 | 29.7M | while (value2 == value && run < 256 && y < avctx->height) { |
108 | 26.0M | x++; |
109 | 26.0M | run++; |
110 | 26.0M | if (x >= alen) { |
111 | 1.77M | x = 0; |
112 | 1.77M | ptr += linesize, y++; |
113 | 1.77M | } |
114 | 26.0M | value2 = GET_VALUE; |
115 | 26.0M | } |
116 | | |
117 | 3.71M | if (run > 2 || value == RLE_TRIGGER) { |
118 | 383k | bytestream2_put_byteu(&s->p, RLE_TRIGGER); |
119 | 383k | bytestream2_put_byteu(&s->p, run - 1); |
120 | 383k | if (run > 1) |
121 | 368k | bytestream2_put_byteu(&s->p, value); |
122 | 3.33M | } else if (run == 1) { |
123 | 3.21M | bytestream2_put_byteu(&s->p, value); |
124 | 3.21M | } else |
125 | 119k | bytestream2_put_be16u(&s->p, (value << 8) | value); |
126 | 3.71M | } |
127 | | |
128 | | // update data length for header |
129 | 8.28k | s->length = bytestream2_tell_p(&s->p) - 32 - s->maplength; |
130 | 8.28k | } else { |
131 | 0 | for (y = 0; y < avctx->height; y++) { |
132 | 0 | bytestream2_put_buffer(&s->p, ptr, len); |
133 | 0 | if (len < alen) |
134 | 0 | bytestream2_put_byteu(&s->p, 0); |
135 | 0 | ptr += linesize; |
136 | 0 | } |
137 | 0 | } |
138 | 8.28k | } |
139 | | |
140 | | static av_cold int sunrast_encode_init(AVCodecContext *avctx) |
141 | 248 | { |
142 | 248 | SUNRASTContext *s = avctx->priv_data; |
143 | | |
144 | | // adjust boolean option to RT equivalent |
145 | 248 | s->type++; |
146 | | |
147 | 248 | s->maptype = RMT_NONE; |
148 | 248 | s->maplength = 0; |
149 | | |
150 | 248 | switch (avctx->pix_fmt) { |
151 | 90 | case AV_PIX_FMT_MONOWHITE: |
152 | 90 | s->depth = 1; |
153 | 90 | break; |
154 | 55 | case AV_PIX_FMT_PAL8 : |
155 | 55 | s->maptype = RMT_EQUAL_RGB; |
156 | 55 | s->maplength = 3 * 256; |
157 | | /* fall-through */ |
158 | 72 | case AV_PIX_FMT_GRAY8: |
159 | 72 | s->depth = 8; |
160 | 72 | break; |
161 | 86 | case AV_PIX_FMT_BGR24: |
162 | 86 | s->depth = 24; |
163 | 86 | break; |
164 | 0 | default: |
165 | 0 | return AVERROR_BUG; |
166 | 248 | } |
167 | 248 | s->length = avctx->height * (FFALIGN(avctx->width * s->depth, 16) >> 3); |
168 | 248 | s->size = 32 + s->maplength + s->length * s->type; |
169 | | |
170 | 248 | return 0; |
171 | 248 | } |
172 | | |
173 | | static int sunrast_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, |
174 | | const AVFrame *frame, int *got_packet_ptr) |
175 | 8.28k | { |
176 | 8.28k | SUNRASTContext *s = avctx->priv_data; |
177 | 8.28k | int ret; |
178 | | |
179 | 8.28k | if ((ret = ff_alloc_packet(avctx, avpkt, s->size)) < 0) |
180 | 0 | return ret; |
181 | | |
182 | 8.28k | bytestream2_init_writer(&s->p, avpkt->data, avpkt->size); |
183 | 8.28k | sunrast_image_write_header(avctx); |
184 | 8.28k | sunrast_image_write_image(avctx, frame->data[0], |
185 | 8.28k | (const uint32_t *)frame->data[1], |
186 | 8.28k | frame->linesize[0]); |
187 | | // update data length in header after RLE |
188 | 8.28k | if (s->type == RT_BYTE_ENCODED) |
189 | 8.28k | AV_WB32(&avpkt->data[16], s->length); |
190 | | |
191 | 8.28k | *got_packet_ptr = 1; |
192 | 8.28k | avpkt->size = bytestream2_tell_p(&s->p); |
193 | 8.28k | return 0; |
194 | 8.28k | } |
195 | | |
196 | | #define OFFSET(x) offsetof(SUNRASTContext, x) |
197 | | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
198 | | static const AVOption options[] = { |
199 | | { "rle", "Use run-length compression", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, |
200 | | |
201 | | { NULL }, |
202 | | }; |
203 | | |
204 | | static const AVClass sunrast_class = { |
205 | | .class_name = "sunrast", |
206 | | .item_name = av_default_item_name, |
207 | | .option = options, |
208 | | .version = LIBAVUTIL_VERSION_INT, |
209 | | }; |
210 | | |
211 | | const FFCodec ff_sunrast_encoder = { |
212 | | .p.name = "sunrast", |
213 | | CODEC_LONG_NAME("Sun Rasterfile image"), |
214 | | .p.type = AVMEDIA_TYPE_VIDEO, |
215 | | .p.id = AV_CODEC_ID_SUNRAST, |
216 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
217 | | .priv_data_size = sizeof(SUNRASTContext), |
218 | | .init = sunrast_encode_init, |
219 | | FF_CODEC_ENCODE_CB(sunrast_encode_frame), |
220 | | .p.priv_class = &sunrast_class, |
221 | | CODEC_PIXFMTS(AV_PIX_FMT_BGR24, |
222 | | AV_PIX_FMT_PAL8, |
223 | | AV_PIX_FMT_GRAY8, |
224 | | AV_PIX_FMT_MONOWHITE), |
225 | | }; |