Coverage Report

Created: 2026-10-28 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/3dostr.c
Line
Count
Source
1
/*
2
 * 3DO STR demuxer
3
 * Copyright (c) 2015 Paul B Mahol
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 "libavutil/intreadwrite.h"
23
#include "avformat.h"
24
#include "demux.h"
25
#include "internal.h"
26
27
static int threedostr_probe(const AVProbeData *p)
28
963k
{
29
981k
    for (int i = 0; i < p->buf_size;) {
30
975k
        unsigned chunk = AV_RL32(p->buf + i);
31
975k
        unsigned size  = AV_RB32(p->buf + i + 4);
32
33
975k
        if (size < 8 || p->buf_size - i < size)
34
956k
            return 0;
35
18.8k
        i += 8;
36
18.8k
        size -= 8;
37
18.8k
        switch (chunk) {
38
0
        case MKTAG('C','T','R','L'):
39
0
            break;
40
328
        case MKTAG('S','N','D','S'):
41
328
            if (size < 56)
42
61
                return 0;
43
267
            i += 8;
44
267
            if (AV_RL32(p->buf + i) != MKTAG('S','H','D','R'))
45
62
                return 0;
46
205
            i += 28;
47
48
205
            if (AV_RB32(p->buf + i) <= 0)
49
89
                return 0;
50
116
            i += 4;
51
116
            if (AV_RB32(p->buf + i) <= 0)
52
29
                return 0;
53
87
            i += 4;
54
87
            if (AV_RL32(p->buf + i) == MKTAG('S','D','X','2'))
55
43
                return AVPROBE_SCORE_MAX;
56
44
            else
57
44
                return 0;
58
0
            break;
59
235
        case MKTAG('S','H','D','R'):
60
235
            if (size > 0x78) {
61
94
                i += 0x78;
62
94
                size -= 0x78;
63
94
            }
64
235
            break;
65
18.3k
        default:
66
18.3k
            break;
67
18.8k
        }
68
69
18.5k
        i += size;
70
18.5k
    }
71
72
6.82k
    return 0;
73
963k
}
74
75
static int threedostr_read_header(AVFormatContext *s)
76
2.60k
{
77
2.60k
    unsigned chunk, codec = 0, size, ctrl_size = -1, found_shdr = 0;
78
2.60k
    AVStream *st;
79
80
65.8k
    while (!avio_feof(s->pb) && !found_shdr) {
81
63.6k
        chunk = avio_rl32(s->pb);
82
63.6k
        size  = avio_rb32(s->pb);
83
84
63.6k
        if (size < 8)
85
203
            return AVERROR_INVALIDDATA;
86
63.4k
        size -= 8;
87
88
63.4k
        switch (chunk) {
89
512
        case MKTAG('C','T','R','L'):
90
512
            ctrl_size = size;
91
512
            break;
92
1.90k
        case MKTAG('S','N','D','S'):
93
1.90k
            if (size < 56)
94
7
                return AVERROR_INVALIDDATA;
95
1.89k
            avio_skip(s->pb, 8);
96
1.89k
            if (avio_rl32(s->pb) != MKTAG('S','H','D','R'))
97
112
                return AVERROR_INVALIDDATA;
98
1.78k
            avio_skip(s->pb, 24);
99
100
1.78k
            st = avformat_new_stream(s, NULL);
101
1.78k
            if (!st)
102
0
                return AVERROR(ENOMEM);
103
104
1.78k
            st->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
105
1.78k
            st->codecpar->sample_rate = avio_rb32(s->pb);
106
1.78k
            st->codecpar->ch_layout.nb_channels = avio_rb32(s->pb);
107
1.78k
            if (st->codecpar->ch_layout.nb_channels <= 0 || st->codecpar->sample_rate <= 0)
108
80
                return AVERROR_INVALIDDATA;
109
1.70k
            codec                  = avio_rl32(s->pb);
110
1.70k
            avio_skip(s->pb, 4);
111
1.70k
            if (ctrl_size == 20 || ctrl_size == 3 || ctrl_size == -1)
112
1.65k
                st->duration       = (avio_rb32(s->pb) - 1) / st->codecpar->ch_layout.nb_channels;
113
52
            else
114
52
                st->duration       = avio_rb32(s->pb) * 16 / st->codecpar->ch_layout.nb_channels;
115
1.70k
            size -= 56;
116
1.70k
            found_shdr = 1;
117
1.70k
            break;
118
1.30k
        case MKTAG('S','H','D','R'):
119
1.30k
            if (size >  0x78) {
120
1.01k
                avio_skip(s->pb, 0x74);
121
1.01k
                size -= 0x78;
122
1.01k
                if (avio_rl32(s->pb) == MKTAG('C','T','R','L') && size > 4) {
123
298
                    ctrl_size = avio_rb32(s->pb);
124
298
                    size -= 4;
125
298
                }
126
1.01k
            }
127
1.30k
            break;
128
59.6k
        default:
129
59.6k
            av_log(s, AV_LOG_DEBUG, "skipping unknown chunk: %X\n", chunk);
130
59.6k
            break;
131
63.4k
        }
132
133
63.2k
        avio_skip(s->pb, size);
134
63.2k
    }
135
136
2.20k
    switch (codec) {
137
1.58k
    case MKTAG('S','D','X','2'):
138
1.58k
        st->codecpar->codec_id    = AV_CODEC_ID_SDX2_DPCM;
139
1.58k
        st->codecpar->block_align = 1 * st->codecpar->ch_layout.nb_channels;
140
1.58k
        break;
141
617
    default:
142
617
        avpriv_request_sample(s, "codec %X", codec);
143
617
        return AVERROR_PATCHWELCOME;
144
2.20k
    }
145
146
1.58k
    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
147
148
1.58k
    return 0;
149
2.20k
}
150
151
static int threedostr_read_packet(AVFormatContext *s, AVPacket *pkt)
152
76.2k
{
153
76.2k
    unsigned chunk, size;
154
76.2k
    AVStream *st = s->streams[0];
155
76.2k
    int64_t pos;
156
76.2k
    int ret = 0;
157
158
260k
    while (!avio_feof(s->pb)) {
159
258k
        pos   = avio_tell(s->pb);
160
258k
        chunk = avio_rl32(s->pb);
161
258k
        size  = avio_rb32(s->pb);
162
163
258k
        if (!size)
164
3.13k
            continue;
165
166
254k
        if (size < 8)
167
55
            return AVERROR_INVALIDDATA;
168
254k
        size -= 8;
169
170
254k
        switch (chunk) {
171
73.8k
        case MKTAG('S','N','D','S'):
172
73.8k
            if (size <= 16)
173
5
                return AVERROR_INVALIDDATA;
174
73.8k
            avio_skip(s->pb, 8);
175
73.8k
            if (avio_rl32(s->pb) != MKTAG('S','S','M','P'))
176
203
                return AVERROR_INVALIDDATA;
177
73.6k
            avio_skip(s->pb, 4);
178
73.6k
            size -= 16;
179
73.6k
            ret = av_get_packet(s->pb, pkt, size);
180
73.6k
            pkt->pos = pos;
181
73.6k
            pkt->stream_index = 0;
182
73.6k
            pkt->duration = size / st->codecpar->ch_layout.nb_channels;
183
73.6k
            return ret;
184
181k
        default:
185
181k
            av_log(s, AV_LOG_DEBUG, "skipping unknown chunk: %X\n", chunk);
186
181k
            break;
187
254k
        }
188
189
181k
        avio_skip(s->pb, size);
190
181k
    }
191
192
2.37k
    return AVERROR_EOF;
193
76.2k
}
194
195
const FFInputFormat ff_threedostr_demuxer = {
196
    .p.name         = "3dostr",
197
    .p.long_name    = NULL_IF_CONFIG_SMALL("3DO STR"),
198
    .p.extensions   = "str",
199
    .p.flags        = AVFMT_GENERIC_INDEX,
200
    .read_probe     = threedostr_probe,
201
    .read_header    = threedostr_read_header,
202
    .read_packet    = threedostr_read_packet,
203
};