Really fixes hangs and infinite loops.
Unified · Split
| @@ -41,6 +41,7 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | #include "audio.h" |
| 43 | 43 | #include "avfilter.h" |
| 44 | +#include "filters.h" | |
| 44 | 45 | #include "formats.h" |
| 45 | 46 | #include "internal.h" |
| 46 | 47 | |
| @@ -151,6 +152,7 @@ static int frame_list_add_frame(FrameList *frame_list, int nb_samples, int64_t p · 104 unmodified lines | ||
| 151 | 152 | return 0; |
| 152 | 153 | } |
| 153 | 154 | |
| 155 | +/* FIXME: use directly links fifo */ | |
| 154 | 156 | |
| 155 | 157 | typedef struct MixContext { |
| 156 | 158 | const AVClass *class; /**< class for AVOptions */ |
| @@ -263,21 +265,15 @@ static int config_output(AVFilterLink *outlink) · 106 unmodified lines | ||
| 263 | 265 | return 0; |
| 264 | 266 | } |
| 265 | 267 | |
| 266 | −static int calc_active_inputs(MixContext *s); | |
| 267 | − | |
| 268 | 268 | /** |
| 269 | 269 | * Read samples from the input FIFOs, mix, and write to the output link. |
| 270 | 270 | */ |
| 271 | −static int output_frame(AVFilterLink *outlink, int need_request) | |
| 271 | +static int output_frame(AVFilterLink *outlink) | |
| 272 | 272 | { |
| 273 | 273 | AVFilterContext *ctx = outlink->src; |
| 274 | 274 | MixContext *s = ctx->priv; |
| 275 | 275 | AVFrame *out_buf, *in_buf; |
| 276 | − int nb_samples, ns, ret, i; | |
| 277 | − | |
| 278 | − ret = calc_active_inputs(s); | |
| 279 | − if (ret < 0) | |
| 280 | − return ret; | |
| 276 | + int nb_samples, ns, i; | |
| 281 | 277 | |
| 282 | 278 | if (s->input_state[0] & INPUT_ON) { |
| 283 | 279 | /* first input live: use the corresponding frame size */ |
| @@ -288,7 +284,7 @@ static int output_frame(AVFilterLink *outlink, int need_request) · 4 unmodified lines | ||
| 288 | 284 | if (ns < nb_samples) { |
| 289 | 285 | if (!(s->input_state[i] & INPUT_EOF)) |
| 290 | 286 | /* unclosed input with not enough samples */ |
| 291 | − return need_request ? ff_request_frame(ctx->inputs[i]) : 0; | |
| 287 | + return 0; | |
| 292 | 288 | /* closed input to drain */ |
| 293 | 289 | nb_samples = ns; |
| 294 | 290 | } |
| @@ -303,8 +299,10 @@ static int output_frame(AVFilterLink *outlink, int need_request) · 8 unmodified lines | ||
| 303 | 299 | nb_samples = FFMIN(nb_samples, ns); |
| 304 | 300 | } |
| 305 | 301 | } |
| 306 | − if (nb_samples == INT_MAX) | |
| 307 | − return AVERROR_EOF; | |
| 302 | + if (nb_samples == INT_MAX) { | |
| 303 | + ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); | |
| 304 | + return 0; | |
| 305 | + } | |
| 308 | 306 | } |
| 309 | 307 | |
| 310 | 308 | s->next_pts = frame_list_next_pts(s->frame_list); |
| @@ -367,27 +365,18 @@ static int output_frame(AVFilterLink *outlink, int need_request) · 56 unmodified lines | ||
| 367 | 365 | static int request_samples(AVFilterContext *ctx, int min_samples) |
| 368 | 366 | { |
| 369 | 367 | MixContext *s = ctx->priv; |
| 370 | − int i, ret; | |
| 368 | + int i; | |
| 371 | 369 | |
| 372 | 370 | av_assert0(s->nb_inputs > 1); |
| 373 | 371 | |
| 374 | 372 | for (i = 1; i < s->nb_inputs; i++) { |
| 375 | − ret = 0; | |
| 376 | 373 | if (!(s->input_state[i] & INPUT_ON)) |
| 377 | 374 | continue; |
| 378 | 375 | if (av_audio_fifo_size(s->fifos[i]) >= min_samples) |
| 379 | 376 | continue; |
| 380 | − ret = ff_request_frame(ctx->inputs[i]); | |
| 381 | − if (ret == AVERROR_EOF) { | |
| 382 | − s->input_state[i] |= INPUT_EOF; | |
| 383 | − if (av_audio_fifo_size(s->fifos[i]) == 0) { | |
| 384 | − s->input_state[i] = 0; | |
| 385 | − continue; | |
| 386 | − } | |
| 387 | − } else if (ret < 0) | |
| 388 | − return ret; | |
| 377 | + ff_inlink_request_frame(ctx->inputs[i]); | |
| 389 | 378 | } |
| 390 | − return output_frame(ctx->outputs[0], 1); | |
| 379 | + return output_frame(ctx->outputs[0]); | |
| 391 | 380 | } |
| 392 | 381 | |
| 393 | 382 | /** |
| @@ -411,73 +400,87 @@ static int calc_active_inputs(MixContext *s) · 17 unmodified lines | ||
| 411 | 400 | return 0; |
| 412 | 401 | } |
| 413 | 402 | |
| 414 | −static int request_frame(AVFilterLink *outlink) | |
| 403 | +static int activate(AVFilterContext *ctx) | |
| 415 | 404 | { |
| 416 | − AVFilterContext *ctx = outlink->src; | |
| 417 | − MixContext *s = ctx->priv; | |
| 418 | − int ret; | |
| 419 | − int wanted_samples; | |
| 420 | − | |
| 421 | − ret = calc_active_inputs(s); | |
| 422 | − if (ret < 0) | |
| 423 | − return ret; | |
| 424 | − | |
| 425 | − if (!(s->input_state[0] & INPUT_ON)) | |
| 426 | − return request_samples(ctx, 1); | |
| 427 | − | |
| 428 | − if (s->frame_list->nb_frames == 0) { | |
| 429 | − ret = ff_request_frame(ctx->inputs[0]); | |
| 430 | − if (ret == AVERROR_EOF) { | |
| 431 | − s->input_state[0] = 0; | |
| 432 | − if (s->nb_inputs == 1) | |
| 433 | − return AVERROR_EOF; | |
| 434 | − return output_frame(ctx->outputs[0], 1); | |
| 435 | − } | |
| 436 | − return ret; | |
| 437 | − } | |
| 438 | − av_assert0(s->frame_list->nb_frames > 0); | |
| 405 | + AVFilterLink *outlink = ctx->outputs[0]; | |
| 406 | + MixContext *s = ctx->priv; | |
| 407 | + AVFrame *buf = NULL; | |
| 408 | + int i, ret; | |
| 439 | 409 | |
| 440 | − wanted_samples = frame_list_next_frame_size(s->frame_list); | |
| 410 | + for (i = 0; i < s->nb_inputs; i++) { | |
| 411 | + AVFilterLink *inlink = ctx->inputs[i]; | |
| 412 | + | |
| 413 | + if ((ret = ff_inlink_consume_frame(ctx->inputs[i], &buf)) > 0) { | |
| 414 | + if (i == 0) { | |
| 415 | + int64_t pts = av_rescale_q(buf->pts, inlink->time_base, | |
| 416 | + outlink->time_base); | |
| 417 | + ret = frame_list_add_frame(s->frame_list, buf->nb_samples, pts); | |
| 418 | + if (ret < 0) { | |
| 419 | + av_frame_free(&buf); | |
| 420 | + return ret; | |
| 421 | + } | |
| 422 | + } | |
| 441 | 423 | |
| 442 | − return request_samples(ctx, wanted_samples); | |
| 443 | −} | |
| 424 | + ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, | |
| 425 | + buf->nb_samples); | |
| 426 | + if (ret < 0) { | |
| 427 | + av_frame_free(&buf); | |
| 428 | + return ret; | |
| 429 | + } | |
| 444 | 430 | |
| 445 | −static int filter_frame(AVFilterLink *inlink, AVFrame *buf) | |
| 446 | −{ | |
| 447 | − AVFilterContext *ctx = inlink->dst; | |
| 448 | − MixContext *s = ctx->priv; | |
| 449 | − AVFilterLink *outlink = ctx->outputs[0]; | |
| 450 | − int i, ret = 0; | |
| 431 | + av_frame_free(&buf); | |
| 451 | 432 | |
| 452 | − for (i = 0; i < ctx->nb_inputs; i++) | |
| 453 | − if (ctx->inputs[i] == inlink) | |
| 454 | − break; | |
| 455 | − if (i >= ctx->nb_inputs) { | |
| 456 | − av_log(ctx, AV_LOG_ERROR, "unknown input link\n"); | |
| 457 | − ret = AVERROR(EINVAL); | |
| 458 | − goto fail; | |
| 433 | + ret = output_frame(outlink); | |
| 434 | + if (ret < 0) | |
| 435 | + return ret; | |
| 436 | + } | |
| 459 | 437 | } |
| 460 | 438 | |
| 461 | − if (i == 0) { | |
| 462 | − int64_t pts = av_rescale_q(buf->pts, inlink->time_base, | |
| 463 | − outlink->time_base); | |
| 464 | − ret = frame_list_add_frame(s->frame_list, buf->nb_samples, pts); | |
| 465 | − if (ret < 0) | |
| 466 | − goto fail; | |
| 439 | + for (i = 0; i < s->nb_inputs; i++) { | |
| 440 | + int64_t pts; | |
| 441 | + int status; | |
| 442 | + | |
| 443 | + if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) { | |
| 444 | + if (status == AVERROR_EOF) { | |
| 445 | + if (i == 0) { | |
| 446 | + s->input_state[i] = 0; | |
| 447 | + if (s->nb_inputs == 1) { | |
| 448 | + ff_outlink_set_status(outlink, status, pts); | |
| 449 | + return 0; | |
| 450 | + } | |
| 451 | + } else { | |
| 452 | + s->input_state[i] |= INPUT_EOF; | |
| 453 | + if (av_audio_fifo_size(s->fifos[i]) == 0) { | |
| 454 | + s->input_state[i] = 0; | |
| 455 | + } | |
| 456 | + } | |
| 457 | + } | |
| 458 | + } | |
| 467 | 459 | } |
| 468 | 460 | |
| 469 | − ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, | |
| 470 | − buf->nb_samples); | |
| 471 | − if (ret < 0) | |
| 472 | − goto fail; | |
| 461 | + if (calc_active_inputs(s)) { | |
| 462 | + ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); | |
| 463 | + return 0; | |
| 464 | + } | |
| 473 | 465 | |
| 474 | − av_frame_free(&buf); | |
| 475 | − return output_frame(outlink, 0); | |
| 466 | + if (ff_outlink_frame_wanted(outlink)) { | |
| 467 | + int wanted_samples; | |
| 476 | 468 | |
| 477 | −fail: | |
| 478 | − av_frame_free(&buf); | |
| 469 | + if (!(s->input_state[0] & INPUT_ON)) | |
| 470 | + return request_samples(ctx, 1); | |
| 479 | 471 | |
| 480 | − return ret; | |
| 472 | + if (s->frame_list->nb_frames == 0) { | |
| 473 | + ff_inlink_request_frame(ctx->inputs[0]); | |
| 474 | + return 0; | |
| 475 | + } | |
| 476 | + av_assert0(s->frame_list->nb_frames > 0); | |
| 477 | + | |
| 478 | + wanted_samples = frame_list_next_frame_size(s->frame_list); | |
| 479 | + | |
| 480 | + return request_samples(ctx, wanted_samples); | |
| 481 | + } | |
| 482 | + | |
| 483 | + return 0; | |
| 481 | 484 | } |
| 482 | 485 | |
| 483 | 486 | static av_cold int init(AVFilterContext *ctx) |
| @@ -494,7 +497,6 @@ static av_cold int init(AVFilterContext *ctx) · 10 unmodified lines | ||
| 494 | 497 | pad.name = av_strdup(name); |
| 495 | 498 | if (!pad.name) |
| 496 | 499 | return AVERROR(ENOMEM); |
| 497 | − pad.filter_frame = filter_frame; | |
| 498 | 500 | |
| 499 | 501 | if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { |
| 500 | 502 | av_freep(&pad.name); |
| @@ -562,7 +564,6 @@ static const AVFilterPad avfilter_af_amix_outputs[] = { · 61 unmodified lines | ||
| 562 | 564 | .name = "default", |
| 563 | 565 | .type = AVMEDIA_TYPE_AUDIO, |
| 564 | 566 | .config_props = config_output, |
| 565 | − .request_frame = request_frame | |
| 566 | 567 | }, |
| 567 | 568 | { NULL } |
| 568 | 569 | }; |
| @@ -574,6 +575,7 @@ AVFilter ff_af_amix = { · 5 unmodified lines | ||
| 574 | 575 | .priv_class = &amix_class, |
| 575 | 576 | .init = init, |
| 576 | 577 | .uninit = uninit, |
| 578 | + .activate = activate, | |
| 577 | 579 | .query_formats = query_formats, |
| 578 | 580 | .inputs = NULL, |
| 579 | 581 | .outputs = avfilter_af_amix_outputs, |