Coverage Report

Created: 2025-11-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/segafilm.c
Line
Count
Source
1
/*
2
 * Sega FILM Format (CPK) Demuxer
3
 * Copyright (c) 2003 The FFmpeg project
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
 * Sega FILM (.cpk) file demuxer
25
 * by Mike Melanson (melanson@pcisys.net)
26
 * For more information regarding the Sega FILM file format, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28
 */
29
30
#include "libavutil/intreadwrite.h"
31
#include "libavutil/mem.h"
32
#include "avformat.h"
33
#include "demux.h"
34
#include "internal.h"
35
36
964k
#define FILM_TAG MKBETAG('F', 'I', 'L', 'M')
37
3.23k
#define FDSC_TAG MKBETAG('F', 'D', 'S', 'C')
38
2.73k
#define STAB_TAG MKBETAG('S', 'T', 'A', 'B')
39
2.84k
#define CVID_TAG MKBETAG('c', 'v', 'i', 'd')
40
875
#define RAW_TAG  MKBETAG('r', 'a', 'w', ' ')
41
42
typedef struct film_sample {
43
  int stream;
44
  unsigned int sample_size;
45
  int64_t sample_offset;
46
  int64_t pts;
47
  int keyframe;
48
} film_sample;
49
50
typedef struct FilmDemuxContext {
51
    int video_stream_index;
52
    int audio_stream_index;
53
54
    enum AVCodecID audio_type;
55
    unsigned int audio_samplerate;
56
    unsigned int audio_bits;
57
    unsigned int audio_channels;
58
59
    enum AVCodecID video_type;
60
    unsigned int sample_count;
61
    film_sample *sample_table;
62
    unsigned int current_sample;
63
64
    unsigned int base_clock;
65
    unsigned int version;
66
} FilmDemuxContext;
67
68
static int film_probe(const AVProbeData *p)
69
964k
{
70
964k
    if (AV_RB32(&p->buf[0]) != FILM_TAG)
71
964k
        return 0;
72
73
292
    if (AV_RB32(&p->buf[16]) != FDSC_TAG)
74
182
        return 0;
75
76
110
    return AVPROBE_SCORE_MAX;
77
292
}
78
79
static int film_read_close(AVFormatContext *s)
80
3.12k
{
81
3.12k
    FilmDemuxContext *film = s->priv_data;
82
83
3.12k
    av_freep(&film->sample_table);
84
85
3.12k
    return 0;
86
3.12k
}
87
88
static int film_read_header(AVFormatContext *s)
89
3.12k
{
90
3.12k
    FilmDemuxContext *film = s->priv_data;
91
3.12k
    AVIOContext *pb = s->pb;
92
3.12k
    AVStream *st;
93
3.12k
    unsigned char scratch[256];
94
3.12k
    int i;
95
3.12k
    unsigned int data_offset;
96
3.12k
    unsigned int audio_frame_counter;
97
3.12k
    unsigned int video_frame_counter;
98
99
3.12k
    film->sample_table = NULL;
100
101
    /* load the main FILM header */
102
3.12k
    if (avio_read(pb, scratch, 16) != 16)
103
101
        return AVERROR(EIO);
104
3.02k
    data_offset = AV_RB32(&scratch[4]);
105
3.02k
    film->version = AV_RB32(&scratch[8]);
106
107
    /* load the FDSC chunk */
108
3.02k
    if (film->version == 0) {
109
        /* special case for Lemmings .film files; 20-byte header */
110
2.37k
        if (avio_read(pb, scratch, 20) != 20)
111
16
            return AVERROR(EIO);
112
        /* make some assumptions about the audio parameters */
113
2.36k
        film->audio_type = AV_CODEC_ID_PCM_S8;
114
2.36k
        film->audio_samplerate = 22050;
115
2.36k
        film->audio_channels = 1;
116
2.36k
        film->audio_bits = 8;
117
2.36k
    } else {
118
        /* normal Saturn .cpk files; 32-byte header */
119
644
        if (avio_read(pb, scratch, 32) != 32)
120
68
            return AVERROR(EIO);
121
576
        film->audio_samplerate = AV_RB16(&scratch[24]);
122
576
        film->audio_channels = scratch[21];
123
576
        film->audio_bits = scratch[22];
124
576
        if (scratch[23] == 2 && film->audio_channels > 0)
125
254
            film->audio_type = AV_CODEC_ID_ADPCM_ADX;
126
322
        else if (film->audio_channels > 0) {
127
304
            if (film->audio_bits == 8)
128
77
                film->audio_type = AV_CODEC_ID_PCM_S8_PLANAR;
129
227
            else if (film->audio_bits == 16)
130
119
                film->audio_type = AV_CODEC_ID_PCM_S16BE_PLANAR;
131
108
            else
132
108
                film->audio_type = AV_CODEC_ID_NONE;
133
304
        } else
134
18
            film->audio_type = AV_CODEC_ID_NONE;
135
576
    }
136
137
2.93k
    if (AV_RB32(&scratch[0]) != FDSC_TAG)
138
89
        return AVERROR_INVALIDDATA;
139
140
2.84k
    if (AV_RB32(&scratch[8]) == CVID_TAG) {
141
1.97k
        film->video_type = AV_CODEC_ID_CINEPAK;
142
1.97k
    } else if (AV_RB32(&scratch[8]) == RAW_TAG) {
143
142
        film->video_type = AV_CODEC_ID_RAWVIDEO;
144
733
    } else {
145
733
        film->video_type = AV_CODEC_ID_NONE;
146
733
    }
147
148
2.84k
    if (film->video_type == AV_CODEC_ID_NONE && film->audio_type == AV_CODEC_ID_NONE)
149
12
        return AVERROR_INVALIDDATA;
150
151
    /* initialize the decoder streams */
152
2.83k
    if (film->video_type != AV_CODEC_ID_NONE) {
153
2.11k
        st = avformat_new_stream(s, NULL);
154
2.11k
        if (!st)
155
0
            return AVERROR(ENOMEM);
156
2.11k
        film->video_stream_index = st->index;
157
2.11k
        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
158
2.11k
        st->codecpar->codec_id = film->video_type;
159
2.11k
        st->codecpar->codec_tag = 0;  /* no fourcc */
160
2.11k
        st->codecpar->width = AV_RB32(&scratch[16]);
161
2.11k
        st->codecpar->height = AV_RB32(&scratch[12]);
162
163
2.11k
        if (film->video_type == AV_CODEC_ID_RAWVIDEO) {
164
142
            if (scratch[20] == 24) {
165
131
                st->codecpar->format = AV_PIX_FMT_RGB24;
166
131
            } else {
167
11
                av_log(s, AV_LOG_ERROR, "raw video is using unhandled %dbpp\n", scratch[20]);
168
11
                return -1;
169
11
            }
170
142
        }
171
2.11k
    }
172
173
2.82k
    if (film->audio_type != AV_CODEC_ID_NONE) {
174
2.74k
        st = avformat_new_stream(s, NULL);
175
2.74k
        if (!st)
176
0
            return AVERROR(ENOMEM);
177
2.74k
        film->audio_stream_index = st->index;
178
2.74k
        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
179
2.74k
        st->codecpar->codec_id = film->audio_type;
180
2.74k
        st->codecpar->codec_tag = 1;
181
2.74k
        st->codecpar->ch_layout.nb_channels = film->audio_channels;
182
2.74k
        st->codecpar->sample_rate = film->audio_samplerate;
183
184
2.74k
        if (film->audio_type == AV_CODEC_ID_ADPCM_ADX) {
185
249
            st->codecpar->bits_per_coded_sample = 18 * 8 / 32;
186
249
            st->codecpar->block_align = film->audio_channels * 18;
187
249
            ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL;
188
2.50k
        } else {
189
2.50k
            st->codecpar->bits_per_coded_sample = film->audio_bits;
190
2.50k
            st->codecpar->block_align = film->audio_channels *
191
2.50k
                st->codecpar->bits_per_coded_sample / 8;
192
2.50k
        }
193
194
2.74k
        st->codecpar->bit_rate = film->audio_channels * st->codecpar->sample_rate *
195
2.74k
            st->codecpar->bits_per_coded_sample;
196
2.74k
    }
197
198
    /* load the sample table */
199
2.82k
    if (avio_read(pb, scratch, 16) != 16)
200
88
        return AVERROR(EIO);
201
2.73k
    if (AV_RB32(&scratch[0]) != STAB_TAG)
202
48
        return AVERROR_INVALIDDATA;
203
2.69k
    film->base_clock = AV_RB32(&scratch[8]);
204
2.69k
    film->sample_count = AV_RB32(&scratch[12]);
205
2.69k
    film->sample_table = av_malloc_array(film->sample_count, sizeof(film_sample));
206
2.69k
    if (!film->sample_table)
207
38
        return AVERROR(ENOMEM);
208
209
7.28k
    for (i = 0; i < s->nb_streams; i++) {
210
4.63k
        st = s->streams[i];
211
4.63k
        if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
212
2.05k
            avpriv_set_pts_info(st, 33, 1, film->base_clock);
213
2.57k
        else
214
2.57k
            avpriv_set_pts_info(st, 64, 1, film->audio_samplerate);
215
4.63k
    }
216
217
2.65k
    audio_frame_counter = video_frame_counter = 0;
218
134k
    for (i = 0; i < film->sample_count; i++) {
219
        /* load the next sample record and transfer it to an internal struct */
220
132k
        if (avio_read(pb, scratch, 16) != 16)
221
169
            return AVERROR(EIO);
222
132k
        film->sample_table[i].sample_offset =
223
132k
            data_offset + AV_RB32(&scratch[0]);
224
132k
        film->sample_table[i].sample_size = AV_RB32(&scratch[4]);
225
132k
        if (film->sample_table[i].sample_size > INT_MAX / 4)
226
33
            return AVERROR_INVALIDDATA;
227
132k
        if (AV_RB32(&scratch[8]) == 0xFFFFFFFF) {
228
7.16k
            film->sample_table[i].stream = film->audio_stream_index;
229
7.16k
            film->sample_table[i].pts = audio_frame_counter;
230
231
7.16k
            if (film->audio_type == AV_CODEC_ID_ADPCM_ADX)
232
5.64k
                audio_frame_counter += (film->sample_table[i].sample_size * 32 /
233
5.64k
                    (18 * film->audio_channels));
234
1.52k
            else if (film->audio_type != AV_CODEC_ID_NONE)
235
1.03k
                audio_frame_counter += (film->sample_table[i].sample_size /
236
1.03k
                    (film->audio_channels * film->audio_bits / 8));
237
7.16k
            film->sample_table[i].keyframe = 1;
238
124k
        } else {
239
124k
            film->sample_table[i].stream = film->video_stream_index;
240
124k
            film->sample_table[i].pts = AV_RB32(&scratch[8]) & 0x7FFFFFFF;
241
124k
            film->sample_table[i].keyframe = (scratch[8] & 0x80) ? 0 : AVINDEX_KEYFRAME;
242
124k
            video_frame_counter++;
243
124k
            if (film->video_type != AV_CODEC_ID_NONE)
244
118k
                av_add_index_entry(s->streams[film->video_stream_index],
245
118k
                                   film->sample_table[i].sample_offset,
246
118k
                                   film->sample_table[i].pts,
247
118k
                                   film->sample_table[i].sample_size, 0,
248
118k
                                   film->sample_table[i].keyframe);
249
124k
        }
250
132k
    }
251
252
2.45k
    if (film->audio_type != AV_CODEC_ID_NONE)
253
2.39k
        s->streams[film->audio_stream_index]->duration = audio_frame_counter;
254
255
2.45k
    if (film->video_type != AV_CODEC_ID_NONE)
256
1.88k
        s->streams[film->video_stream_index]->duration = video_frame_counter;
257
258
2.45k
    film->current_sample = 0;
259
260
2.45k
    return 0;
261
2.65k
}
262
263
static int film_read_packet(AVFormatContext *s,
264
                            AVPacket *pkt)
