Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/c93.c
Line
Count
Source
1
/*
2
 * Interplay C93 demuxer
3
 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
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
#include "avformat.h"
23
#include "avio_internal.h"
24
#include "demux.h"
25
#include "internal.h"
26
#include "voc.h"
27
#include "libavutil/intreadwrite.h"
28
29
typedef struct C93BlockRecord {
30
    uint16_t index;
31
    uint8_t length;
32
    uint8_t frames;
33
} C93BlockRecord;
34
35
typedef struct C93DemuxContext {
36
    VocDecContext voc;
37
38
    C93BlockRecord block_records[512];
39
    int current_block;
40
41
    uint32_t frame_offsets[32];
42
    int current_frame;
43
    int next_pkt_is_audio;
44
45
    AVStream *audio;
46
} C93DemuxContext;
47
48
static int probe(const AVProbeData *p)
49
967k
{
50
967k
    int i;
51
967k
    int index = 1;
52
967k
    if (p->buf_size < 16)
53
144k
        return 0;
54
827k
    for (i = 0; i < 16; i += 4) {
55
827k
        if (AV_RL16(p->buf + i) != index || !p->buf[i + 2] || !p->buf[i + 3])
56
823k
            return 0;
57
4.03k
        index += p->buf[i + 2];
58
4.03k
    }
59
143
    return AVPROBE_SCORE_MAX;
60
823k
}
61
62
static int read_header(AVFormatContext *s)
63
2.43k
{
64
2.43k
    AVStream *video;
65
2.43k
    AVIOContext *pb = s->pb;
66
2.43k
    C93DemuxContext *c93 = s->priv_data;
67
2.43k
    int i;
68
2.43k
    int framecount = 0;
69
70
1.21M
    for (i = 0; i < 512; i++) {
71
1.21M
        c93->block_records[i].index = avio_rl16(pb);
72
1.21M
        c93->block_records[i].length = avio_r8(pb);
73
1.21M
        c93->block_records[i].frames = avio_r8(pb);
74
1.21M
        if (c93->block_records[i].frames > 32) {
75
64
            av_log(s, AV_LOG_ERROR, "too many frames in block\n");
76
64
            return AVERROR_INVALIDDATA;
77
64
        }
78
1.21M
        framecount += c93->block_records[i].frames;
79
1.21M
    }
80
81
    /* Audio streams are added if audio packets are found */
82
2.36k
    s->ctx_flags |= AVFMTCTX_NOHEADER;
83
84
2.36k
    video = avformat_new_stream(s, NULL);
85
2.36k
    if (!video)
86
0
        return AVERROR(ENOMEM);
87
88
2.36k
    video->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
89
2.36k
    video->codecpar->codec_id = AV_CODEC_ID_C93;
90
2.36k
    video->codecpar->width = 320;
91
2.36k
    video->codecpar->height = 192;
92
    /* 4:3 320x200 with 8 empty lines */
93
2.36k
    video->sample_aspect_ratio = (AVRational) { 5, 6 };
94
2.36k
    avpriv_set_pts_info(video, 64, 2, 25);
95
2.36k
    video->nb_frames = framecount;
96
2.36k
    video->duration = framecount;
97
2.36k
    video->start_time = 0;
98
99
2.36k
    c93->current_block = 0;
100
2.36k
    c93->current_frame = 0;
101
2.36k
    c93->next_pkt_is_audio = 0;
102
2.36k
    return 0;
