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