... | ... |
@@ -26,28 +26,27 @@ |
26 | 26 |
#include "libswresample/swresample.h" // only for SWR_CH_MAX |
27 | 27 |
#include "avfilter.h" |
28 | 28 |
#include "audio.h" |
29 |
+#include "bufferqueue.h" |
|
29 | 30 |
#include "internal.h" |
30 | 31 |
|
31 |
-#define QUEUE_SIZE 16 |
|
32 |
- |
|
33 | 32 |
typedef struct { |
34 | 33 |
int nb_in_ch[2]; /**< number of channels for each input */ |
35 | 34 |
int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */ |
36 | 35 |
int bps; |
37 |
- struct amerge_queue { |
|
38 |
- AVFilterBufferRef *buf[QUEUE_SIZE]; |
|
39 |
- int nb_buf, nb_samples, pos; |
|
40 |
- } queue[2]; |
|
36 |
+ struct amerge_input { |
|
37 |
+ struct FFBufQueue queue; |
|
38 |
+ int nb_samples; |
|
39 |
+ int pos; |
|
40 |
+ } in[2]; |
|
41 | 41 |
} AMergeContext; |
42 | 42 |
|
43 | 43 |
static av_cold void uninit(AVFilterContext *ctx) |
44 | 44 |
{ |
45 | 45 |
AMergeContext *am = ctx->priv; |
46 |
- int i, j; |
|
46 |
+ int i; |
|
47 | 47 |
|
48 | 48 |
for (i = 0; i < 2; i++) |
49 |
- for (j = 0; j < am->queue[i].nb_buf; j++) |
|
50 |
- avfilter_unref_buffer(am->queue[i].buf[j]); |
|
49 |
+ ff_bufqueue_discard_all(&am->in[i].queue); |
|
51 | 50 |
} |
52 | 51 |
|
53 | 52 |
static int query_formats(AVFilterContext *ctx) |
... | ... |
@@ -144,7 +143,7 @@ static int request_frame(AVFilterLink *outlink) |
144 | 144 |
int i, ret; |
145 | 145 |
|
146 | 146 |
for (i = 0; i < 2; i++) |
147 |
- if (!am->queue[i].nb_samples) |
|
147 |
+ if (!am->in[i].nb_samples) |
|
148 | 148 |
if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0) |
149 | 149 |
return ret; |
150 | 150 |
return 0; |
... | ... |
@@ -189,47 +188,38 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) |
189 | 189 |
AMergeContext *am = ctx->priv; |
190 | 190 |
AVFilterLink *const outlink = ctx->outputs[0]; |
191 | 191 |
int input_number = inlink == ctx->inputs[1]; |
192 |
- struct amerge_queue *inq = &am->queue[input_number]; |
|
193 | 192 |
int nb_samples, ns, i; |
194 |
- AVFilterBufferRef *outbuf, **inbuf[2]; |
|
193 |
+ AVFilterBufferRef *outbuf, *inbuf[2]; |
|
195 | 194 |
uint8_t *ins[2], *outs; |
196 | 195 |
|
197 |
- if (inq->nb_buf == QUEUE_SIZE) { |
|
198 |
- av_log(ctx, AV_LOG_ERROR, "Packet queue overflow; dropped\n"); |
|
199 |
- avfilter_unref_buffer(insamples); |
|
200 |
- return; |
|
201 |
- } |
|
202 |
- inq->buf[inq->nb_buf++] = avfilter_ref_buffer(insamples, AV_PERM_READ | |
|
203 |
- AV_PERM_PRESERVE); |
|
204 |
- inq->nb_samples += insamples->audio->nb_samples; |
|
205 |
- avfilter_unref_buffer(insamples); |
|
206 |
- if (!am->queue[!input_number].nb_samples) |
|
196 |
+ ff_bufqueue_add(ctx, &am->in[input_number].queue, insamples); |
|
197 |
+ am->in[input_number].nb_samples += insamples->audio->nb_samples; |
|
198 |
+ if (!am->in[!input_number].nb_samples) |
|
207 | 199 |
return; |
208 | 200 |
|
209 |
- nb_samples = FFMIN(am->queue[0].nb_samples, |
|
210 |
- am->queue[1].nb_samples); |
|
211 |
- outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE, |
|
212 |
- nb_samples); |
|
201 |
+ nb_samples = FFMIN(am->in[0].nb_samples, |
|
202 |
+ am->in[1].nb_samples); |
|
203 |
+ outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE, nb_samples); |
|
213 | 204 |
outs = outbuf->data[0]; |
214 | 205 |
for (i = 0; i < 2; i++) { |
215 |
- inbuf[i] = am->queue[i].buf; |
|
216 |
- ins[i] = (*inbuf[i])->data[0] + |
|
217 |
- am->queue[i].pos * am->nb_in_ch[i] * am->bps; |
|
206 |
+ inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0); |
|
207 |
+ ins[i] = inbuf[i]->data[0] + |
|
208 |
+ am->in[i].pos * am->nb_in_ch[i] * am->bps; |
|
218 | 209 |
} |
219 |
- outbuf->pts = (*inbuf[0])->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : |
|
220 |
- (*inbuf[0])->pts + |
|
221 |
- av_rescale_q(am->queue[0].pos, |
|
210 |
+ outbuf->pts = inbuf[0]->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : |
|
211 |
+ inbuf[0]->pts + |
|
212 |
+ av_rescale_q(am->in[0].pos, |
|
222 | 213 |
(AVRational){ 1, ctx->inputs[0]->sample_rate }, |
223 | 214 |
ctx->outputs[0]->time_base); |
224 | 215 |
|
225 |
- avfilter_copy_buffer_ref_props(outbuf, *inbuf[0]); |
|
216 |
+ avfilter_copy_buffer_ref_props(outbuf, inbuf[0]); |
|
226 | 217 |
outbuf->audio->nb_samples = nb_samples; |
227 | 218 |
outbuf->audio->channel_layout = outlink->channel_layout; |
228 | 219 |
|
229 | 220 |
while (nb_samples) { |
230 | 221 |
ns = nb_samples; |
231 | 222 |
for (i = 0; i < 2; i++) |
232 |
- ns = FFMIN(ns, (*inbuf[i])->audio->nb_samples - am->queue[i].pos); |
|
223 |
+ ns = FFMIN(ns, inbuf[i]->audio->nb_samples - am->in[i].pos); |
|
233 | 224 |
/* Unroll the most common sample formats: speed +~350% for the loop, |
234 | 225 |
+~13% overall (including two common decoders) */ |
235 | 226 |
switch (am->bps) { |
... | ... |
@@ -249,25 +239,17 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) |
249 | 249 |
|
250 | 250 |
nb_samples -= ns; |
251 | 251 |
for (i = 0; i < 2; i++) { |
252 |
- am->queue[i].nb_samples -= ns; |
|
253 |
- am->queue[i].pos += ns; |
|
254 |
- if (am->queue[i].pos == (*inbuf[i])->audio->nb_samples) { |
|
255 |
- am->queue[i].pos = 0; |
|
256 |
- avfilter_unref_buffer(*inbuf[i]); |
|
257 |
- *inbuf[i] = NULL; |
|
258 |
- inbuf[i]++; |
|
259 |
- ins[i] = *inbuf[i] ? (*inbuf[i])->data[0] : NULL; |
|
252 |
+ am->in[i].nb_samples -= ns; |
|
253 |
+ am->in[i].pos += ns; |
|
254 |
+ if (am->in[i].pos == inbuf[i]->audio->nb_samples) { |
|
255 |
+ am->in[i].pos = 0; |
|
256 |
+ avfilter_unref_buffer(inbuf[i]); |
|
257 |
+ ff_bufqueue_get(&am->in[i].queue); |
|
258 |
+ inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0); |
|
259 |
+ ins[i] = inbuf[i] ? inbuf[i]->data[0] : NULL; |
|
260 | 260 |
} |
261 | 261 |
} |
262 | 262 |
} |
263 |
- for (i = 0; i < 2; i++) { |
|
264 |
- int nbufused = inbuf[i] - am->queue[i].buf; |
|
265 |
- if (nbufused) { |
|
266 |
- am->queue[i].nb_buf -= nbufused; |
|
267 |
- memmove(am->queue[i].buf, inbuf[i], |
|
268 |
- am->queue[i].nb_buf * sizeof(**inbuf)); |
|
269 |
- } |
|
270 |
- } |
|
271 | 263 |
ff_filter_samples(ctx->outputs[0], outbuf); |
272 | 264 |
} |
273 | 265 |
|
... | ... |
@@ -283,11 +265,11 @@ AVFilter avfilter_af_amerge = { |
283 | 283 |
{ .name = "in1", |
284 | 284 |
.type = AVMEDIA_TYPE_AUDIO, |
285 | 285 |
.filter_samples = filter_samples, |
286 |
- .min_perms = AV_PERM_READ, }, |
|
286 |
+ .min_perms = AV_PERM_READ | AV_PERM_PRESERVE, }, |
|
287 | 287 |
{ .name = "in2", |
288 | 288 |
.type = AVMEDIA_TYPE_AUDIO, |
289 | 289 |
.filter_samples = filter_samples, |
290 |
- .min_perms = AV_PERM_READ, }, |
|
290 |
+ .min_perms = AV_PERM_READ | AV_PERM_PRESERVE, }, |
|
291 | 291 |
{ .name = NULL } |
292 | 292 |
}, |
293 | 293 |
.outputs = (const AVFilterPad[]) { |