103
2.36k
}
104
105
7.09k
#define C93_HAS_PALETTE 0x01
106
100
#define C93_FIRST_FRAME 0x02
107
108
static int read_packet(AVFormatContext *s, AVPacket *pkt)
109
91.4k
{
110
91.4k
    AVIOContext *pb = s->pb;
111
91.4k
    C93DemuxContext *c93 = s->priv_data;
112
91.4k
    C93BlockRecord *br = &c93->block_records[c93->current_block];
113
91.4k
    int datasize;
114
91.4k
    int ret, i;
115
116
91.4k
    if (c93->next_pkt_is_audio) {
117
60.5k
        c93->current_frame++;
118
60.5k
        c93->next_pkt_is_audio = 0;
119
60.5k
        datasize = avio_rl16(pb);
120
60.5k
        if (datasize > 42) {
121
42.7k
            if (!c93->audio) {
122
1.87k
                c93->audio = avformat_new_stream(s, NULL);
123
1.87k
                if (!c93->audio)
124
0
                    return AVERROR(ENOMEM);
125
1.87k
                c93->audio->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
126
1.87k
            }
127
42.7k
            avio_skip(pb, 26); /* VOC header */
128
42.7k
            ret = ff_voc_get_packet(s, pkt, c93->audio, datasize - 26);
129
42.7k
            if (ret > 0) {
130
26.4k
                pkt->stream_index = 1;
131
26.4k
                pkt->flags |= AV_PKT_FLAG_KEY;
132
26.4k
                return ret;
133
26.4k
            }
134
42.7k
        }
135
60.5k
    }
136
65.0k
    if (c93->current_frame >= br->frames) {
137
34.3k
        if (c93->current_block >= 511 || !br[1].length)
138
1.26k
            return AVERROR_EOF;
139
33.0k
        br++;
140
33.0k
        c93->current_block++;
141
33.0k
        c93->current_frame = 0;
142
33.0k
    }
143
144
63.8k
    if (c93->current_frame == 0) {
145
33.5k
        avio_seek(pb, br->index * 2048, SEEK_SET);
146
1.10M
        for (i = 0; i < 32; i++) {
147
1.07M
            c93->frame_offsets[i] = avio_rl32(pb);
148
1.07M
        }
149
33.5k
    }
150
151
63.8k
    avio_seek(pb,br->index * 2048 +
152
63.8k
            c93->frame_offsets[c93->current_frame], SEEK_SET);
153
63.8k
    datasize = avio_rl16(pb); /* video frame size */
154
155
63.8k
    ret = av_new_packet(pkt, datasize + 768 + 1);
156
63.8k
    if (ret < 0)
157
0
        return ret;
158
63.8k
    pkt->data[0] = 0;
159
63.8k
    pkt->size = datasize + 1;
160
161
63.8k
    ret = ffio_read_size(pb, pkt->data + 1, datasize);
162
63.8k
    if (ret < 0) {
163
3.02k
        return ret;
164
3.02k
    }
165
166
60.7k
    datasize = avio_rl16(pb); /* palette size */
167
60.7k
    if (datasize) {
168
7.28k
        if (datasize != 768) {
169
188
            av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize);
170
188
            return AVERROR_INVALIDDATA;
171
188
        }
172
7.09k
        pkt->data[0] |= C93_HAS_PALETTE;
173
7.09k
        ret = ffio_read_size(pb, pkt->data + pkt->size, datasize);
174
7.09k
        if (ret < 0) {
175
24
            return ret;
176
24
        }
177
7.06k
        pkt->size += 768;
178
7.06k
    }
179
60.5k
    pkt->stream_index = 0;
180
60.5k
    c93->next_pkt_is_audio = 1;
181
182
    /* only the first frame is guaranteed to not reference previous frames */
183
60.5k
    if (c93->current_block == 0 && c93->current_frame == 0) {
184
100
        pkt->flags |= AV_PKT_FLAG_KEY;
185
100
        pkt->data[0] |= C93_FIRST_FRAME;
186
100
    }
187
60.5k
    return 0;
188
60.7k
}
189
190
const FFInputFormat ff_c93_demuxer = {
191
    .p.name         = "c93",
192
    .p.long_name    = NULL_IF_CONFIG_SMALL("Interplay C93"),
193
    .priv_data_size = sizeof(C93DemuxContext),
194
    .read_probe     = probe,
195
    .read_header    = read_header,
196
    .read_packet    = read_packet,
197
};