FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/msrleenc.c
Date: 2025-10-10 03:51:19
Exec Total Coverage
Lines: 126 154 81.8%
Functions: 9 9 100.0%
Branches: 56 72 77.8%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2023 Tomas Härdin
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * MSRLE encoder
24 * @see https://wiki.multimedia.cx/index.php?title=Microsoft_RLE
25 */
26
27 // TODO: pal4 mode?
28
29 #include "bytestream.h"
30 #include "codec_internal.h"
31 #include "encode.h"
32
33 #include "libavutil/attributes.h"
34
35 typedef struct MSRLEContext {
36 int curframe;
37 AVFrame *last_frame;
38 } MSRLEContext;
39
40 4 static av_cold int msrle_encode_init(AVCodecContext *avctx)
41 {
42 4 MSRLEContext *s = avctx->priv_data;
43
44 4 avctx->bits_per_coded_sample = 8;
45 4 s->last_frame = av_frame_alloc();
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!s->last_frame)
47 return AVERROR(ENOMEM);
48
49 4 return 0;
50 }
51
52 422558 static void write_run(AVCodecContext *avctx, uint8_t **data, int len, int value)
53 {
54 // we're allowed to write odd runs
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422558 times.
422558 while (len >= 255) {
56 bytestream_put_byte(data, 255);
57 bytestream_put_byte(data, value);
58 len -= 255;
59 }
60
1/2
✓ Branch 0 taken 422558 times.
✗ Branch 1 not taken.
422558 if (len >= 1) {
61 // this is wasteful when len == 1 and sometimes when len == 2
62 // but sometimes we have no choice. also write_absolute()
63 // relies on this
64 422558 bytestream_put_byte(data, len);
65 422558 bytestream_put_byte(data, value);
66 }
67 422558 }
68
69 610297 static void write_absolute(AVCodecContext *avctx, uint8_t **data,
70 const uint8_t *line, int len)
71 {
72 // writing 255 would be wasteful here due to the padding requirement
73
2/2
✓ Branch 0 taken 3016 times.
✓ Branch 1 taken 610297 times.
613313 while (len >= 254) {
74 3016 bytestream_put_byte(data, 0);
75 3016 bytestream_put_byte(data, 254);
76 3016 bytestream_put_buffer(data, line, 254);
77 3016 line += 254;
78 3016 len -= 254;
79 }
80
2/2
✓ Branch 0 taken 95987 times.
✓ Branch 1 taken 514310 times.
610297 if (len == 1) {
81 // it's less wasteful to write single pixels as runs
82 // not to mention that absolute mode requires >= 3 pixels
83 95987 write_run(avctx, data, 1, line[0]);
84
2/2
✓ Branch 0 taken 28683 times.
✓ Branch 1 taken 485627 times.
514310 } else if (len == 2) {
85 28683 write_run(avctx, data, 1, line[0]);
86 28683 write_run(avctx, data, 1, line[1]);
87
2/2
✓ Branch 0 taken 463998 times.
✓ Branch 1 taken 21629 times.
485627 } else if (len > 0) {
88 463998 bytestream_put_byte(data, 0);
89 463998 bytestream_put_byte(data, len);
90 463998 bytestream_put_buffer(data, line, len);
91
2/2
✓ Branch 0 taken 239120 times.
✓ Branch 1 taken 224878 times.
463998 if (len & 1)
92 239120 bytestream_put_byte(data, 0);
93 }
94 610297 }
95
96 311281 static void write_delta(AVCodecContext *avctx, uint8_t **data, int delta)
97 {
98 // we let the yskip logic handle the case where we want to delta
99 // to following lines. it's not perfect but it's easier than finding
100 // the optimal combination of end-of-lines and deltas to reach any
101 // following position including places where dx < 0
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 311281 times.
311281 while (delta >= 255) {
103 bytestream_put_byte(data, 0);
104 bytestream_put_byte(data, 2);
105 bytestream_put_byte(data, 255);
106 bytestream_put_byte(data, 0);
107 delta -= 255;
108 }
109
1/2
✓ Branch 0 taken 311281 times.
✗ Branch 1 not taken.
311281 if (delta > 0) {
110 311281 bytestream_put_byte(data, 0);
111 311281 bytestream_put_byte(data, 2);
112 311281 bytestream_put_byte(data, delta);
113 311281 bytestream_put_byte(data, 0);
114 }
115 311281 }
116
117 659907 static void write_yskip(AVCodecContext *avctx, uint8_t **data, int yskip)
118 {
119
1/2
✓ Branch 0 taken 659907 times.
✗ Branch 1 not taken.
659907 if (yskip < 4)
120 659907 return;
121 // we have yskip*2 nul bytess
122 *data -= 2*yskip;
123 // the end-of-line counts as one skip
124 yskip--;
125 while (yskip >= 255) {
126 bytestream_put_byte(data, 0);
127 bytestream_put_byte(data, 2);
128 bytestream_put_byte(data, 0);
129 bytestream_put_byte(data, 255);
130 yskip -= 255;
131 }
132 if (yskip > 0) {
133 bytestream_put_byte(data, 0);
134 bytestream_put_byte(data, 2);
135 bytestream_put_byte(data, 0);
136 bytestream_put_byte(data, yskip);
137 }
138 bytestream_put_be16(data, 0x0000);
139 }
140
141 // used both to encode lines in keyframes and to encode lines between deltas
142 352796 static void encode_line(AVCodecContext *avctx, uint8_t **data,
143 const uint8_t *line, int length)
144 {
145 352796 int run = 0, last = -1, absstart = 0;
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 352796 times.
352796 if (length == 0)
147 return;
148
2/2
✓ Branch 0 taken 12285392 times.
✓ Branch 1 taken 352796 times.
12638188 for (int x = 0; x < length; x++) {
149
2/2
✓ Branch 0 taken 1279883 times.
✓ Branch 1 taken 11005509 times.
12285392 if (last == line[x]) {
150 1279883 run++;
151
2/2
✓ Branch 0 taken 269205 times.
✓ Branch 1 taken 1010678 times.
1279883 if (run == 3)
152 269205 write_absolute(avctx, data, &line[absstart], x - absstart - 2);
153 } else {
154
2/2
✓ Branch 0 taken 257501 times.
✓ Branch 1 taken 10748008 times.
11005509 if (run >= 3) {
155 257501 write_run(avctx, data, run, last);
156 257501 absstart = x;
157 }
158 11005509 run = 1;
159 }
160 12285392 last = line[x];
161 }
162
2/2
✓ Branch 0 taken 11704 times.
✓ Branch 1 taken 341092 times.
352796 if (run >= 3)
163 11704 write_run(avctx, data, run, last);
164 else
165 341092 write_absolute(avctx, data, &line[absstart], length - absstart);
166 }
167
168 200 static int encode(AVCodecContext *avctx, AVPacket *pkt,
169 const AVFrame *pict, int keyframe, int *got_keyframe)
170 {
171 200 MSRLEContext *s = avctx->priv_data;
172 200 uint8_t *data = pkt->data;
173
174 /* Compare the current frame to the last frame, or code the entire frame
175 if keyframe != 0. We're continually outputting pairs of bytes:
176
177 00 00 end of line
178 00 01 end of bitmap
179 00 02 dx dy delta. move pointer to x+dx, y+dy
180 00 ll dd dd .. absolute (verbatim) mode. ll >= 3
181 rr dd run. rr >= 1
182
183 For keyframes we only have absolute mode and runs at our disposal, and
184 we are not allowed to end a line early. If this happens when keyframe == 0
185 then *got_keyframe is set to 1 and s->curframe is reset.
186 */
187 200 *got_keyframe = 1; // set to zero whenever we use a feature that makes this a not-keyframe
188
189
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 184 times.
200 if (keyframe) {
190
2/2
✓ Branch 0 taken 4354 times.
✓ Branch 1 taken 16 times.
4370 for (int y = avctx->height-1; y >= 0; y--) {
191 4354 uint8_t *line = &pict->data[0][y*pict->linesize[0]];
192 4354 encode_line(avctx, &data, line, avctx->width);
193 4354 bytestream_put_be16(&data, 0x0000); // end of line
194 }
195 } else {
196 // compare to previous frame
197 184 int yskip = 0; // we can encode large skips using deltas
198
2/2
✓ Branch 0 taken 40546 times.
✓ Branch 1 taken 184 times.
40730 for (int y = avctx->height-1; y >= 0; y--) {
199 40546 const uint8_t *line = &pict->data[0][y*pict->linesize[0]];
200 40546 const uint8_t *prev = &s->last_frame->data[0][y*s->last_frame->linesize[0]];
201 // we need at least 5 pixels in a row for a delta to be worthwhile
202 40546 int delta = 0, linestart = 0, encoded = 0;
203
2/2
✓ Branch 0 taken 13742404 times.
✓ Branch 1 taken 40546 times.
13782950 for (int x = 0; x < avctx->width; x++) {
204
2/2
✓ Branch 0 taken 5361836 times.
✓ Branch 1 taken 8380568 times.
13742404 if (line[x] == prev[x]) {
205 5361836 delta++;
206
2/2
✓ Branch 0 taken 313829 times.
✓ Branch 1 taken 5048007 times.
5361836 if (delta == 5) {
207 313829 int len = x - linestart - 4;
208
2/2
✓ Branch 0 taken 310444 times.
✓ Branch 1 taken 3385 times.
313829 if (len > 0) {
209 310444 write_yskip(avctx, &data, yskip);
210 310444 yskip = 0;
211 310444 encode_line(avctx, &data, &line[linestart], len);
212 310444 encoded = 1;
213 }
214 313829 linestart = -1;
215 }
216 } else {
217
2/2
✓ Branch 0 taken 311281 times.
✓ Branch 1 taken 8069287 times.
8380568 if (delta >= 5) {
218 311281 write_yskip(avctx, &data, yskip);
219 311281 yskip = 0;
220 311281 write_delta(avctx, &data, delta);
221 311281 *got_keyframe = 0;
222 311281 encoded = 1;
223 }
224 8380568 delta = 0;
225
2/2
✓ Branch 0 taken 311281 times.
✓ Branch 1 taken 8069287 times.
8380568 if (linestart == -1)
226 311281 linestart = x;
227 }
228 }
229
2/2
✓ Branch 0 taken 37998 times.
✓ Branch 1 taken 2548 times.
40546 if (delta < 5) {
230 37998 write_yskip(avctx, &data, yskip);
231 37998 yskip = 0;
232 37998 encode_line(avctx, &data, &line[linestart], avctx->width - linestart);
233 37998 encoded = 1;
234 } else
235 2548 *got_keyframe = 0;
236 40546 bytestream_put_be16(&data, 0x0000); // end of line
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40546 times.
40546 if (!encoded)
238 yskip++;
239 else
240 40546 yskip = 0;
241 }
242 184 write_yskip(avctx, &data, yskip);
243 }
244 200 bytestream_put_be16(&data, 0x0001); // end of bitmap
245 200 pkt->size = data - pkt->data;
246 200 return 0;
247 }
248
249 200 static int msrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
250 const AVFrame *pict, int *got_packet)
251 {
252 200 MSRLEContext *s = avctx->priv_data;
253 int ret, got_keyframe;
254
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if ((ret = ff_alloc_packet(avctx, pkt, (
256 200 avctx->width*2 /* worst case = rle every pixel */ + 2 /*end of line */
257 200 ) * avctx->height + 2 /* end of bitmap */ + FF_INPUT_BUFFER_MIN_SIZE)))
258 return ret;
259
260
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (pict->data[1]) {
261 200 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (!side_data)
263 return AVERROR(ENOMEM);
264 200 memcpy(side_data, pict->data[1], AVPALETTE_SIZE);
265 }
266
267
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
200 if ((ret = encode(avctx, pkt, pict, s->curframe == 0, &got_keyframe)))
268 return ret;
269
270
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 145 times.
200 if (got_keyframe) {
271 55 pkt->flags |= AV_PKT_FLAG_KEY;
272 55 s->curframe = 0;
273 }
274
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 188 times.
200 if (++s->curframe >= avctx->gop_size)
275 12 s->curframe = 0;
276 200 *got_packet = 1;
277
278 200 return av_frame_replace(s->last_frame, pict);
279 }
280
281 4 static av_cold int msrle_encode_close(AVCodecContext *avctx)
282 {
283 4 MSRLEContext *s = avctx->priv_data;
284 4 av_frame_free(&s->last_frame);
285 4 return 0;
286 }
287
288 const FFCodec ff_msrle_encoder = {
289 .p.name = "msrle",
290 CODEC_LONG_NAME("Microsoft RLE"),
291 .p.type = AVMEDIA_TYPE_VIDEO,
292 .p.id = AV_CODEC_ID_MSRLE,
293 .p.capabilities = AV_CODEC_CAP_DR1,
294 .priv_data_size = sizeof(MSRLEContext),
295 .init = msrle_encode_init,
296 FF_CODEC_ENCODE_CB(msrle_encode_frame),
297 .close = msrle_encode_close,
298 CODEC_PIXFMTS(AV_PIX_FMT_PAL8),
299 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
300 };
301