Coverage Report

Created: 2025-08-28 07:12

/src/ffmpeg/libavformat/westwood_aud.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Westwood Studios AUD Format 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
 * Westwood Studios AUD file demuxer
25
 * by Mike Melanson (melanson@pcisys.net)
26
 * for more information on the Westwood file formats, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28
 *   http://www.geocities.com/SiliconValley/8682/aud3.txt
29
 *
30
 * Implementation note: There is no definite file signature for AUD files.
31
 * The demuxer uses a probabilistic strategy for content detection. This
32
 * entails performing sanity checks on certain header values in order to
33
 * qualify a file. Refer to wsaud_probe() for the precise parameters.
34
 */
35
36
#include "libavutil/channel_layout.h"
37
#include "libavutil/intreadwrite.h"
38
#include "avformat.h"
39
#include "demux.h"
40
#include "internal.h"
41
42
936k
#define AUD_HEADER_SIZE 12
43
1.26M
#define AUD_CHUNK_PREAMBLE_SIZE 8
44
176k
#define AUD_CHUNK_SIGNATURE 0x0000DEAF
45
46
static int wsaud_probe(const AVProbeData *p)
47
924k
{
48
924k
    int field;
49
50
    /* Probabilistic content detection strategy: There is no file signature
51
     * so perform sanity checks on various header parameters:
52
     *   8000 <= sample rate (16 bits) <= 48000  ==> 40001 acceptable numbers
53
     *   flags <= 0x03 (2 LSBs are used)         ==> 4 acceptable numbers
54
     *   compression type (8 bits) = 1 or 99     ==> 2 acceptable numbers
55
     *   first audio chunk signature (32 bits)   ==> 1 acceptable number
56
     * The number space contains 2^64 numbers. There are 40001 * 4 * 2 * 1 =
57
     * 320008 acceptable number combinations.
58
     */
59
60
924k
    if (p->buf_size < AUD_HEADER_SIZE + AUD_CHUNK_PREAMBLE_SIZE)
61
165k
        return 0;
62
63
    /* check sample rate */
64
759k
    field = AV_RL16(&p->buf[0]);
65
759k
    if ((field < 8000) || (field > 48000))
66
341k
        return 0;
67
68
    /* enforce the rule that the top 6 bits of this flags field are reserved (0);
69
     * this might not be true, but enforce it until deemed unnecessary */
70
417k
    if (p->buf[10] & 0xFC)
71
276k
        return 0;
72
73
141k
    if (p->buf[11] != 99 && p->buf[11] != 1)
74
133k
        return 0;
75
76
    /* read ahead to the first audio chunk and validate the first header signature */
77
8.13k
    if (AV_RL32(&p->buf[16]) != AUD_CHUNK_SIGNATURE)
78
8.12k
        return 0;
79
80
    /* return 1/2 certainty since this file check is a little sketchy */
81
12
    return AVPROBE_SCORE_EXTENSION;
82
8.13k
}
83
84
static int wsaud_read_header(AVFormatContext *s)
85
6.19k
{
86
6.19k
    AVIOContext *pb = s->pb;
87
6.19k
    AVStream *st;
88
6.19k
    unsigned char header[AUD_HEADER_SIZE];
89
6.19k
    int sample_rate, channels, codec;
90
91
6.19k
    if (avio_read(pb, header, AUD_HEADER_SIZE) != AUD_HEADER_SIZE)
92
5.17k
        return AVERROR(EIO);
93
94
1.01k
    sample_rate = AV_RL16(&header[0]);
95
1.01k
    channels    = (header[10] & 0x1) + 1;
96
1.01k
    codec       = header[11];
97
98
    /* initialize the audio decoder stream */
99
1.01k
    st = avformat_new_stream(s, NULL);
100
1.01k
    if (!st)
101
0
        return AVERROR(ENOMEM);
102
103
1.01k
    switch (codec) {
104
333
    case  1:
105
333
        if (channels != 1) {
106
2
            avpriv_request_sample(s, "Stereo WS-SND1");
107
2
            return AVERROR_PATCHWELCOME;
108
2
        }
109
331
        st->codecpar->codec_id = AV_CODEC_ID_WESTWOOD_SND1;
110
331
        break;
111
558
    case 99:
112
558
        st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
113
558
        st->codecpar->bits_per_coded_sample = 4;
114
558
        st->codecpar->bit_rate = channels * sample_rate * 4;
115
558
        break;
116
124
    default:
117
124
        avpriv_request_sample(s, "Unknown codec: %d", codec);
118
124
        return AVERROR_PATCHWELCOME;
119
1.01k
    }
120
889
    avpriv_set_pts_info(st, 64, 1, sample_rate);
121
889
    st->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
122
889
    av_channel_layout_default(&st->codecpar->ch_layout, channels);
123
889
    st->codecpar->sample_rate = sample_rate;
124
125
889
    return 0;
126
1.01k
}
127
128
static int wsaud_read_packet(AVFormatContext *s,
129
                             AVPacket *pkt)
130
169k
{
131
169k
    AVIOContext *pb = s->pb;
132
169k
    unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE];
133
169k
    unsigned int chunk_size;
134
169k
    int ret = 0;
135
169k
    AVStream *st = s->streams[0];
136
137
169k
    if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) !=
138
169k
        AUD_CHUNK_PREAMBLE_SIZE)
139
1.13k
        return AVERROR(EIO);
140
141
    /* validate the chunk */
142
168k
    if (AV_RL32(&preamble[4]) != AUD_CHUNK_SIGNATURE)
143
258
        return AVERROR_INVALIDDATA;
144
145
167k
    chunk_size = AV_RL16(&preamble[0]);
146
147
167k
    if (st->codecpar->codec_id == AV_CODEC_ID_WESTWOOD_SND1) {
148
        /* For Westwood SND1 audio we need to add the output size and input
149
           size to the start of the packet to match what is in VQA.
150
           Specifically, this is needed to signal when a packet should be
151
           decoding as raw 8-bit pcm or variable-size ADPCM. */
152
8.76k
        int out_size = AV_RL16(&preamble[2]);
153
8.76k
        if ((ret = av_new_packet(pkt, chunk_size + 4)) < 0)
154
0
            return ret;
155
8.76k
        if ((ret = avio_read(pb, &pkt->data[4], chunk_size)) != chunk_size)
156
35
            return ret < 0 ? ret : AVERROR(EIO);
157
8.72k
        AV_WL16(&pkt->data[0], out_size);
158
8.72k
        AV_WL16(&pkt->data[2], chunk_size);
159
160
8.72k
        pkt->duration = out_size;
161
159k
    } else {
162
159k
        ret = av_get_packet(pb, pkt, chunk_size);
163
159k
        if (ret != chunk_size)
164
68
            return AVERROR(EIO);
165
166
158k
        if (st->codecpar->ch_layout.nb_channels <= 0) {
167
0
            av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n",
168
0
                   st->codecpar->ch_layout.nb_channels);
169
0
            return AVERROR_INVALIDDATA;
170
0
        }
171
172
        /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
173
158k
        pkt->duration = (chunk_size * 2) / st->codecpar->ch_layout.nb_channels;
174
158k
    }
175
167k
    pkt->stream_index = st->index;
176
177
167k
    return ret;
178
167k
}
179
180
const FFInputFormat ff_wsaud_demuxer = {
181
    .p.name         = "wsaud",
182
    .p.long_name    = NULL_IF_CONFIG_SMALL("Westwood Studios audio"),
183
    .read_probe     = wsaud_probe,
184
    .read_header    = wsaud_read_header,
185
    .read_packet    = wsaud_read_packet,
186
};