Coverage Report

Created: 2026-01-16 07:48

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
895
{
37
895
    SimbiosisIMXContext *imx = avctx->priv_data;
38
39
895
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
40
895
    avctx->width   = 320;
41
895
    avctx->height  = 160;
42
43
895
    imx->frame = av_frame_alloc();
44
895
    if (!imx->frame)
45
0
        return AVERROR(ENOMEM);
46
47
895
    return 0;
48
895
}
49
50
static int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
51
                            int *got_frame, AVPacket *avpkt)
52
14.3k
{
53
14.3k
    SimbiosisIMXContext *imx = avctx->priv_data;
54
14.3k
    int ret, x, y;
55
14.3k
    AVFrame *frame = imx->frame;
56
14.3k
    GetByteContext gb;
57
58
14.3k
    if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
59
0
        return ret;
60
61
14.3k
    if (ff_copy_palette(imx->pal, avpkt, avctx)) {
62
0
        frame->flags |= AV_FRAME_FLAG_KEY;
63
14.3k
    } else {
64
14.3k
        frame->flags &= ~AV_FRAME_FLAG_KEY;
65
14.3k
    }
66
67
14.3k
    bytestream2_init(&gb, avpkt->data, avpkt->size);
68
69
14.3k
    memcpy(frame->data[1], imx->pal, AVPALETTE_SIZE);
70
71
14.3k
    x = 0, y = 0;
72
294k
    while (bytestream2_get_bytes_left(&gb) > 0 &&
73
281k
           x < 320 && y < 160) {
74
281k
        int b = bytestream2_get_byte(&gb);
75
281k
        int len = b & 0x3f;
76
281k
        int op = b >> 6;
77
281k
        int fill;
78
79
281k
        switch (op) {
80
15.0k
        case 3:
81
15.0k
            len = len * 64 + bytestream2_get_byte(&gb);
82
212k
        case 0:
83
54.9M
            while (len > 0) {
84
54.7M
                x++;
85
54.7M
                len--;
86
54.7M
                if (x >= 320) {
87
169k
                    x = 0;
88
169k
                    y++;
89
169k
                }
90
54.7M
                if (y >= 160)
91
373
                    break;
92
54.7M
            }
93
94
212k
            frame->flags &= ~AV_FRAME_FLAG_KEY;
95
212k
            break;
96
60.5k
        case 1:
97
60.5k
            if (len == 0) {
98
6.92k
                int offset = bytestream2_get_le16(&gb);
99
100
6.92k
                if (offset < 0 || offset >= 32768)
101
961
                    return AVERROR_INVALIDDATA;
102
103
5.96k
                len = bytestream2_get_byte(&gb);
104
220k
                while (len > 0 && offset < 32768) {
105
214k
                    frame->data[0][x + y * frame->linesize[0]] = imx->history[offset++];
106
214k
                    x++;
107
214k
                    len--;
108
214k
                    if (x >= 320) {
109
688
                        x = 0;
110
688
                        y++;
111
688
                    }
112
214k
                    if (y >= 160)
113
83
                        break;
114
214k
                }
115
116
5.96k
                frame->flags &= ~AV_FRAME_FLAG_KEY;
117
53.6k
            } else {
118
1.78M
                while (len > 0) {
119
1.72M
                    fill = bytestream2_get_byte(&gb);
120
1.72M
                    frame->data[0][x + y * frame->linesize[0]] = fill;
121
1.72M
                    if (imx->pos < 32768)
122
1.55M
                        imx->history[imx->pos++] = fill;
123
1.72M
                    x++;
124
1.72M
                    len--;
125
1.72M
                    if (x >= 320) {
126
4.91k
                        x = 0;
127
4.91k
                        y++;
128
4.91k
                    }
129
1.72M
                    if (y >= 160)
130
91
                        break;
131
1.72M
                }
132
53.6k
            }
133
59.6k
            break;
134
59.6k
        case 2:
135
8.11k
            fill = bytestream2_get_byte(&gb);
136
137
303k
            while (len > 0) {
138
295k
                frame->data[0][x + y * frame->linesize[0]] = fill;
139
295k
                x++;
140
295k
                len--;
141
295k
                if (x >= 320) {
142
880
                    x = 0;
143
880
                    y++;
144
880
                }
145
295k
                if (y >= 160)
146
70
                    break;
147
295k
            }
148
8.11k
            break;
149
281k
        }
150
281k
    }
151
152
13.4k
    frame->pict_type = (frame->flags & AV_FRAME_FLAG_KEY) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
153
154
13.4k
    if ((ret = av_frame_ref(rframe, frame)) < 0)
155
0
        return ret;
156
157
13.4k
    *got_frame = 1;
158
159
13.4k
    return avpkt->size;
160
13.4k
}
161
162
static av_cold void imx_decode_flush(AVCodecContext *avctx)
163
1.82k
{
164
1.82k
    SimbiosisIMXContext *imx = avctx->priv_data;
165
166
1.82k
    av_frame_unref(imx->frame);
167
1.82k
    imx->pos = 0;
168
1.82k
    memset(imx->pal, 0, sizeof(imx->pal));
169
1.82k
    memset(imx->history, 0, sizeof(imx->history));
170
1.82k
}
171
172
static av_cold int imx_decode_close(AVCodecContext *avctx)
173
895
{
174
895
    SimbiosisIMXContext *imx = avctx->priv_data;
175
176
895
    av_frame_free(&imx->frame);
177
178
895
    return 0;
179
895
}
180
181
const FFCodec ff_simbiosis_imx_decoder = {
182
    .p.name         = "simbiosis_imx",
183
    CODEC_LONG_NAME("Simbiosis Interactive IMX Video"),
184
    .p.type         = AVMEDIA_TYPE_VIDEO,
185
    .p.id           = AV_CODEC_ID_SIMBIOSIS_IMX,
186
    .priv_data_size = sizeof(SimbiosisIMXContext),
187
    .init           = imx_decode_init,
188
    FF_CODEC_DECODE_CB(imx_decode_frame),
189
    .close          = imx_decode_close,
190
    .flush          = imx_decode_flush,
191
    .p.capabilities = AV_CODEC_CAP_DR1,
192
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
193
};