Coverage Report

Created: 2026-09-14 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/imx.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2021 Paul B Mahol
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
#include "libavutil/attributes.h"
22
#include "libavutil/common.h"
23
#include "avcodec.h"
24
#include "bytestream.h"
25
#include "codec_internal.h"
26
#include "decode.h"
27
28
typedef struct SimbiosisIMXContext {
29
    AVFrame *frame;
30
    uint32_t pal[256];
31
    uint8_t history[32768];
32
    int pos;
33
} SimbiosisIMXContext;
34
35
static av_cold int imx_decode_init(AVCodecContext *avctx)
36
883
{
37
883
    SimbiosisIMXContext *imx = avctx->priv_data;
38
39
883
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
40
883
    avctx->width   = 320;
41
883
    avctx->height  = 160;
42
43
883
    imx->frame = av_frame_alloc();
44
883
    if (!imx->frame)
45
0
        return AVERROR(ENOMEM);
46
47
883
    return 0;
48
883
}
49
50
static int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
51
                            int *got_frame, AVPacket *avpkt)
52
15.7k
{
53
15.7k
    SimbiosisIMXContext *imx = avctx->priv_data;
54
15.7k
    int ret, x, y;
55
15.7k
    AVFrame *frame = imx->frame;
56
15.7k
    GetByteContext gb;
57
58
15.7k
    if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
59
2.87k
        return ret;
60
61
12.8k
    if (ff_copy_palette(imx->pal, avpkt, avctx)) {
62
0
        frame->flags |= AV_FRAME_FLAG_KEY;
63
12.8k
    } else {
64
12.8k
        frame->flags &= ~AV_FRAME_FLAG_KEY;
65
12.8k
    }
66
67
12.8k
    bytestream2_init(&gb, avpkt->data, avpkt->size);
68
69
12.8k
    memcpy(frame->data[1], imx->pal, AVPALETTE_SIZE);
70
71
12.8k
    x = 0, y = 0;
72
201k
    while (bytestream2_get_bytes_left(&gb) > 0 &&
73
189k
           x < 320 && y < 160) {
74
189k
        int b = bytestream2_get_byte(&gb);
75
189k
        int len = b & 0x3f;
76
189k
        int op = b >> 6;
77
189k
        int fill;
78
79
189k
        switch (op) {
80
11.7k
        case 3:
81
11.7k
            len = len * 64 + bytestream2_get_byte(&gb);
82
11.7k
            av_fallthrough;
83
129k
        case 0:
84
43.6M
            while (len > 0) {
85
43.5M
                x++;
86
43.5M
                len--;
87
43.5M
                if (x >= 320) {
88
134k
                    x = 0;
89
134k
                    y++;
90
134k
                }
91
43.5M
                if (y >= 160)
92
286
                    break;
93
43.5M
            }
94
95
129k
            frame->flags &= ~AV_FRAME_FLAG_KEY;
96
129k
            break;
97
53.7k
        case 1:
98
53.7k
            if (len == 0) {
99
5.85k
                int offset = bytestream2_get_le16(&gb);
100
101
5.85k
                if (offset < 0 || offset >= 32768)
102
936
                    return AVERROR_INVALIDDATA;
103
104
4.92k
                len = bytestream2_get_byte(&gb);
105
229k
                while (len > 0 && offset < 32768) {
106
225k
                    frame->data[0][x + y * frame->linesize[0]] = imx->history[offset++];
107
225k
                    x++;
108
225k
                    len--;
109
225k
                    if (x >= 320) {
110
727
                        x = 0;
111
727
                        y++;
112
727
                    }
113
225k
                    if (y >= 160)
114
69
                        break;
115
225k
                }
116
117
4.92k
                frame->flags &= ~AV_FRAME_FLAG_KEY;
118
47.8k
            } else {
119
1.61M
                while (len > 0) {
120
1.56M
                    fill = bytestream2_get_byte(&gb);
121
1.56M
                    frame->data[0][x + y * frame->linesize[0]] = fill;
122
1.56M
                    if (imx->pos < 32768)
123
1.42M
                        imx->history[imx->pos++] = fill;
124
1.56M
                    x++;
125
1.56M
                    len--;
126
1.56M
                    if (x >= 320) {
127
4.47k
                        x = 0;
128
4.47k
                        y++;
129
4.47k
                    }
130
1.56M
                    if (y >= 160)
131
86
                        break;
132
1.56M
                }
133
47.8k
            }
134
52.7k
            break;
135
52.7k
        case 2:
136
6.64k
            fill = bytestream2_get_byte(&gb);
137
138
239k
            while (len > 0) {
139
233k
                frame->data[0][x + y * frame->linesize[0]] = fill;
140
233k
                x++;
141
233k
                len--;
142
233k
                if (x >= 320) {
143
759
                    x = 0;
144
759
                    y++;
145
759
                }
146
233k
                if (y >= 160)
147
69
                    break;
148
233k
            }
149
6.64k
            break;
150
189k
        }
151
189k
    }
152
153
11.9k
    frame->pict_type = (frame->flags & AV_FRAME_FLAG_KEY) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
154
155
11.9k
    if ((ret = av_frame_ref(rframe, frame)) < 0)
156
0
        return ret;
157
158
11.9k
    *got_frame = 1;
159
160
11.9k
    return avpkt->size;
161
11.9k
}
162
163
static av_cold void imx_decode_flush(AVCodecContext *avctx)
164
2.34k
{
165
2.34k
    SimbiosisIMXContext *imx = avctx->priv_data;
166
167
2.34k
    av_frame_unref(imx->frame);
168
2.34k
    imx->pos = 0;
169
2.34k
    memset(imx->pal, 0, sizeof(imx->pal));
170
2.34k
    memset(imx->history, 0, sizeof(imx->history));
171
2.34k
}
172
173
static av_cold int imx_decode_close(AVCodecContext *avctx)
174
883
{
175
883
    SimbiosisIMXContext *imx = avctx->priv_data;
176
177
883
    av_frame_free(&imx->frame);
178
179
883
    return 0;
180
883
}
181
182
const FFCodec ff_simbiosis_imx_decoder = {
183
    .p.name         = "simbiosis_imx",
184
    CODEC_LONG_NAME("Simbiosis Interactive IMX Video"),
185
    .p.type         = AVMEDIA_TYPE_VIDEO,
186
    .p.id           = AV_CODEC_ID_SIMBIOSIS_IMX,
187
    .priv_data_size = sizeof(SimbiosisIMXContext),
188
    .init           = imx_decode_init,
189
    FF_CODEC_DECODE_CB(imx_decode_frame),
190
    .close          = imx_decode_close,
191
    .flush          = imx_decode_flush,
192
    .p.capabilities = AV_CODEC_CAP_DR1,
193
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
194
};