Coverage Report

Created: 2025-11-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/rl2.c
Line
Count
Source
1
/*
2
 * RL2 Video Decoder
3
 * Copyright (C) 2008 Sascha Sommer (saschasommer@freenet.de)
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
/**
23
 * @file
24
 * RL2 Video Decoder
25
 * @author Sascha Sommer (saschasommer@freenet.de)
26
 * @see http://wiki.multimedia.cx/index.php?title=RL2
27
 */
28
29
#include <string.h>
30
31
#include "libavutil/internal.h"
32
#include "libavutil/intreadwrite.h"
33
#include "libavutil/mem.h"
34
#include "avcodec.h"
35
#include "codec_internal.h"
36
#include "decode.h"
37
38
39
701
#define EXTRADATA1_SIZE (6 + 256 * 3) ///< video base, clr count, palette
40
41
typedef struct Rl2Context {
42
    AVCodecContext *avctx;
43
44
    uint16_t video_base;  ///< initial drawing offset
45
    uint32_t clr_count;   ///< number of used colors (currently unused)
46
    uint8_t *back_frame;  ///< background frame
47
    uint32_t palette[AVPALETTE_COUNT];
48
} Rl2Context;
49
50
/**
51
 * Run Length Decode a single 320x200 frame
52
 * @param s rl2 context
53
 * @param in input buffer
54
 * @param size input buffer size
55
 * @param out output buffer
56
 * @param stride stride of the output buffer
57
 * @param video_base offset of the rle data inside the frame
58
 */
59
static void rl2_rle_decode(Rl2Context *s, const uint8_t *in, int size,
60
                           uint8_t *out, ptrdiff_t stride, int video_base)
61
161k
{
62
161k
    int base_x = video_base % s->avctx->width;
63
161k
    int base_y = video_base / s->avctx->width;
64
161k
    ptrdiff_t stride_adj = stride - s->avctx->width;
65
161k
    const uint8_t *back_frame = s->back_frame;
66
161k
    const uint8_t *in_end     = in + size;
67
161k
    const uint8_t *out_end    = out + stride * s->avctx->height - stride_adj;
68
161k
    uint8_t *line_end;
69
70
    /** copy start of the background frame */
71
161k
    if (s->back_frame) {
72
10.1M
        for (int i = 0; i <= base_y; i++) {
73
10.0M
            memcpy(out, back_frame, s->avctx->width);
74
10.0M
            out        += stride;
75
10.0M
            back_frame += s->avctx->width;
76
10.0M
        }
77
155k
        back_frame += base_x - s->avctx->width;
78
155k
    } else {
79
5.18k
        out += stride * (base_y + 1);
80
5.18k
    }
81
161k
    line_end    = out - stride_adj;
82
161k
    out        += base_x - stride;
83
84
    /** decode the variable part of the frame */
85
446k
    while (in < in_end) {
86
321k
        uint8_t val = *in++;
87
321k
        int len     = 1;
88
321k
        if (val >= 0x80) {
89
71.8k
            if (in >= in_end)
90
29.9k
                break;
91
41.9k
            len = *in++;
92
41.9k
            if (!len)
93
4.33k
                break;
94
37.5k
            val &= 0x7F;
95
37.5k
        }
96
97
286k
        if (back_frame) {
98
240k
            if (!val) {
99
111k
                do {
100
111k
                    size_t copy = FFMIN(line_end - out, len);
101
111k
                    memcpy(out, back_frame, copy);
102
111k
                    out        += copy;
103
111k
                    back_frame += copy;
104
111k
                    len        -= copy;
105
111k
                    if (out == line_end) {
106
911
                        if (out == out_end)
107
254
                            return;
108
657
                        out      += stride_adj;
109
657
                        line_end += stride;
110
657
                    }
111
111k
                } while (len > 0);
112
110k
                continue;
113
110k
            }
114
129k
            back_frame += len;
115
129k
            val |= 0x80;
116
129k
        }
117
118
5.91M
        while (len--) {
119
5.74M
            *out++ = val;
120
5.74M
            if (out == line_end) {
121
12.4k
                if (out == out_end)
122
1.53k
                    return;
123
10.9k
                out      += stride_adj;
124
10.9k
                line_end += stride;
125
10.9k
            }
126
5.74M
        }
127
176k
    }
128
129
    /** copy the rest from the background frame */
130
159k
    if (s->back_frame) {
131
21.3M
        while (1) {
132
21.3M
            memcpy(out, back_frame, line_end - out);
133
21.3M
            if (line_end == out_end)
134
155k
                break;
135
21.1M
            back_frame += line_end - out;
136
21.1M
            out         = line_end + stride_adj;
137
21.1M
            line_end   += stride;
138
21.1M
        }
139
155k
    }
140
159k
}
141
142
143
/**
144
 * Initialize the decoder
145
 * @param avctx decoder context
146
 * @return 0 success, -1 on error
147
 */
