FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/lafdec.c
Date: 2026-09-25 11:37:27
Exec Total Coverage
Lines: 3 160 1.9%
Functions: 1 5 20.0%
Branches: 1 90 1.1%

Line Branch Exec Source
1 /*
2 * Limitless Audio Format demuxer
3 * Copyright (c) 2022 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/intfloat.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/mem.h"
25 #include "avformat.h"
26 #include "avio_internal.h"
27 #include "demux.h"
28 #include "internal.h"
29
30 #define MAX_STREAMS 4096
31
32 typedef struct StreamParams {
33 AVChannelLayout layout;
34 float horizontal;
35 float vertical;
36 int lfe;
37 int stored;
38 } StreamParams;
39
40 typedef struct LAFContext {
41 uint8_t *data;
42 unsigned nb_stored;
43 unsigned stored_index;
44 unsigned index;
45 unsigned bpp;
46
47 StreamParams p[MAX_STREAMS];
48
49 int header_len;
50 uint8_t header[(MAX_STREAMS + 7) / 8];
51 } LAFContext;
52
53 8064 static int laf_probe(const AVProbeData *p)
54 {
55
1/2
✓ Branch 0 taken 8064 times.
✗ Branch 1 not taken.
8064 if (memcmp(p->buf, "LIMITLESS", 9))
56 8064 return 0;
57 ✗ if (memcmp(p->buf + 9, "HEAD", 4))
58 ✗ return 0;
59 ✗ return AVPROBE_SCORE_MAX;
60 }
61
62 ✗ static int laf_read_header(AVFormatContext *ctx)
63 {
64 ✗ LAFContext *s = ctx->priv_data;
65 ✗ AVIOContext *pb = ctx->pb;
66 unsigned st_count, mode;
67 unsigned sample_rate;
68 int64_t duration;
69 int codec_id;
70 int quality;
71 int bpp;
72
73 ✗ avio_skip(pb, 9);
74 ✗ if (avio_rb32(pb) != MKBETAG('H','E','A','D'))
75 ✗ return AVERROR_INVALIDDATA;
76
77 ✗ quality = avio_r8(pb);
78 ✗ if (quality > 3)
79 ✗ return AVERROR_INVALIDDATA;
80 ✗ mode = avio_r8(pb);
81 ✗ if (mode > 1)
82 ✗ return AVERROR_INVALIDDATA;
83 ✗ st_count = avio_rl32(pb);
84 ✗ if (st_count == 0 || st_count > MAX_STREAMS)
85 ✗ return AVERROR_INVALIDDATA;
86
87 ✗ for (int i = 0; i < st_count; i++) {
88 ✗ StreamParams *stp = &s->p[i];
89
90 ✗ stp->vertical = av_int2float(avio_rl32(pb));
91 ✗ stp->horizontal = av_int2float(avio_rl32(pb));
92 ✗ stp->lfe = avio_r8(pb);
93 ✗ if (stp->lfe) {
94 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_LOW_FREQUENCY));
95 ✗ } else if (stp->vertical == 0.f &&
96 ✗ stp->horizontal == 0.f) {
97 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_FRONT_CENTER));
98 ✗ } else if (stp->vertical == 0.f &&
99 ✗ stp->horizontal == -30.f) {
100 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_FRONT_LEFT));
101 ✗ } else if (stp->vertical == 0.f &&
102 ✗ stp->horizontal == 30.f) {
103 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_FRONT_RIGHT));
104 ✗ } else if (stp->vertical == 0.f &&
105 ✗ stp->horizontal == -110.f) {
106 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_SIDE_LEFT));
107 ✗ } else if (stp->vertical == 0.f &&
108 ✗ stp->horizontal == 110.f) {
109 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MASK(1, (AV_CH_SIDE_RIGHT));
110 } else {
111 ✗ stp->layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
112 }
113 }
114
115 ✗ sample_rate = avio_rl32(pb);
116 ✗ duration = avio_rl64(pb) / st_count;
117
118 ✗ if (avio_feof(pb))
119 ✗ return AVERROR_INVALIDDATA;
120
121 ✗ switch (quality) {
122 ✗ case 0:
123 ✗ codec_id = AV_CODEC_ID_PCM_U8;
124 ✗ bpp = 1;
125 ✗ break;
126 ✗ case 1:
127 ✗ codec_id = AV_CODEC_ID_PCM_S16LE;
128 ✗ bpp = 2;
129 ✗ break;
130 ✗ case 2:
131 ✗ codec_id = AV_CODEC_ID_PCM_F32LE;
132 ✗ bpp = 4;
133 ✗ break;
134 ✗ case 3:
135 ✗ codec_id = AV_CODEC_ID_PCM_S24LE;
136 ✗ bpp = 3;
137 ✗ break;
138 ✗ default:
139 ✗ return AVERROR_INVALIDDATA;
140 }
141
142 ✗ s->index = 0;
143 ✗ s->stored_index = 0;
144 ✗ s->bpp = bpp;
145 ✗ if ((int64_t)bpp * st_count * (int64_t)sample_rate >= INT32_MAX ||
146 ✗ (int64_t)bpp * st_count * (int64_t)sample_rate == 0
147 )
148 ✗ return AVERROR_INVALIDDATA;
149 ✗ s->data = av_calloc(st_count * sample_rate, bpp);
150 ✗ if (!s->data)
151 ✗ return AVERROR(ENOMEM);
152
153 ✗ for (unsigned i = 0; i < st_count; i++) {
154 ✗ StreamParams *stp = &s->p[i];
155 AVCodecParameters *par;
156 ✗ AVStream *st = avformat_new_stream(ctx, NULL);
157 ✗ if (!st)
158 ✗ return AVERROR(ENOMEM);
159
160 ✗ par = st->codecpar;
161 ✗ par->codec_id = codec_id;
162 ✗ par->codec_type = AVMEDIA_TYPE_AUDIO;
163 ✗ par->ch_layout.nb_channels = 1;
164 ✗ par->ch_layout = stp->layout;
165 ✗ par->sample_rate = sample_rate;
166 ✗ st->duration = duration;
167
168 ✗ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
169 }
170
171 ✗ s->header_len = (ctx->nb_streams + 7) / 8;
172
173 ✗ return 0;
174 }
175
176 ✗ static int laf_read_packet(AVFormatContext *ctx, AVPacket *pkt)
177 {
178 ✗ AVIOContext *pb = ctx->pb;
179 ✗ LAFContext *s = ctx->priv_data;
180 ✗ AVStream *st = ctx->streams[0];
181 ✗ const int bpp = s->bpp;
182 StreamParams *stp;
183 int64_t pos;
184 int ret;
185
186 ✗ pos = avio_tell(pb);
187
188 ✗ again:
189 ✗ if (avio_feof(pb))
190 ✗ return AVERROR_EOF;
191
192 ✗ if (s->index >= ctx->nb_streams) {
193 ✗ int cur_st = 0, st_count = 0, st_index = 0;
194
195 ✗ ret = ffio_read_size(pb, s->header, s->header_len);
196 ✗ if (ret < 0)
197 ✗ return ret;
198 ✗ for (int i = 0; i < s->header_len; i++) {
199 ✗ uint8_t val = s->header[i];
200
201 ✗ for (int j = 0; j < 8 && cur_st < ctx->nb_streams; j++, cur_st++) {
202 ✗ s->p[st_index].stored = val & 1;
203 ✗ st_count += val & 1;
204 ✗ val >>= 1;
205 ✗ st_index++;
206 }
207 }
208
209 ✗ s->index = s->stored_index = 0;
210 ✗ s->nb_stored = st_count;
211 ✗ if (!st_count)
212 ✗ return AVERROR_INVALIDDATA;
213 ✗ ret = ffio_read_size(pb, s->data, st_count * st->codecpar->sample_rate * bpp);
214 ✗ if (ret < 0)
215 ✗ return ret;
216 }
217
218 ✗ st = ctx->streams[s->index];
219 ✗ stp = &s->p[s->index];
220 ✗ while (!stp->stored) {
221 ✗ s->index++;
222 ✗ if (s->index >= ctx->nb_streams)
223 ✗ goto again;
224 ✗ stp = &s->p[s->index];
225 }
226 ✗ st = ctx->streams[s->index];
227
228 ✗ ret = av_new_packet(pkt, st->codecpar->sample_rate * bpp);
229 ✗ if (ret < 0)
230 ✗ return ret;
231
232 ✗ switch (bpp) {
233 ✗ case 1:
234 ✗ for (int n = 0; n < st->codecpar->sample_rate; n++)
235 ✗ pkt->data[n] = s->data[n * s->nb_stored + s->stored_index];
236 ✗ break;
237 ✗ case 2:
238 ✗ for (int n = 0; n < st->codecpar->sample_rate; n++)
239 ✗ AV_WN16(pkt->data + n * 2, AV_RN16(s->data + n * s->nb_stored * 2 + s->stored_index * 2));
240 ✗ break;
241 ✗ case 3:
242 ✗ for (int n = 0; n < st->codecpar->sample_rate; n++)
243 ✗ AV_WL24(pkt->data + n * 3, AV_RL24(s->data + n * s->nb_stored * 3 + s->stored_index * 3));
244 ✗ break;
245 ✗ case 4:
246 ✗ for (int n = 0; n < st->codecpar->sample_rate; n++)
247 ✗ AV_WN32(pkt->data + n * 4, AV_RN32(s->data + n * s->nb_stored * 4 + s->stored_index * 4));
248 ✗ break;
249 }
250
251 ✗ pkt->stream_index = s->index;
252 ✗ pkt->pos = pos;
253 ✗ s->index++;
254 ✗ s->stored_index++;
255
256 ✗ return 0;
257 }
258
259 ✗ static int laf_read_close(AVFormatContext *ctx)
260 {
261 ✗ LAFContext *s = ctx->priv_data;
262
263 ✗ av_freep(&s->data);
264
265 ✗ return 0;
266 }
267
268 ✗ static int laf_read_seek(AVFormatContext *ctx, int stream_index,
269 int64_t timestamp, int flags)
270 {
271 ✗ LAFContext *s = ctx->priv_data;
272
273 ✗ s->stored_index = s->index = s->nb_stored = 0;
274
275 ✗ return -1;
276 }
277
278 const FFInputFormat ff_laf_demuxer = {
279 .p.name = "laf",
280 .p.long_name = NULL_IF_CONFIG_SMALL("LAF (Limitless Audio Format)"),
281 .p.extensions = "laf",
282 .p.flags = AVFMT_GENERIC_INDEX,
283 .priv_data_size = sizeof(LAFContext),
284 .read_probe = laf_probe,
285 .read_header = laf_read_header,
286 .read_packet = laf_read_packet,
287 .read_close = laf_read_close,
288 .read_seek = laf_read_seek,
289 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
290 };
291