FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/sunrastenc.c
Date: 2026-04-29 17:33:30
Exec Total Coverage
Lines: 71 98 72.4%
Functions: 4 4 100.0%
Branches: 28 51 54.9%

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