Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/sdsdec.c
Line
Count
Source
1
/*
2
 * MIDI Sample Dump Standard format demuxer
3
 * Copyright (c) 2017 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
typedef struct SDSContext {
28
    uint8_t data[120];
29
    int bit_depth;
30
    int size;
31
    void (*read_block)(const uint8_t *src, uint32_t *dst);
32
} SDSContext;
33
34
static int sds_probe(const AVProbeData *p)
35
967k
{
36
967k
    if (AV_RB32(p->buf) == 0xF07E0001 && p->buf[20] == 0xF7 &&
37
631
        p->buf[6] >= 8 && p->buf[6] <= 28)
38
120
        return AVPROBE_SCORE_EXTENSION;
39
967k
    return 0;
40
967k
}
41
42
static void byte2_read(const uint8_t *src, uint32_t *dst)
43
55.8k
{
44
55.8k
    int i;
45
46
3.40M
    for (i = 0; i < 120; i += 2) {
47
3.35M
        unsigned sample = ((unsigned)src[i + 0] << 25) + ((unsigned)src[i + 1] << 18);
48
49
3.35M
        dst[i / 2] = sample;
50
3.35M
    }
51
55.8k
}
52
53
static void byte3_read(const uint8_t *src, uint32_t *dst)
54
3.95k
{
55
3.95k
    int i;
56
57
162k
    for (i = 0; i < 120; i += 3) {
58
158k
        unsigned sample;
59
60
158k
        sample = ((unsigned)src[i + 0] << 25) | ((unsigned)src[i + 1] << 18) | ((unsigned)src[i + 2] << 11);
61
158k
        dst[i / 3] = sample;
62
158k
    }
63
3.95k
}
64
65
static void byte4_read(const uint8_t *src, uint32_t *dst)
66
50.2k
{
67
50.2k
    int i;
68
69
1.55M
    for (i = 0; i < 120; i += 4) {
70
1.50M
        unsigned sample;
71
72
1.50M
        sample = ((unsigned)src[i + 0] << 25) | ((unsigned)src[i + 1] << 18) | ((unsigned)src[i + 2] << 11) | ((unsigned)src[i + 3] << 4);
73
1.50M
        dst[i / 4] = sample;
74
1.50M
    }
75
50.2k
}
76
77
907
#define SDS_3BYTE_TO_INT_DECODE(x) (((x) & 0x7F) | (((x) & 0x7F00) >> 1) | (((x) & 0x7F0000) >> 2))
78
79
static int sds_read_header(AVFormatContext *ctx)
80
1.06k
{
81
1.06k
    SDSContext *s = ctx->priv_data;
82
1.06k
    unsigned sample_period;
83
1.06k
    AVIOContext *pb = ctx->pb;
84
1.06k
    AVStream *st;
85
86
1.06k
    st = avformat_new_stream(ctx, NULL);
87
1.06k
    if (!st)
88
0
        return AVERROR(ENOMEM);
89
90
1.06k
    avio_skip(pb, 4);
91
1.06k
    avio_skip(pb, 2);
92
93
1.06k
    s->bit_depth = avio_r8(pb);
94
1.06k
    if (s->bit_depth < 8 || s->bit_depth > 28)
95
154
        return AVERROR_INVALIDDATA;
96
97
907
    if (s->bit_depth < 14) {
98
400
        s->read_block = byte2_read;
99
400
        s->size = 60 * 4;
100
507
    } else if (s->bit_depth < 21) {
101
187
        s->read_block = byte3_read;
102
187
        s->size = 40 * 4;
103
320
    } else {
104
320
        s->read_block = byte4_read;
105
320
        s->size = 30 * 4;
106
320
    }
107
907
    st->codecpar->codec_id = AV_CODEC_ID_PCM_U32LE;
108
109
907
    sample_period = avio_rl24(pb);
110
907
    sample_period = SDS_3BYTE_TO_INT_DECODE(sample_period);
111
907
    avio_skip(pb, 11);
112
113
907
    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
114
907
    st->codecpar->ch_layout.nb_channels = 1;
115
907
    st->codecpar->sample_rate = sample_period ? 1000000000 / sample_period : 16000;
116
907
    st->duration = av_rescale((avio_size(pb) - 21) / 127,  s->size, 4);
117
118
907
    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
119
120
907
    return 0;
121
1.06k
}
122
123
static int sds_read_packet(AVFormatContext *ctx, AVPacket *pkt)
124
111k
{
125
111k
    SDSContext *s = ctx->priv_data;
126
111k
    AVIOContext *pb = ctx->pb;
127
111k
    int64_t pos;
128
111k
    int ret;
129
130
111k
    if (avio_feof(pb))
131
539
        return AVERROR_EOF;
132
133
110k
    pos = avio_tell(pb);
134
110k
    if (avio_rb16(pb) != 0xF07E)
135
723
        return AVERROR_INVALIDDATA;
136
110k
    avio_skip(pb, 3);
137
138
110k
    ret = av_new_packet(pkt, s->size);
139
110k
    if (ret < 0)
140
0
        return ret;
141
142
110k
    ret = avio_read(pb, s->data, 120);
143
144
110k
    s->read_block(s->data, (uint32_t *)pkt->data);
145
146
110k
    avio_skip(pb, 1); // checksum
147
110k
    if (avio_r8(pb) != 0xF7)
148
368
        return AVERROR_INVALIDDATA;
149
150
109k
    pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
151
109k
    pkt->stream_index = 0;
152
109k
    pkt->pos = pos;
153
154
109k
    return ret;
155
110k
}
156
157
const FFInputFormat ff_sds_demuxer = {
158
    .p.name         = "sds",
159
    .p.long_name    = NULL_IF_CONFIG_SMALL("MIDI Sample Dump Standard"),
160
    .p.extensions   = "sds",
161
    .p.flags        = AVFMT_GENERIC_INDEX,
162
    .priv_data_size = sizeof(SDSContext),
163
    .read_probe     = sds_probe,
164
    .read_header    = sds_read_header,
165
    .read_packet    = sds_read_packet,
166
};