FFmpeg coverage


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