| @@ -71,13 +71,19 @@ typedef struct SchTask { · 70 unmodified lines |
| 71 | 71 | int thread_running; |
| 72 | 72 | } SchTask; |
| 73 | 73 | |
| 74 | +typedef struct SchDecOutput { |
| 75 | + SchedulerNode *dst; |
| 76 | + uint8_t *dst_finished; |
| 77 | + unsigned nb_dst; |
| 78 | +} SchDecOutput; |
| 79 | + |
| 74 | 80 | typedef struct SchDec { |
| 75 | 81 | const AVClass *class; |
| 76 | 82 | |
| 77 | 83 | SchedulerNode src; |
| 78 | | − SchedulerNode *dst; |
| 79 | | − uint8_t *dst_finished; |
| 80 | | − unsigned nb_dst; |
| 84 | + |
| 85 | + SchDecOutput *outputs; |
| 86 | + unsigned nb_outputs; |
| 81 | 87 | |
| 82 | 88 | SchTask task; |
| 83 | 89 | // Queue for receiving input packets, one stream. |
| @@ -513,8 +519,14 @@ void sch_free(Scheduler **psch) · 429 unmodified lines |
| 513 | 519 | |
| 514 | 520 | av_thread_message_queue_free(&dec->queue_end_ts); |
| 515 | 521 | |
| 516 | | − av_freep(&dec->dst); |
| 517 | | − av_freep(&dec->dst_finished); |
| 522 | + for (unsigned j = 0; j < dec->nb_outputs; j++) { |
| 523 | + SchDecOutput *o = &dec->outputs[j]; |
| 524 | + |
| 525 | + av_freep(&o->dst); |
| 526 | + av_freep(&o->dst_finished); |
| 527 | + } |
| 528 | + |
| 529 | + av_freep(&dec->outputs); |
| 518 | 530 | |
| 519 | 531 | av_frame_free(&dec->send_frame); |
| 520 | 532 | } |
| @@ -712,14 +724,28 @@ int sch_add_demux_stream(Scheduler *sch, unsigned demux_idx) · 191 unmodified lines |
| 712 | 724 | return ret < 0 ? ret : d->nb_streams - 1; |
| 713 | 725 | } |
| 714 | 726 | |
| 727 | +int sch_add_dec_output(Scheduler *sch, unsigned dec_idx) |
| 728 | +{ |
| 729 | + SchDec *dec; |
| 730 | + int ret; |
| 731 | + |
| 732 | + av_assert0(dec_idx < sch->nb_dec); |
| 733 | + dec = &sch->dec[dec_idx]; |
| 734 | + |
| 735 | + ret = GROW_ARRAY(dec->outputs, dec->nb_outputs); |
| 736 | + if (ret < 0) |
| 737 | + return ret; |
| 738 | + |
| 739 | + return dec->nb_outputs - 1; |
| 740 | +} |
| 741 | + |
| 715 | 742 | static const AVClass sch_dec_class = { |
| 716 | 743 | .class_name = "SchDec", |
| 717 | 744 | .version = LIBAVUTIL_VERSION_INT, |
| 718 | 745 | .parent_log_context_offset = offsetof(SchDec, task.func_arg), |
| 719 | 746 | }; |
| 720 | 747 | |
| 721 | | −int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, |
| 722 | | − int send_end_ts) |
| 748 | +int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts) |
| 723 | 749 | { |
| 724 | 750 | const unsigned idx = sch->nb_dec; |
| 725 | 751 | |
| @@ -739,6 +765,10 @@ int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, · 13 unmodified lines |
| 739 | 765 | if (!dec->send_frame) |
| 740 | 766 | return AVERROR(ENOMEM); |
| 741 | 767 | |
| 768 | + ret = sch_add_dec_output(sch, idx); |
| 769 | + if (ret < 0) |
| 770 | + return ret; |
| 771 | + |
| 742 | 772 | ret = queue_alloc(&dec->queue, 1, 0, QUEUE_PACKETS); |
| 743 | 773 | if (ret < 0) |
| 744 | 774 | return ret; |
| @@ -943,15 +973,19 @@ int sch_connect(Scheduler *sch, SchedulerNode src, SchedulerNode dst) · 198 unmodified lines |
| 943 | 973 | } |
| 944 | 974 | case SCH_NODE_TYPE_DEC: { |
| 945 | 975 | SchDec *dec; |
| 976 | + SchDecOutput *o; |
| 946 | 977 | |
| 947 | 978 | av_assert0(src.idx < sch->nb_dec); |
| 948 | 979 | dec = &sch->dec[src.idx]; |
| 949 | 980 | |
| 950 | | − ret = GROW_ARRAY(dec->dst, dec->nb_dst); |
| 981 | + av_assert0(src.idx_stream < dec->nb_outputs); |
| 982 | + o = &dec->outputs[src.idx_stream]; |
| 983 | + |
| 984 | + ret = GROW_ARRAY(o->dst, o->nb_dst); |
| 951 | 985 | if (ret < 0) |
| 952 | 986 | return ret; |
| 953 | 987 | |
| 954 | | − dec->dst[dec->nb_dst - 1] = dst; |
| 988 | + o->dst[o->nb_dst - 1] = dst; |
| 955 | 989 | |
| 956 | 990 | // decoded frames go to filters or encoding |
| 957 | 991 | switch (dst.type) { |
| @@ -1417,15 +1451,20 @@ static int start_prepare(Scheduler *sch) · 459 unmodified lines |
| 1417 | 1451 | "Decoder not connected to a source\n"); |
| 1418 | 1452 | return AVERROR(EINVAL); |
| 1419 | 1453 | } |
| 1420 | | − if (!dec->nb_dst) { |
| 1421 | | − av_log(dec, AV_LOG_ERROR, |
| 1422 | | − "Decoder not connected to any sink\n"); |
| 1423 | | − return AVERROR(EINVAL); |
| 1424 | | − } |
| 1425 | 1454 | |
| 1426 | | − dec->dst_finished = av_calloc(dec->nb_dst, sizeof(*dec->dst_finished)); |
| 1427 | | − if (!dec->dst_finished) |
| 1428 | | − return AVERROR(ENOMEM); |
| 1455 | + for (unsigned j = 0; j < dec->nb_outputs; j++) { |
| 1456 | + SchDecOutput *o = &dec->outputs[j]; |
| 1457 | + |
| 1458 | + if (!o->nb_dst) { |
| 1459 | + av_log(dec, AV_LOG_ERROR, |
| 1460 | + "Decoder output %u not connected to any sink\n", j); |
| 1461 | + return AVERROR(EINVAL); |
| 1462 | + } |
| 1463 | + |
| 1464 | + o->dst_finished = av_calloc(o->nb_dst, sizeof(*o->dst_finished)); |
| 1465 | + if (!o->dst_finished) |
| 1466 | + return AVERROR(ENOMEM); |
| 1467 | + } |
| 1429 | 1468 | } |
| 1430 | 1469 | |
| 1431 | 1470 | for (unsigned i = 0; i < sch->nb_enc; i++) { |
| @@ -2171,21 +2210,26 @@ finish: · 739 unmodified lines |
| 2171 | 2210 | return AVERROR_EOF; |
| 2172 | 2211 | } |
| 2173 | 2212 | |
| 2174 | | −int sch_dec_send(Scheduler *sch, unsigned dec_idx, AVFrame *frame) |
| 2213 | +int sch_dec_send(Scheduler *sch, unsigned dec_idx, |
| 2214 | + unsigned out_idx, AVFrame *frame) |
| 2175 | 2215 | { |
| 2176 | 2216 | SchDec *dec; |
| 2217 | + SchDecOutput *o; |
| 2177 | 2218 | int ret; |
| 2178 | 2219 | unsigned nb_done = 0; |
| 2179 | 2220 | |
| 2180 | 2221 | av_assert0(dec_idx < sch->nb_dec); |
| 2181 | 2222 | dec = &sch->dec[dec_idx]; |
| 2182 | 2223 | |
| 2183 | | − for (unsigned i = 0; i < dec->nb_dst; i++) { |
| 2184 | | − uint8_t *finished = &dec->dst_finished[i]; |
| 2224 | + av_assert0(out_idx < dec->nb_outputs); |
| 2225 | + o = &dec->outputs[out_idx]; |
| 2226 | + |
| 2227 | + for (unsigned i = 0; i < o->nb_dst; i++) { |
| 2228 | + uint8_t *finished = &o->dst_finished[i]; |
| 2185 | 2229 | AVFrame *to_send = frame; |
| 2186 | 2230 | |
| 2187 | 2231 | // sending a frame consumes it, so make a temporary reference if needed |
| 2188 | | − if (i < dec->nb_dst - 1) { |
| 2232 | + if (i < o->nb_dst - 1) { |
| 2189 | 2233 | to_send = dec->send_frame; |
| 2190 | 2234 | |
| 2191 | 2235 | // frame may sometimes contain props only, |
| @@ -2196,7 +2240,7 @@ int sch_dec_send(Scheduler *sch, unsigned dec_idx, AVFrame *frame) · 4 unmodified lines |
| 2196 | 2240 | return ret; |
| 2197 | 2241 | } |
| 2198 | 2242 | |
| 2199 | | − ret = dec_send_to_dst(sch, dec->dst[i], finished, to_send); |
| 2243 | + ret = dec_send_to_dst(sch, o->dst[i], finished, to_send); |
| 2200 | 2244 | if (ret < 0) { |
| 2201 | 2245 | av_frame_unref(to_send); |
| 2202 | 2246 | if (ret == AVERROR_EOF) { |
| @@ -2207,7 +2251,7 @@ int sch_dec_send(Scheduler *sch, unsigned dec_idx, AVFrame *frame) · 4 unmodified lines |
| 2207 | 2251 | } |
| 2208 | 2252 | } |
| 2209 | 2253 | |
| 2210 | | − return (nb_done == dec->nb_dst) ? AVERROR_EOF : 0; |
| 2254 | + return (nb_done == o->nb_dst) ? AVERROR_EOF : 0; |
| 2211 | 2255 | } |
| 2212 | 2256 | |
| 2213 | 2257 | static int dec_done(Scheduler *sch, unsigned dec_idx) |
| @@ -2222,10 +2266,14 @@ static int dec_done(Scheduler *sch, unsigned dec_idx) · 8 unmodified lines |
| 2222 | 2266 | if (dec->queue_end_ts) |
| 2223 | 2267 | av_thread_message_queue_set_err_recv(dec->queue_end_ts, AVERROR_EOF); |
| 2224 | 2268 | |
| 2225 | | − for (unsigned i = 0; i < dec->nb_dst; i++) { |
| 2226 | | − int err = dec_send_to_dst(sch, dec->dst[i], &dec->dst_finished[i], NULL); |
| 2227 | | − if (err < 0 && err != AVERROR_EOF) |
| 2228 | | − ret = err_merge(ret, err); |
| 2269 | + for (unsigned i = 0; i < dec->nb_outputs; i++) { |
| 2270 | + SchDecOutput *o = &dec->outputs[i]; |
| 2271 | + |
| 2272 | + for (unsigned j = 0; j < o->nb_dst; j++) { |
| 2273 | + int err = dec_send_to_dst(sch, o->dst[j], &o->dst_finished[j], NULL); |
| 2274 | + if (err < 0 && err != AVERROR_EOF) |
| 2275 | + ret = err_merge(ret, err); |
| 2276 | + } |
| 2229 | 2277 | } |
| 2230 | 2278 | |
| 2231 | 2279 | return ret; |