History

fftools/ffmpeg_sched: make sure to always run task cleanup

Even in cases where sch_start() failed. This ensures all links are properly closed and no tasks are left hanging. Fixes #10916.

Anton Khirnov committed 2 years ago

Commit 24b9f291 parent af817881 file · +44 −24Browse files

Unified · Split

fftools/ffmpeg_sched.c+44−24
@@ -260,6 +260,12 @@ typedef struct SchFilterGraph { · 259 unmodified lines
260 int task_exited;260 int task_exited;
261} SchFilterGraph;261} SchFilterGraph;
262 262
263enum SchedulerState {
264 SCH_STATE_UNINIT,
265 SCH_STATE_STARTED,
266 SCH_STATE_STOPPED,
267};
268
263struct Scheduler {269struct 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 start1151 // this may be called during initialization - do not start
1146 // threads before sch_start() is called1152 // 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;
1577fail:
1578 sch_stop(sch, NULL);
1579 return ret;
1569}1580}
1570 1581
1571int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts)1582int 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
2426static 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
2415static void *task_wrapper(void *arg)2438static 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 termination2453 // 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
2451static int task_stop(SchTask *task)2466static 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}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t