Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Audio FIFO | ||
3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
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 | * Audio FIFO | ||
25 | */ | ||
26 | |||
27 | #include <limits.h> | ||
28 | #include <stddef.h> | ||
29 | |||
30 | #include "audio_fifo.h" | ||
31 | #include "error.h" | ||
32 | #include "fifo.h" | ||
33 | #include "macros.h" | ||
34 | #include "mem.h" | ||
35 | #include "samplefmt.h" | ||
36 | |||
37 | struct AVAudioFifo { | ||
38 | AVFifo **buf; /**< single buffer for interleaved, per-channel buffers for planar */ | ||
39 | int nb_buffers; /**< number of buffers */ | ||
40 | int nb_samples; /**< number of samples currently in the FIFO */ | ||
41 | int allocated_samples; /**< current allocated size, in samples */ | ||
42 | |||
43 | int channels; /**< number of channels */ | ||
44 | enum AVSampleFormat sample_fmt; /**< sample format */ | ||
45 | int sample_size; /**< size, in bytes, of one sample in a buffer */ | ||
46 | }; | ||
47 | |||
48 | 191 | void av_audio_fifo_free(AVAudioFifo *af) | |
49 | { | ||
50 |
1/2✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
|
191 | if (af) { |
51 |
1/2✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
|
191 | if (af->buf) { |
52 | int i; | ||
53 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 191 times.
|
499 | for (i = 0; i < af->nb_buffers; i++) { |
54 | 308 | av_fifo_freep2(&af->buf[i]); | |
55 | } | ||
56 | 191 | av_freep(&af->buf); | |
57 | } | ||
58 | 191 | av_free(af); | |
59 | } | ||
60 | 191 | } | |
61 | |||
62 | 191 | AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, | |
63 | int nb_samples) | ||
64 | { | ||
65 | AVAudioFifo *af; | ||
66 | int buf_size, i; | ||
67 | |||
68 | /* get channel buffer size (also validates parameters) */ | ||
69 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 191 times.
|
191 | if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) |
70 | ✗ | return NULL; | |
71 | |||
72 | 191 | af = av_mallocz(sizeof(*af)); | |
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 191 times.
|
191 | if (!af) |
74 | ✗ | return NULL; | |
75 | |||
76 | 191 | af->channels = channels; | |
77 | 191 | af->sample_fmt = sample_fmt; | |
78 | 191 | af->sample_size = buf_size / nb_samples; | |
79 |
2/2✓ Branch 1 taken 175 times.
✓ Branch 2 taken 16 times.
|
191 | af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; |
80 | |||
81 | 191 | af->buf = av_calloc(af->nb_buffers, sizeof(*af->buf)); | |
82 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 191 times.
|
191 | if (!af->buf) |
83 | ✗ | goto error; | |
84 | |||
85 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 191 times.
|
499 | for (i = 0; i < af->nb_buffers; i++) { |
86 | 308 | af->buf[i] = av_fifo_alloc2(buf_size, 1, 0); | |
87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
|
308 | if (!af->buf[i]) |
88 | ✗ | goto error; | |
89 | } | ||
90 | 191 | af->allocated_samples = nb_samples; | |
91 | |||
92 | 191 | return af; | |
93 | |||
94 | ✗ | error: | |
95 | ✗ | av_audio_fifo_free(af); | |
96 | ✗ | return NULL; | |
97 | } | ||
98 | |||
99 | 40 | int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) | |
100 | { | ||
101 | 40 | const size_t cur_size = av_fifo_can_read (af->buf[0]) + | |
102 | 40 | av_fifo_can_write(af->buf[0]); | |
103 | int i, ret, buf_size; | ||
104 | |||
105 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
|
40 | if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, |
106 | af->sample_fmt, 1)) < 0) | ||
107 | ✗ | return ret; | |
108 | |||
109 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | if (buf_size > cur_size) { |
110 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 40 times.
|
83 | for (i = 0; i < af->nb_buffers; i++) { |
111 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
|
43 | if ((ret = av_fifo_grow2(af->buf[i], buf_size - cur_size)) < 0) |
112 | ✗ | return ret; | |
113 | } | ||
114 | } | ||
115 | 40 | af->allocated_samples = nb_samples; | |
116 | 40 | return 0; | |
117 | } | ||
118 | |||
119 | 6543 | int av_audio_fifo_write(AVAudioFifo *af, void * const *data, int nb_samples) | |
120 | { | ||
121 | int i, ret, size; | ||
122 | |||
123 | /* automatically reallocate buffers if needed */ | ||
124 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 6503 times.
|
6543 | if (av_audio_fifo_space(af) < nb_samples) { |
125 | 40 | int current_size = av_audio_fifo_size(af); | |
126 | /* check for integer overflow in new size calculation */ | ||
127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
|
40 | if (INT_MAX / 2 - current_size < nb_samples) |
128 | ✗ | return AVERROR(EINVAL); | |
129 | /* reallocate buffers */ | ||
130 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
|
40 | if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) |
131 | ✗ | return ret; | |
132 | } | ||
133 | |||
134 | 6543 | size = nb_samples * af->sample_size; | |
135 |
2/2✓ Branch 0 taken 11538 times.
✓ Branch 1 taken 6543 times.
|
18081 | for (i = 0; i < af->nb_buffers; i++) { |
136 | 11538 | ret = av_fifo_write(af->buf[i], data[i], size); | |
137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11538 times.
|
11538 | if (ret < 0) |
138 | ✗ | return AVERROR_BUG; | |
139 | } | ||
140 | 6543 | af->nb_samples += nb_samples; | |
141 | |||
142 | 6543 | return nb_samples; | |
143 | } | ||
144 | |||
145 | 6 | int av_audio_fifo_peek(const AVAudioFifo *af, void * const *data, int nb_samples) | |
146 | { | ||
147 | 6 | return av_audio_fifo_peek_at(af, data, nb_samples, 0); | |
148 | } | ||
149 | |||
150 | 60 | int av_audio_fifo_peek_at(const AVAudioFifo *af, void * const *data, | |
151 | int nb_samples, int offset) | ||
152 | { | ||
153 | int i, ret, size; | ||
154 | |||
155 |
2/4✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
|
60 | if (offset < 0 || offset >= af->nb_samples) |
156 | ✗ | return AVERROR(EINVAL); | |
157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (nb_samples < 0) |
158 | ✗ | return AVERROR(EINVAL); | |
159 | 60 | nb_samples = FFMIN(nb_samples, af->nb_samples); | |
160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (!nb_samples) |
161 | ✗ | return 0; | |
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (offset > af->nb_samples - nb_samples) |
163 | ✗ | return AVERROR(EINVAL); | |
164 | |||
165 | 60 | offset *= af->sample_size; | |
166 | 60 | size = nb_samples * af->sample_size; | |
167 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 60 times.
|
141 | for (i = 0; i < af->nb_buffers; i++) { |
168 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
|
81 | if ((ret = av_fifo_peek(af->buf[i], data[i], size, offset)) < 0) |
169 | ✗ | return AVERROR_BUG; | |
170 | } | ||
171 | |||
172 | 60 | return nb_samples; | |
173 | } | ||
174 | |||
175 | 27830 | int av_audio_fifo_read(AVAudioFifo *af, void * const *data, int nb_samples) | |
176 | { | ||
177 | int i, size; | ||
178 | |||
179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27830 times.
|
27830 | if (nb_samples < 0) |
180 | ✗ | return AVERROR(EINVAL); | |
181 | 27830 | nb_samples = FFMIN(nb_samples, af->nb_samples); | |
182 |
2/2✓ Branch 0 taken 26278 times.
✓ Branch 1 taken 1552 times.
|
27830 | if (!nb_samples) |
183 | 26278 | return 0; | |
184 | |||
185 | 1552 | size = nb_samples * af->sample_size; | |
186 |
2/2✓ Branch 0 taken 1555 times.
✓ Branch 1 taken 1552 times.
|
3107 | for (i = 0; i < af->nb_buffers; i++) { |
187 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1555 times.
|
1555 | if (av_fifo_read(af->buf[i], data[i], size) < 0) |
188 | ✗ | return AVERROR_BUG; | |
189 | } | ||
190 | 1552 | af->nb_samples -= nb_samples; | |
191 | |||
192 | 1552 | return nb_samples; | |
193 | } | ||
194 | |||
195 | 6 | int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) | |
196 | { | ||
197 | int i, size; | ||
198 | |||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (nb_samples < 0) |
200 | ✗ | return AVERROR(EINVAL); | |
201 | 6 | nb_samples = FFMIN(nb_samples, af->nb_samples); | |
202 | |||
203 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (nb_samples) { |
204 | 6 | size = nb_samples * af->sample_size; | |
205 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
|
15 | for (i = 0; i < af->nb_buffers; i++) |
206 | 9 | av_fifo_drain2(af->buf[i], size); | |
207 | 6 | af->nb_samples -= nb_samples; | |
208 | } | ||
209 | 6 | return 0; | |
210 | } | ||
211 | |||
212 | ✗ | void av_audio_fifo_reset(AVAudioFifo *af) | |
213 | { | ||
214 | int i; | ||
215 | |||
216 | ✗ | for (i = 0; i < af->nb_buffers; i++) | |
217 | ✗ | av_fifo_reset2(af->buf[i]); | |
218 | |||
219 | ✗ | af->nb_samples = 0; | |
220 | ✗ | } | |
221 | |||
222 | 112154 | int av_audio_fifo_size(AVAudioFifo *af) | |
223 | { | ||
224 | 112154 | return af->nb_samples; | |
225 | } | ||
226 | |||
227 | 6543 | int av_audio_fifo_space(AVAudioFifo *af) | |
228 | { | ||
229 | 6543 | return af->allocated_samples - af->nb_samples; | |
230 | } | ||
231 |