FFmpeg
Loading...
Searching...
No Matches
msrleenc.c
Go to the documentation of this file.
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
34
39
41{
42 MSRLEContext *s = avctx->priv_data;
43
44 avctx->bits_per_coded_sample = 8;
45 s->last_frame = av_frame_alloc();
46 if (!s->last_frame)
47 return AVERROR(ENOMEM);
48
49 return 0;
50}
51
52static void write_run(AVCodecContext *avctx, uint8_t **data, int len, int value)
53{
54 // we're allowed to write odd runs
55 while (len >= 255) {
56 bytestream_put_byte(data, 255);
57 bytestream_put_byte(data, value);
58 len -= 255;
59 }
60 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 bytestream_put_byte(data, len);
65 bytestream_put_byte(data, value);
66 }
67}
68
69static 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 while (len >= 254) {
74 bytestream_put_byte(data, 0);
75 bytestream_put_byte(data, 254);
77 line += 254;
78 len -= 254;
79 }
80 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 write_run(avctx, data, 1, line[0]);
84 } else if (len == 2) {
85 write_run(avctx, data, 1, line[0]);
86 write_run(avctx, data, 1, line[1]);
87 } else if (len > 0) {
88 bytestream_put_byte(data, 0);
89 bytestream_put_byte(data, len);
91 if (len & 1)
92 bytestream_put_byte(data, 0);
93 }
94}
95
96static 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 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 if (delta > 0) {
110 bytestream_put_byte(data, 0);
111 bytestream_put_byte(data, 2);
112 bytestream_put_byte(data, delta);
113 bytestream_put_byte(data, 0);
114 }
115}
116
117static void write_yskip(AVCodecContext *avctx, uint8_t **data, int yskip)
118{
119 if (yskip < 4)
120 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
142static void encode_line(AVCodecContext *avctx, uint8_t **data,
143 const uint8_t *line, int length)
144{
145 int run = 0, last = -1, absstart = 0;
146 if (length == 0)
147 return;
148 for (int x = 0; x < length; x++) {
149 if (last == line[x]) {
150 run++;
151 if (run == 3)
152 write_absolute(avctx, data, &line[absstart], x - absstart - 2);
153 } else {
154 if (run >= 3) {
155 write_run(avctx, data, run, last);
156 absstart = x;
157 }
158 run = 1;
159 }
160 last = line[x];
161 }
162 if (run >= 3)
163 write_run(avctx, data, run, last);
164 else
165 write_absolute(avctx, data, &line[absstart], length - absstart);
166}
167
168static int encode(AVCodecContext *avctx, AVPacket *pkt,
169 const AVFrame *pict, int keyframe, int *got_keyframe)
170{
171 MSRLEContext *s = avctx->priv_data;
172 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 *got_keyframe = 1; // set to zero whenever we use a feature that makes this a not-keyframe
188
189 if (keyframe) {
190 for (int y = avctx->height-1; y >= 0; y--) {
191 uint8_t *line = &pict->data[0][y*pict->linesize[0]];
192 encode_line(avctx, &data, line, avctx->width);
193 bytestream_put_be16(&data, 0x0000); // end of line
194 }
195 } else {
196 // compare to previous frame
197 int yskip = 0; // we can encode large skips using deltas
198 for (int y = avctx->height-1; y >= 0; y--) {
199 const uint8_t *line = &pict->data[0][y*pict->linesize[0]];
200 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 int delta = 0, linestart = 0, encoded = 0;
203 for (int x = 0; x < avctx->width; x++) {
204 if (line[x] == prev[x]) {
205 delta++;
206 if (delta == 5) {
207 int len = x - linestart - 4;
208 if (len > 0) {
209 write_yskip(avctx, &data, yskip);
210 yskip = 0;
211 encode_line(avctx, &data, &line[linestart], len);
212 encoded = 1;
213 }
214 linestart = -1;
215 }
216 } else {
217 if (delta >= 5) {
218 write_yskip(avctx, &data, yskip);
219 yskip = 0;
220 write_delta(avctx, &data, delta);
221 *got_keyframe = 0;
222 encoded = 1;
223 }
224 delta = 0;
225 if (linestart == -1)
226 linestart = x;
227 }
228 }
229 if (delta < 5) {
230 write_yskip(avctx, &data, yskip);
231 yskip = 0;
232 encode_line(avctx, &data, &line[linestart], avctx->width - linestart);
233 encoded = 1;
234 } else
235 *got_keyframe = 0;
236 bytestream_put_be16(&data, 0x0000); // end of line
237 if (!encoded)
238 yskip++;
239 else
240 yskip = 0;
241 }
242 write_yskip(avctx, &data, yskip);
243 }
244 bytestream_put_be16(&data, 0x0001); // end of bitmap
245 pkt->size = data - pkt->data;
246 return 0;
247}
248
250 const AVFrame *pict, int *got_packet)
251{
252 MSRLEContext *s = avctx->priv_data;
253 int ret, got_keyframe;
254
255 if ((ret = ff_alloc_packet(avctx, pkt, (
256 avctx->width*2 /* worst case = rle every pixel */ + 2 /*end of line */
257 ) * avctx->height + 2 /* end of bitmap */ + FF_INPUT_BUFFER_MIN_SIZE)))
258 return ret;
259
260 if (pict->data[1]) {
262 if (!side_data)
263 return AVERROR(ENOMEM);
264 memcpy(side_data, pict->data[1], AVPALETTE_SIZE);
265 }
266
267 if ((ret = encode(avctx, pkt, pict, s->curframe == 0, &got_keyframe)))
268 return ret;
269
270 if (got_keyframe) {
271 pkt->flags |= AV_PKT_FLAG_KEY;
272 s->curframe = 0;
273 }
274 if (++s->curframe >= avctx->gop_size)
275 s->curframe = 0;
276 *got_packet = 1;
277
278 return av_frame_replace(s->last_frame, pict);
279}
280
282{
283 MSRLEContext *s = avctx->priv_data;
284 av_frame_free(&s->last_frame);
285 return 0;
286}
287
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),
297 .close = msrle_encode_close,
299 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
300};
const FFCodec ff_msrle_encoder
Definition msrleenc.c:288
static av_always_inline void bytestream_put_buffer(uint8_t **b, const uint8_t *src, unsigned int size)
Definition bytestream.h:372
#define s(width, name)
Definition cbs_vp9.c:198
#define CODEC_PIXFMTS(...)
#define FF_CODEC_ENCODE_CB(func)
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
static AVPacket * pkt
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
int ff_alloc_packet(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
Check AVPacket size and allocate data.
Definition encode.c:62
#define FF_INPUT_BUFFER_MIN_SIZE
Used by some encoders as upper bound for the length of headers.
Definition encode.h:34
double value
Definition eval.c:102
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_MSRLE
Definition codec_id.h:95
@ AV_PKT_DATA_PALETTE
An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE bytes worth of palette.
Definition packet.h:47
uint8_t * av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, size_t size)
Allocate new information of a packet.
Definition packet.c:231
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition packet.h:650
#define AVERROR(e)
Definition error.h:45
int av_frame_replace(AVFrame *dst, const AVFrame *src)
Ensure the destination frame refers to the same data described by the source frame,...
Definition frame.c:376
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
Macro definitions for various function/variable attributes.
#define av_cold
Definition attributes.h:117
static av_cold int msrle_encode_close(AVCodecContext *avctx)
Definition msrleenc.c:281
static void write_absolute(AVCodecContext *avctx, uint8_t **data, const uint8_t *line, int len)
Definition msrleenc.c:69
static void write_delta(AVCodecContext *avctx, uint8_t **data, int delta)
Definition msrleenc.c:96
static void encode_line(AVCodecContext *avctx, uint8_t **data, const uint8_t *line, int length)
Definition msrleenc.c:142
static int encode(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int keyframe, int *got_keyframe)
Definition msrleenc.c:168
static void write_yskip(AVCodecContext *avctx, uint8_t **data, int yskip)
Definition msrleenc.c:117
static int msrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet)
Definition msrleenc.c:249
static av_cold int msrle_encode_init(AVCodecContext *avctx)
Definition msrleenc.c:40
static void write_run(AVCodecContext *avctx, uint8_t **data, int len, int value)
Definition msrleenc.c:52
const char data[16]
Definition mxf.c:149
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition pixfmt.h:84
#define AVPALETTE_SIZE
Definition pixfmt.h:32
main external API structure.
Definition avcodec.h:443
int width
picture width / height.
Definition avcodec.h:604
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition avcodec.h:1564
int gop_size
the number of pictures in a group of pictures, or 0 for intra_only
Definition avcodec.h:1021
void * priv_data
Definition avcodec.h:470
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
This structure stores compressed data.
Definition packet.h:580
AVFrame * last_frame
Definition msrleenc.c:37
uint8_t run
Definition svq3.c:207
float delta
int len