FFmpeg coverage


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