Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 "avutil.h" | |
28 | #include "audio_fifo.h" | |
29 | #include "common.h" | |
30 | #include "fifo.h" | |
31 | #include "mem.h" | |
32 | #include "samplefmt.h" | |
33 | ||
34 | struct AVAudioFifo { | |
35 | AVFifoBuffer **buf; /**< single buffer for interleaved, per-channel buffers for planar */ | |
36 | int nb_buffers; /**< number of buffers */ | |
37 | int nb_samples; /**< number of samples currently in the FIFO */ | |
38 | int allocated_samples; /**< current allocated size, in samples */ | |
39 | ||
40 | int channels; /**< number of channels */ | |
41 | enum AVSampleFormat sample_fmt; /**< sample format */ | |
42 | int sample_size; /**< size, in bytes, of one sample in a buffer */ | |
43 | }; | |
44 | ||
45 | void av_audio_fifo_free(AVAudioFifo *af) | |
46 | { | |
47 | if (af) { | |
48 | if (af->buf) { | |
49 | int i; | |
50 | for (i = 0; i < af->nb_buffers; i++) { | |
51 | if (af->buf[i]) | |
52 | av_fifo_free(af->buf[i]); | |
53 | } | |
54 | av_free(af->buf); | |
55 | } | |
56 | av_free(af); | |
57 | } | |
58 | } | |
59 | ||
60 | AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, | |
61 | int nb_samples) | |
62 | { | |
63 | AVAudioFifo *af; | |
64 | int buf_size, i; | |
65 | ||
66 | /* get channel buffer size (also validates parameters) */ | |
67 | if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) | |
68 | return NULL; | |
69 | ||
70 | af = av_mallocz(sizeof(*af)); | |
71 | if (!af) | |
72 | return NULL; | |
73 | ||
74 | af->channels = channels; | |
75 | af->sample_fmt = sample_fmt; | |
76 | af->sample_size = buf_size / nb_samples; | |
77 | af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; | |
78 | ||
79 | af->buf = av_mallocz_array(af->nb_buffers, sizeof(*af->buf)); | |
80 | if (!af->buf) | |
81 | goto error; | |
82 | ||
83 | for (i = 0; i < af->nb_buffers; i++) { | |
84 | af->buf[i] = av_fifo_alloc(buf_size); | |
85 | if (!af->buf[i]) | |
86 | goto error; | |
87 | } | |
88 | af->allocated_samples = nb_samples; | |
89 | ||
90 | return af; | |
91 | ||
92 | error: | |
93 | av_audio_fifo_free(af); | |
94 | return NULL; | |
95 | } | |
96 | ||
97 | int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) | |
98 | { | |
99 | int i, ret, buf_size; | |
100 | ||
101 | if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, | |
102 | af->sample_fmt, 1)) < 0) | |
103 | return ret; | |
104 | ||
105 | for (i = 0; i < af->nb_buffers; i++) { | |
106 | if ((ret = av_fifo_realloc2(af->buf[i], buf_size)) < 0) | |
107 | return ret; | |
108 | } | |
109 | af->allocated_samples = nb_samples; | |
110 | return 0; | |
111 | } | |
112 | ||
113 | int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples) | |
114 | { | |
115 | int i, ret, size; | |
116 | ||
117 | /* automatically reallocate buffers if needed */ | |
118 | if (av_audio_fifo_space(af) < nb_samples) { | |
119 | int current_size = av_audio_fifo_size(af); | |
120 | /* check for integer overflow in new size calculation */ | |
121 | if (INT_MAX / 2 - current_size < nb_samples) | |
122 | return AVERROR(EINVAL); | |
123 | /* reallocate buffers */ | |
124 | if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) | |
125 | return ret; | |
126 | } | |
127 | ||
128 | size = nb_samples * af->sample_size; | |
129 | for (i = 0; i < af->nb_buffers; i++) { | |
130 | ret = av_fifo_generic_write(af->buf[i], data[i], size, NULL); | |
131 | if (ret != size) | |
132 | return AVERROR_BUG; | |
133 | } | |
134 | af->nb_samples += nb_samples; | |
135 | ||
136 | return nb_samples; | |
137 | } | |
138 | ||
139 | int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples) | |
140 | { | |
141 | int i, ret, size; | |
142 | ||
143 | if (nb_samples < 0) | |
144 | return AVERROR(EINVAL); | |
145 | nb_samples = FFMIN(nb_samples, af->nb_samples); | |
146 | if (!nb_samples) | |
147 | return 0; | |
148 | ||
149 | size = nb_samples * af->sample_size; | |
150 | for (i = 0; i < af->nb_buffers; i++) { | |
151 | if ((ret = av_fifo_generic_read(af->buf[i], data[i], size, NULL)) < 0) | |
152 | return AVERROR_BUG; | |
153 | } | |
154 | af->nb_samples -= nb_samples; | |
155 | ||
156 | return nb_samples; | |
157 | } | |
158 | ||
159 | int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) | |
160 | { | |
161 | int i, size; | |
162 | ||
163 | if (nb_samples < 0) | |
164 | return AVERROR(EINVAL); | |
165 | nb_samples = FFMIN(nb_samples, af->nb_samples); | |
166 | ||
167 | if (nb_samples) { | |
168 | size = nb_samples * af->sample_size; | |
169 | for (i = 0; i < af->nb_buffers; i++) | |
170 | av_fifo_drain(af->buf[i], size); | |
171 | af->nb_samples -= nb_samples; | |
172 | } | |
173 | return 0; | |
174 | } | |
175 | ||
176 | void av_audio_fifo_reset(AVAudioFifo *af) | |
177 | { | |
178 | int i; | |
179 | ||
180 | for (i = 0; i < af->nb_buffers; i++) | |
181 | av_fifo_reset(af->buf[i]); | |
182 | ||
183 | af->nb_samples = 0; | |
184 | } | |
185 | ||
186 | int av_audio_fifo_size(AVAudioFifo *af) | |
187 | { | |
188 | return af->nb_samples; | |
189 | } | |
190 | ||
191 | int av_audio_fifo_space(AVAudioFifo *af) | |
192 | { | |
193 | return af->allocated_samples - af->nb_samples; | |
194 | } |