265
46.1k
{
266
46.1k
    FilmDemuxContext *film = s->priv_data;
267
46.1k
    AVIOContext *pb = s->pb;
268
46.1k
    film_sample *sample;
269
46.1k
    film_sample *next_sample = NULL;
270
46.1k
    int next_sample_id;
271
46.1k
    int ret = 0;
272
273
46.1k
    if (film->current_sample >= film->sample_count)
274
2.55k
        return AVERROR_EOF;
275
276
43.6k
    sample = &film->sample_table[film->current_sample];
277
278
    /* Find the next sample from the same stream, assuming there is one;
279
     * this is used to calculate the duration below */
280
43.6k
    next_sample_id = film->current_sample + 1;
281
93.5k
    while (next_sample == NULL) {
282
52.0k
        if (next_sample_id >= film->sample_count)
283
2.21k
            break;
284
285
49.8k
        next_sample = &film->sample_table[next_sample_id];
286
49.8k
        if (next_sample->stream != sample->stream) {
287
8.44k
            next_sample = NULL;
288
8.44k
            next_sample_id++;
289
8.44k
        }
290
49.8k
    }
291
292
    /* position the stream (will probably be there anyway) */
293
43.6k
    avio_seek(pb, sample->sample_offset, SEEK_SET);
294
295
43.6k
    ret = av_get_packet(pb, pkt, sample->sample_size);
296
43.6k
    if (ret != sample->sample_size)
297
1.96k
        ret = AVERROR(EIO);
298
299
43.6k
    pkt->stream_index = sample->stream;
300
43.6k
    pkt->dts = sample->pts;
301
43.6k
    pkt->pts = sample->pts;
302
43.6k
    pkt->flags |= sample->keyframe ? AV_PKT_FLAG_KEY : 0;
303
43.6k
    if (next_sample != NULL)
304
41.4k
        pkt->duration = next_sample->pts - sample->pts;
305
306
43.6k
    film->current_sample++;
307
308
43.6k
    return ret;
309
46.1k
}
310
311
static int film_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
312
0
{
313
0
    FilmDemuxContext *film = s->priv_data;
314
0
    AVStream *st = s->streams[stream_index];
315
0
    int64_t pos;
316
0
    int ret = av_index_search_timestamp(st, timestamp, flags);
317
0
    if (ret < 0)
318
0
        return ret;
319
320
0
    pos = avio_seek(s->pb, ffstream(st)->index_entries[ret].pos, SEEK_SET);
321
0
    if (pos < 0)
322
0
        return pos;
323
324
0
    film->current_sample = ret;
325
326
0
    return 0;
327
0
}
328
329
const FFInputFormat ff_segafilm_demuxer = {
330
    .p.name         = "film_cpk",
331
    .p.long_name    = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"),
332
    .priv_data_size = sizeof(FilmDemuxContext),
333
    .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
334
    .read_probe     = film_probe,
335
    .read_header    = film_read_header,
336
    .read_packet    = film_read_packet,
337
    .read_close     = film_read_close,
338
    .read_seek      = film_read_seek,
339
};