148
static av_cold int rl2_decode_init(AVCodecContext *avctx)
149
464
{
150
464
    Rl2Context *s = avctx->priv_data;
151
464
    int back_size;
152
464
    int i;
153
464
    int ret;
154
155
464
    s->avctx       = avctx;
156
464
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
157
158
464
    ret = ff_set_dimensions(avctx, 320, 200);
159
464
    if (ret < 0)
160
0
        return ret;
161
162
    /** parse extra data */
163
464
    if (!avctx->extradata || avctx->extradata_size < EXTRADATA1_SIZE) {
164
203
        av_log(avctx, AV_LOG_ERROR, "invalid extradata size\n");
165
203
        return AVERROR(EINVAL);
166
203
    }
167
168
    /** get frame_offset */
169
261
    s->video_base = AV_RL16(&avctx->extradata[0]);
170
261
    s->clr_count  = AV_RL32(&avctx->extradata[2]);
171
172
261
    if (s->video_base >= avctx->width * avctx->height) {
173
3
        av_log(avctx, AV_LOG_ERROR, "invalid video_base\n");
174
3
        return AVERROR_INVALIDDATA;
175
3
    }
176
177
    /** initialize palette */
178
66.3k
    for (i = 0; i < AVPALETTE_COUNT; i++)
179
66.0k
        s->palette[i] = 0xFFU << 24 | AV_RB24(&avctx->extradata[6 + i * 3]);
180
181
    /** decode background frame if present */
182
258
    back_size = avctx->extradata_size - EXTRADATA1_SIZE;
183
184
258
    if (back_size > 0) {
185
        /* The 254 are padding to ensure that pointer arithmetic stays within
186
         * the buffer. */
187
138
        uint8_t *back_frame = av_mallocz(avctx->width * avctx->height + 254);
188
138
        if (!back_frame)
189
0
            return AVERROR(ENOMEM);
190
138
        rl2_rle_decode(s, avctx->extradata + EXTRADATA1_SIZE, back_size,
191
138
                       back_frame, avctx->width, 0);
192
138
        s->back_frame = back_frame;
193
138
    }
194
258
    return 0;
195
258
}
196
197
198
static int rl2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
199
                            int *got_frame, AVPacket *avpkt)
200
161k
{
201
161k
    const uint8_t *buf = avpkt->data;
202
161k
    int ret, buf_size  = avpkt->size;
203
161k
    Rl2Context *s = avctx->priv_data;
204
205
161k
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
206
0
        return ret;
207
208
    /** run length decode */
209
161k
    rl2_rle_decode(s, buf, buf_size, frame->data[0], frame->linesize[0],
210
161k
                   s->video_base);
211
212
    /** make the palette available on the way out */
213
161k
    memcpy(frame->data[1], s->palette, AVPALETTE_SIZE);
214
215
161k
    *got_frame = 1;
216
217
    /** report that the buffer was completely consumed */
218
161k
    return buf_size;
219
161k
}
220
221
222
/**
223
 * Uninit decoder
224
 * @param avctx decoder context
225
 * @return 0 success, -1 on error
226
 */
227
static av_cold int rl2_decode_end(AVCodecContext *avctx)
228
258
{
229
258
    Rl2Context *s = avctx->priv_data;
230
231
258
    av_freep(&s->back_frame);
232
233
258
    return 0;
234
258
}
235
236
237
const FFCodec ff_rl2_decoder = {
238
    .p.name         = "rl2",
239
    CODEC_LONG_NAME("RL2 video"),
240
    .p.type         = AVMEDIA_TYPE_VIDEO,
241
    .p.id           = AV_CODEC_ID_RL2,
242
    .priv_data_size = sizeof(Rl2Context),
243
    .init           = rl2_decode_init,
244
    .close          = rl2_decode_end,
245
    FF_CODEC_DECODE_CB(rl2_decode_frame),
246
    .p.capabilities = AV_CODEC_CAP_DR1,
247
};