1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-10-06 05:47:18 +02:00

fftools/ffmpeg_sched: get rid of src_sched

This field is just saving (typically) a single pointer indirection; and IMO
makes the logic and graph relations unnecessarily complicated. I am also
considering adding choking logic to decoders and encoders as well, which this
field would get in the way of.

Apart from the unchoking logic in unchoke_for_input(), the only other place
that uses this field is the (cold) function check_acyclic(), which can be
served just as well with a simple function to do the graph traversal there.
This commit is contained in:
Niklas Haas
2025-09-04 16:53:28 +02:00
parent fd4b5b24ce
commit 23f1f094f8

View File

@@ -189,7 +189,6 @@ typedef struct PreMuxQueue {
typedef struct SchMuxStream {
SchedulerNode src;
SchedulerNode src_sched;
unsigned *sub_heartbeat_dst;
unsigned nb_sub_heartbeat_dst;
@@ -235,7 +234,6 @@ typedef struct SchMux {
typedef struct SchFilterIn {
SchedulerNode src;
SchedulerNode src_sched;
int send_finished;
int receive_finished;
} SchFilterIn;
@@ -1268,24 +1266,31 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
{
while (1) {
SchFilterGraph *fg;
switch (src.type) {
case SCH_NODE_TYPE_DEMUX:
// fed directly by a demuxer (i.e. not through a filtergraph)
if (src.type == SCH_NODE_TYPE_DEMUX) {
sch->demux[src.idx].waiter.choked_next = 0;
return;
}
av_assert0(src.type == SCH_NODE_TYPE_FILTER_OUT);
case SCH_NODE_TYPE_DEC:
src = sch->dec[src.idx].src;
continue;
case SCH_NODE_TYPE_ENC:
src = sch->enc[src.idx].src;
continue;
case SCH_NODE_TYPE_FILTER_OUT:
fg = &sch->filters[src.idx];
// the filtergraph contains internal sources and
// requested to be scheduled directly
if (fg->best_input == fg->nb_inputs) {
fg->waiter.choked_next = 0;
return;
}
src = fg->inputs[fg->best_input].src_sched;
src = fg->inputs[fg->best_input].src;
continue;
default:
av_unreachable("Invalid source node type?");
return;
}
}
}
@@ -1328,7 +1333,7 @@ static void schedule_update_locked(Scheduler *sch)
continue;
// resolve the source to unchoke
unchoke_for_stream(sch, ms->src_sched);
unchoke_for_stream(sch, ms->src);
have_unchoked = 1;
}
}
@@ -1361,6 +1366,27 @@ enum {
CYCLE_NODE_DONE,
};
// Finds the filtergraph or muxer upstream of a scheduler node
static SchedulerNode src_filtergraph(const Scheduler *sch, SchedulerNode src)
{
while (1) {
switch (src.type) {
case SCH_NODE_TYPE_DEMUX:
case SCH_NODE_TYPE_FILTER_OUT:
return src;
case SCH_NODE_TYPE_DEC:
src = sch->dec[src.idx].src;
continue;
case SCH_NODE_TYPE_ENC:
src = sch->enc[src.idx].src;
continue;
default:
av_unreachable("Invalid source node type?");
return (SchedulerNode) {0};
}
}
}
static int
check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
uint8_t *filters_visited, SchedulerNode *filters_stack)
@@ -1377,22 +1403,23 @@ check_acyclic_for_output(const Scheduler *sch, SchedulerNode src,
// descend into every input, depth first
if (src.idx_stream < fg->nb_inputs) {
const SchFilterIn *fi = &fg->inputs[src.idx_stream++];
SchedulerNode node = src_filtergraph(sch, fi->src);
// connected to demuxer, no cycles possible
if (fi->src_sched.type == SCH_NODE_TYPE_DEMUX)
if (node.type == SCH_NODE_TYPE_DEMUX)
continue;
// otherwise connected to another filtergraph
av_assert0(fi->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
av_assert0(node.type == SCH_NODE_TYPE_FILTER_OUT);
// found a cycle
if (filters_visited[fi->src_sched.idx] == CYCLE_NODE_STARTED)
if (filters_visited[node.idx] == CYCLE_NODE_STARTED)
return AVERROR(EINVAL);
// place current position on stack and descend
av_assert0(nb_filters_stack < sch->nb_filters);
filters_stack[nb_filters_stack++] = src;
src = (SchedulerNode){ .idx = fi->src_sched.idx, .idx_stream = 0 };
src = (SchedulerNode){ .idx = node.idx, .idx_stream = 0 };
continue;
}
@@ -1514,22 +1541,7 @@ static int start_prepare(Scheduler *sch)
for (unsigned j = 0; j < mux->nb_streams; j++) {
SchMuxStream *ms = &mux->streams[j];
switch (ms->src.type) {
case SCH_NODE_TYPE_ENC: {
SchEnc *enc = &sch->enc[ms->src.idx];
if (enc->src.type == SCH_NODE_TYPE_DEC) {
ms->src_sched = sch->dec[enc->src.idx].src;
av_assert0(ms->src_sched.type == SCH_NODE_TYPE_DEMUX);
} else {
ms->src_sched = enc->src;
av_assert0(ms->src_sched.type == SCH_NODE_TYPE_FILTER_OUT);
}
break;
}
case SCH_NODE_TYPE_DEMUX:
ms->src_sched = ms->src;
break;
default:
if (!ms->src.type) {
av_log(mux, AV_LOG_ERROR,
"Muxer stream #%u not connected to a source\n", j);
return AVERROR(EINVAL);
@@ -1547,26 +1559,12 @@ static int start_prepare(Scheduler *sch)
for (unsigned j = 0; j < fg->nb_inputs; j++) {
SchFilterIn *fi = &fg->inputs[j];
SchDec *dec;
if (!fi->src.type) {
av_log(fg, AV_LOG_ERROR,
"Filtergraph input %u not connected to a source\n", j);
return AVERROR(EINVAL);
}
if (fi->src.type == SCH_NODE_TYPE_FILTER_OUT)
fi->src_sched = fi->src;
else {
av_assert0(fi->src.type == SCH_NODE_TYPE_DEC);
dec = &sch->dec[fi->src.idx];
switch (dec->src.type) {
case SCH_NODE_TYPE_DEMUX: fi->src_sched = dec->src; break;
case SCH_NODE_TYPE_ENC: fi->src_sched = sch->enc[dec->src.idx].src; break;
default: av_assert0(0);
}
}
}
for (unsigned j = 0; j < fg->nb_outputs; j++) {