Even in cases where sch_start() failed. This ensures all links are properly closed and no tasks are left hanging. Fixes #10916.
Unified · Split
| @@ -260,6 +260,12 @@ typedef struct SchFilterGraph { · 259 unmodified lines | |||
| 260 | int task_exited; | 260 | int task_exited; |
| 261 | } SchFilterGraph; | 261 | } SchFilterGraph; |
| 262 | 262 | ||
| 263 | enum SchedulerState { | ||
| 264 | SCH_STATE_UNINIT, | ||
| 265 | SCH_STATE_STARTED, | ||
| 266 | SCH_STATE_STOPPED, | ||
| 267 | }; | ||
| 268 | |||
| 263 | struct Scheduler { | 269 | struct Scheduler { |
| 264 | const AVClass *class; | 270 | const AVClass *class; |
| 265 | 271 | ||
| @@ -292,7 +298,7 @@ struct Scheduler { · 26 unmodified lines | |||
| 292 | char *sdp_filename; | 298 | char *sdp_filename; |
| 293 | int sdp_auto; | 299 | int sdp_auto; |
| 294 | 300 | ||
| 295 | int transcode_started; | 301 | enum SchedulerState state; |
| 296 | atomic_int terminate; | 302 | atomic_int terminate; |
| 297 | atomic_int task_failed; | 303 | atomic_int task_failed; |
| 298 | 304 | ||
| @@ -1144,7 +1150,8 @@ int sch_mux_stream_ready(Scheduler *sch, unsigned mux_idx, unsigned stream_idx) · 845 unmodified lines | |||
| 1144 | 1150 | ||
| 1145 | // this may be called during initialization - do not start | 1151 | // this may be called during initialization - do not start |
| 1146 | // threads before sch_start() is called | 1152 | // threads before sch_start() is called |
| 1147 | if (++mux->nb_streams_ready == mux->nb_streams && sch->transcode_started) | 1153 | if (++mux->nb_streams_ready == mux->nb_streams && |
| 1154 | sch->state >= SCH_STATE_STARTED) | ||
| 1148 | ret = mux_init(sch, mux); | 1155 | ret = mux_init(sch, mux); |
| 1149 | 1156 | ||
| 1150 | pthread_mutex_unlock(&sch->mux_ready_lock); | 1157 | pthread_mutex_unlock(&sch->mux_ready_lock); |
| @@ -1514,7 +1521,8 @@ int sch_start(Scheduler *sch) · 363 unmodified lines | |||
| 1514 | if (ret < 0) | 1521 | if (ret < 0) |
| 1515 | return ret; | 1522 | return ret; |
| 1516 | 1523 | ||
| 1517 | sch->transcode_started = 1; | 1524 | av_assert0(sch->state == SCH_STATE_UNINIT); |
| 1525 | sch->state = SCH_STATE_STARTED; | ||
| 1518 | 1526 | ||
| 1519 | for (unsigned i = 0; i < sch->nb_mux; i++) { | 1527 | for (unsigned i = 0; i < sch->nb_mux; i++) { |
| 1520 | SchMux *mux = &sch->mux[i]; | 1528 | SchMux *mux = &sch->mux[i]; |
| @@ -1522,7 +1530,7 @@ int sch_start(Scheduler *sch) · 1 unmodified line | |||
| 1522 | if (mux->nb_streams_ready == mux->nb_streams) { | 1530 | if (mux->nb_streams_ready == mux->nb_streams) { |
| 1523 | ret = mux_init(sch, mux); | 1531 | ret = mux_init(sch, mux); |
| 1524 | if (ret < 0) | 1532 | if (ret < 0) |
| 1525 | return ret; | 1533 | goto fail; |
| 1526 | } | 1534 | } |
| 1527 | } | 1535 | } |
| 1528 | 1536 | ||
| @@ -1531,7 +1539,7 @@ int sch_start(Scheduler *sch) · 2 unmodified lines | |||
| 1531 | 1539 | ||
| 1532 | ret = task_start(&enc->task); | 1540 | ret = task_start(&enc->task); |
| 1533 | if (ret < 0) | 1541 | if (ret < 0) |
| 1534 | return ret; | 1542 | goto fail; |
| 1535 | } | 1543 | } |
| 1536 | 1544 | ||
| 1537 | for (unsigned i = 0; i < sch->nb_filters; i++) { | 1545 | for (unsigned i = 0; i < sch->nb_filters; i++) { |
| @@ -1539,7 +1547,7 @@ int sch_start(Scheduler *sch) · 1 unmodified line | |||
| 1539 | 1547 | ||
| 1540 | ret = task_start(&fg->task); | 1548 | ret = task_start(&fg->task); |
| 1541 | if (ret < 0) | 1549 | if (ret < 0) |
| 1542 | return ret; | 1550 | goto fail; |
| 1543 | } | 1551 | } |
| 1544 | 1552 | ||
| 1545 | for (unsigned i = 0; i < sch->nb_dec; i++) { | 1553 | for (unsigned i = 0; i < sch->nb_dec; i++) { |
| @@ -1547,7 +1555,7 @@ int sch_start(Scheduler *sch) · 1 unmodified line | |||
| 1547 | 1555 | ||
| 1548 | ret = task_start(&dec->task); | 1556 | ret = task_start(&dec->task); |
| 1549 | if (ret < 0) | 1557 | if (ret < 0) |
| 1550 | return ret; | 1558 | goto fail; |
| 1551 | } | 1559 | } |
| 1552 | 1560 | ||
| 1553 | for (unsigned i = 0; i < sch->nb_demux; i++) { | 1561 | for (unsigned i = 0; i < sch->nb_demux; i++) { |
| @@ -1558,7 +1566,7 @@ int sch_start(Scheduler *sch) · 4 unmodified lines | |||
| 1558 | 1566 | ||
| 1559 | ret = task_start(&d->task); | 1567 | ret = task_start(&d->task); |
| 1560 | if (ret < 0) | 1568 | if (ret < 0) |
| 1561 | return ret; | 1569 | goto fail; |
| 1562 | } | 1570 | } |
| 1563 | 1571 | ||
| 1564 | pthread_mutex_lock(&sch->schedule_lock); | 1572 | pthread_mutex_lock(&sch->schedule_lock); |
| @@ -1566,6 +1574,9 @@ int sch_start(Scheduler *sch) · 1 unmodified line | |||
| 1566 | pthread_mutex_unlock(&sch->schedule_lock); | 1574 | pthread_mutex_unlock(&sch->schedule_lock); |
| 1567 | 1575 | ||
| 1568 | return 0; | 1576 | return 0; |
| 1577 | fail: | ||
| 1578 | sch_stop(sch, NULL); | ||
| 1579 | return ret; | ||
| 1569 | } | 1580 | } |
| 1570 | 1581 | ||
| 1571 | int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts) | 1582 | int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts) |
| @@ -2412,6 +2423,18 @@ int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame) · 840 unmodified lines | |||
| 2412 | return send_to_filter(sch, fg, fg->nb_inputs, frame); | 2423 | return send_to_filter(sch, fg, fg->nb_inputs, frame); |
| 2413 | } | 2424 | } |
| 2414 | 2425 | ||
| 2426 | static int task_cleanup(Scheduler *sch, SchedulerNode node) | ||
| 2427 | { | ||
| 2428 | switch (node.type) { | ||
| 2429 | case SCH_NODE_TYPE_DEMUX: return demux_done (sch, node.idx); | ||
| 2430 | case SCH_NODE_TYPE_MUX: return mux_done (sch, node.idx); | ||
| 2431 | case SCH_NODE_TYPE_DEC: return dec_done (sch, node.idx); | ||
| 2432 | case SCH_NODE_TYPE_ENC: return enc_done (sch, node.idx); | ||
| 2433 | case SCH_NODE_TYPE_FILTER_IN: return filter_done(sch, node.idx); | ||
| 2434 | default: av_assert0(0); | ||
| 2435 | } | ||
| 2436 | } | ||
| 2437 | |||
| 2415 | static void *task_wrapper(void *arg) | 2438 | static void *task_wrapper(void *arg) |
| 2416 | { | 2439 | { |
| 2417 | SchTask *task = arg; | 2440 | SchTask *task = arg; |
| @@ -2424,15 +2447,7 @@ static void *task_wrapper(void *arg) · 6 unmodified lines | |||
| 2424 | av_log(task->func_arg, AV_LOG_ERROR, | 2447 | av_log(task->func_arg, AV_LOG_ERROR, |
| 2425 | "Task finished with error code: %d (%s)\n", ret, av_err2str(ret)); | 2448 | "Task finished with error code: %d (%s)\n", ret, av_err2str(ret)); |
| 2426 | 2449 | ||
| 2427 | switch (task->node.type) { | 2450 | err = task_cleanup(sch, task->node); |
| 2428 | case SCH_NODE_TYPE_DEMUX: err = demux_done (sch, task->node.idx); break; | ||
| 2429 | case SCH_NODE_TYPE_MUX: err = mux_done (sch, task->node.idx); break; | ||
| 2430 | case SCH_NODE_TYPE_DEC: err = dec_done (sch, task->node.idx); break; | ||
| 2431 | case SCH_NODE_TYPE_ENC: err = enc_done (sch, task->node.idx); break; | ||
| 2432 | case SCH_NODE_TYPE_FILTER_IN: err = filter_done(sch, task->node.idx); break; | ||
| 2433 | default: av_assert0(0); | ||
| 2434 | } | ||
| 2435 | |||
| 2436 | ret = err_merge(ret, err); | 2451 | ret = err_merge(ret, err); |
| 2437 | 2452 | ||
| 2438 | // EOF is considered normal termination | 2453 | // EOF is considered normal termination |
| @@ -2448,13 +2463,13 @@ static void *task_wrapper(void *arg) · 9 unmodified lines | |||
| 2448 | return (void*)(intptr_t)ret; | 2463 | return (void*)(intptr_t)ret; |
| 2449 | } | 2464 | } |
| 2450 | 2465 | ||
| 2451 | static int task_stop(SchTask *task) | 2466 | static int task_stop(Scheduler *sch, SchTask *task) |
| 2452 | { | 2467 | { |
| 2453 | int ret; | 2468 | int ret; |
| 2454 | void *thread_ret; | 2469 | void *thread_ret; |
| 2455 | 2470 | ||
| 2456 | if (!task->thread_running) | 2471 | if (!task->thread_running) |
| 2457 | return 0; | 2472 | return task_cleanup(sch, task->node); |
| 2458 | 2473 | ||
| 2459 | ret = pthread_join(task->thread, &thread_ret); | 2474 | ret = pthread_join(task->thread, &thread_ret); |
| 2460 | av_assert0(ret == 0); | 2475 | av_assert0(ret == 0); |
| @@ -2468,6 +2483,9 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts) · 7 unmodified lines | |||
| 2468 | { | 2483 | { |
| 2469 | int ret = 0, err; | 2484 | int ret = 0, err; |
| 2470 | 2485 | ||
| 2486 | if (sch->state != SCH_STATE_STARTED) | ||
| 2487 | return 0; | ||
| 2488 | |||
| 2471 | atomic_store(&sch->terminate, 1); | 2489 | atomic_store(&sch->terminate, 1); |
| 2472 | 2490 | ||
| 2473 | for (unsigned type = 0; type < 2; type++) | 2491 | for (unsigned type = 0; type < 2; type++) |
| @@ -2479,40 +2497,42 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts) · 5 unmodified lines | |||
| 2479 | for (unsigned i = 0; i < sch->nb_demux; i++) { | 2497 | for (unsigned i = 0; i < sch->nb_demux; i++) { |
| 2480 | SchDemux *d = &sch->demux[i]; | 2498 | SchDemux *d = &sch->demux[i]; |
| 2481 | 2499 | ||
| 2482 | err = task_stop(&d->task); | 2500 | err = task_stop(sch, &d->task); |
| 2483 | ret = err_merge(ret, err); | 2501 | ret = err_merge(ret, err); |
| 2484 | } | 2502 | } |
| 2485 | 2503 | ||
| 2486 | for (unsigned i = 0; i < sch->nb_dec; i++) { | 2504 | for (unsigned i = 0; i < sch->nb_dec; i++) { |
| 2487 | SchDec *dec = &sch->dec[i]; | 2505 | SchDec *dec = &sch->dec[i]; |
| 2488 | 2506 | ||
| 2489 | err = task_stop(&dec->task); | 2507 | err = task_stop(sch, &dec->task); |
| 2490 | ret = err_merge(ret, err); | 2508 | ret = err_merge(ret, err); |
| 2491 | } | 2509 | } |
| 2492 | 2510 | ||
| 2493 | for (unsigned i = 0; i < sch->nb_filters; i++) { | 2511 | for (unsigned i = 0; i < sch->nb_filters; i++) { |
| 2494 | SchFilterGraph *fg = &sch->filters[i]; | 2512 | SchFilterGraph *fg = &sch->filters[i]; |
| 2495 | 2513 | ||
| 2496 | err = task_stop(&fg->task); | 2514 | err = task_stop(sch, &fg->task); |
| 2497 | ret = err_merge(ret, err); | 2515 | ret = err_merge(ret, err); |
| 2498 | } | 2516 | } |
| 2499 | 2517 | ||
| 2500 | for (unsigned i = 0; i < sch->nb_enc; i++) { | 2518 | for (unsigned i = 0; i < sch->nb_enc; i++) { |
| 2501 | SchEnc *enc = &sch->enc[i]; | 2519 | SchEnc *enc = &sch->enc[i]; |
| 2502 | 2520 | ||
| 2503 | err = task_stop(&enc->task); | 2521 | err = task_stop(sch, &enc->task); |
| 2504 | ret = err_merge(ret, err); | 2522 | ret = err_merge(ret, err); |
| 2505 | } | 2523 | } |
| 2506 | 2524 | ||
| 2507 | for (unsigned i = 0; i < sch->nb_mux; i++) { | 2525 | for (unsigned i = 0; i < sch->nb_mux; i++) { |
| 2508 | SchMux *mux = &sch->mux[i]; | 2526 | SchMux *mux = &sch->mux[i]; |
| 2509 | 2527 | ||
| 2510 | err = task_stop(&mux->task); | 2528 | err = task_stop(sch, &mux->task); |
| 2511 | ret = err_merge(ret, err); | 2529 | ret = err_merge(ret, err); |
| 2512 | } | 2530 | } |
| 2513 | 2531 | ||
| 2514 | if (finish_ts) | 2532 | if (finish_ts) |
| 2515 | *finish_ts = trailing_dts(sch, 1); | 2533 | *finish_ts = trailing_dts(sch, 1); |
| 2516 | 2534 | ||
| 2535 | sch->state = SCH_STATE_STOPPED; | ||
| 2536 | |||
| 2517 | return ret; | 2537 | return ret; |
| 2518 | } | 2538 | } |