Go to the documentation of this file.
22 #include <stdatomic.h>
45 #define SCHEDULE_TOLERANCE (100 * 1000)
379 if (queue_size <= 0) {
441 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
444 for (
unsigned j = 0; j < mux->
nb_streams; j++) {
471 for (
unsigned j = 0; j < d->
nb_streams; j++) {
484 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
487 for (
unsigned j = 0; j < mux->
nb_streams; j++) {
507 for (
unsigned i = 0;
i < sch->
nb_dec;
i++) {
514 for (
unsigned j = 0; j < dec->
nb_outputs; j++) {
527 for (
unsigned i = 0;
i < sch->
nb_enc;
i++) {
621 .parent_log_context_offset = offsetof(
SchMux, task.func_arg),
625 void *
arg,
int sdp_auto,
unsigned thread_queue_size)
627 const unsigned idx = sch->
nb_mux;
636 mux = &sch->
mux[idx];
656 mux = &sch->
mux[mux_idx];
663 ms = &mux->
streams[stream_idx];
677 .parent_log_context_offset = offsetof(
SchDemux, task.func_arg),
691 d = &sch->
demux[idx];
713 d = &sch->
demux[demux_idx];
725 dec = &sch->
dec[dec_idx];
737 .parent_log_context_offset = offsetof(
SchDec, task.func_arg),
742 const unsigned idx = sch->
nb_dec;
751 dec = &sch->
dec[idx];
780 .parent_log_context_offset = offsetof(
SchEnc, task.func_arg),
786 const unsigned idx = sch->
nb_enc;
795 enc = &sch->
enc[idx];
818 .parent_log_context_offset = offsetof(
SchFilterGraph, task.func_arg),
889 int limiting, uint64_t max_frames)
896 sq = &sch->
sq_enc[sq_idx];
899 enc = &sch->
enc[enc_idx];
913 if (max_frames != INT64_MAX)
1026 enc = &sch->
enc[
dst.idx];
1053 enc = &sch->
enc[
src.idx];
1079 dec = &sch->
dec[
dst.idx];
1107 int min_stream = -1;
1131 if (min_stream >= 0) {
1183 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
1198 size_t data_threshold,
int max_packets)
1204 mux = &sch->
mux[mux_idx];
1207 ms = &mux->
streams[stream_idx];
1219 mux = &sch->
mux[mux_idx];
1246 mux = &sch->
mux[mux_idx];
1249 ms = &mux->
streams[stream_idx];
1295 int have_unchoked = 0;
1315 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
1318 for (
unsigned j = 0; j < mux->
nb_streams; j++) {
1337 for (
unsigned type = 0; !have_unchoked &&
type < 2;
type++)
1352 if (
w->choked_prev !=
w->choked_next)
1368 unsigned nb_filters_stack = 0;
1370 memset(filters_visited, 0, sch->
nb_filters *
sizeof(*filters_visited));
1393 av_assert0(nb_filters_stack < sch->nb_filters);
1394 filters_stack[nb_filters_stack++] =
src;
1402 if (nb_filters_stack) {
1403 src = filters_stack[--nb_filters_stack];
1412 uint8_t *filters_visited =
NULL;
1421 if (!filters_visited)
1425 if (!filters_stack) {
1433 filters_visited, filters_stack);
1453 for (
unsigned j = 0; j < d->
nb_streams; j++) {
1458 "Demuxer stream %u not connected to any sink\n", j);
1468 for (
unsigned i = 0;
i < sch->
nb_dec;
i++) {
1473 "Decoder not connected to a source\n");
1477 for (
unsigned j = 0; j < dec->
nb_outputs; j++) {
1482 "Decoder output %u not connected to any sink\n", j);
1492 for (
unsigned i = 0;
i < sch->
nb_enc;
i++) {
1497 "Encoder not connected to a source\n");
1502 "Encoder not connected to any sink\n");
1511 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
1514 for (
unsigned j = 0; j < mux->
nb_streams; j++) {
1534 "Muxer stream #%u not connected to a source\n", j);
1548 for (
unsigned j = 0; j < fg->
nb_inputs; j++) {
1554 "Filtergraph input %u not connected to a source\n", j);
1572 for (
unsigned j = 0; j < fg->
nb_outputs; j++) {
1577 "Filtergraph %u output %u not connected to a sink\n",
i, j);
1602 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
1612 for (
unsigned i = 0;
i < sch->
nb_enc;
i++) {
1628 for (
unsigned i = 0;
i < sch->
nb_dec;
i++) {
1667 struct timespec tv = { .tv_sec = timeout_us / 1000000,
1668 .tv_nsec = (timeout_us % 1000000) * 1000 };
1738 for (
unsigned i = 0;
i < enc->
nb_dst;
i++) {
1812 if (!
frame->buf[0]) {
1818 return (enc->
sq_idx[0] >= 0) ?
1833 size_t max_packets = thresh_reached ? q->
max_packets : SIZE_MAX;
1834 size_t new_size =
FFMIN(2 * packets, max_packets);
1836 if (new_size <= packets) {
1838 "Too many packets buffered for output stream.\n");
1877 queued =
ret < 0 ?
ret : 1;
1885 goto update_schedule;
1956 unsigned nb_done = 0;
1958 for (
unsigned i = 0;
i < ds->
nb_dst;
i++) {
1965 if (
pkt && i < ds->nb_dst - 1) {
1994 for (
unsigned j = 0; j < ds->
nb_dst; j++) {
2002 dec = &sch->
dec[
dst->idx];
2036 d = &sch->
demux[demux_idx];
2076 int ret, stream_idx;
2079 mux = &sch->
mux[mux_idx];
2091 mux = &sch->
mux[mux_idx];
2111 mux = &sch->
mux[mux_idx];
2114 ms = &mux->
streams[stream_idx];
2163 dec = &sch->
dec[dec_idx];
2239 unsigned nb_done = 0;
2242 dec = &sch->
dec[dec_idx];
2247 for (
unsigned i = 0;
i < o->
nb_dst;
i++) {
2252 if (i < o->nb_dst - 1) {
2292 for (
unsigned j = 0; j < o->
nb_dst; j++) {
2308 enc = &sch->
enc[enc_idx];
2352 enc = &sch->
enc[enc_idx];
2354 for (
unsigned i = 0;
i < enc->
nb_dst;
i++) {
2359 if (i < enc->nb_dst - 1) {
2386 for (
unsigned i = 0;
i < enc->
nb_dst;
i++) {
2429 else if (
ret >= 0) {
2448 fi = &fg->
inputs[in_idx];
2517 switch (node.
type) {
2553 "Terminating thread with return code %d (%s)\n",
ret,
2556 return (
void*)(intptr_t)
ret;
2572 return (intptr_t)thread_ret;
2597 for (
unsigned i = 0;
i < sch->
nb_dec;
i++) {
2611 for (
unsigned i = 0;
i < sch->
nb_enc;
i++) {
2618 for (
unsigned i = 0;
i < sch->
nb_mux;
i++) {
int(* func)(AVBPrint *dst, const char *in, const char *arg)
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
static int mux_task_start(SchMux *mux)
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
static int waiter_init(SchWaiter *w)
size_t av_fifo_can_write(const AVFifo *f)
pthread_mutex_t finish_lock
#define atomic_store(object, desired)
int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *frame)
Called by filtergraph tasks to send a filtered frame or EOF to consumers.
static int err_merge(int err0, int err1)
Merge two return codes - return one of the error codes if at least one of them was negative,...
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare two timestamps each in its own time base.
void sch_mux_receive_finish(Scheduler *sch, unsigned mux_idx, unsigned stream_idx)
Called by muxer tasks to signal that a stream will no longer accept input.
#define atomic_fetch_add(object, operand)
static int demux_flush(Scheduler *sch, SchDemux *d, AVPacket *pkt)
#define AVERROR_EOF
End of file.
AVPacket * sub_heartbeat_pkt
void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames)
Limit the number of output frames for stream with index stream_idx to max_frames.
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
#define SCHEDULE_TOLERANCE
int sch_add_demux(Scheduler *sch, SchThreadFunc func, void *ctx)
Add a demuxer to the scheduler.
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
static int mux_done(Scheduler *sch, unsigned mux_idx)
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
static int check_acyclic_for_output(const Scheduler *sch, SchedulerNode src, uint8_t *filters_visited, SchedulerNode *filters_stack)
This structure describes decoded (raw) audio or video data.
static int task_cleanup(Scheduler *sch, SchedulerNode node)
unsigned nb_streams_ready
static int send_to_mux(Scheduler *sch, SchMux *mux, unsigned stream_idx, AVPacket *pkt)
ThreadQueue * tq_alloc(unsigned int nb_streams, size_t queue_size, enum ThreadQueueType type)
Allocate a queue for sending data between threads.
static int enc_done(Scheduler *sch, unsigned enc_idx)
#define AV_LOG_VERBOSE
Detailed information.
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
AVFifo * fifo
Queue for buffering the packets before the muxer task can be started.
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
#define DEFAULT_FRAME_THREAD_QUEUE_SIZE
Default size of a frame thread queue.
atomic_int_least64_t last_dts
int sch_mux_stream_ready(Scheduler *sch, unsigned mux_idx, unsigned stream_idx)
Signal to the scheduler that the specified muxed stream is initialized and ready.
static int send_to_enc_thread(Scheduler *sch, SchEnc *enc, AVFrame *frame)
static int task_stop(Scheduler *sch, SchTask *task)
enum SchedulerNodeType type
int sch_stop(Scheduler *sch, int64_t *finish_ts)
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
int(* SchThreadFunc)(void *arg)
int av_fifo_grow2(AVFifo *f, size_t inc)
Enlarge an AVFifo.
int sch_add_mux_stream(Scheduler *sch, unsigned mux_idx)
Add a muxed stream for a previously added muxer.
atomic_uint nb_inputs_finished_send
int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
Read a frame from the queue.
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
int av_thread_message_queue_recv(AVThreadMessageQueue *mq, void *msg, unsigned flags)
Receive a message from the queue.
int sch_add_filtergraph(Scheduler *sch, unsigned nb_inputs, unsigned nb_outputs, SchThreadFunc func, void *ctx)
Add a filtergraph to the scheduler.
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
void sch_free(Scheduler **psch)
enum SchedulerState state
int av_thread_message_queue_send(AVThreadMessageQueue *mq, void *msg, unsigned flags)
Send a message on the queue.
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
int sch_add_mux(Scheduler *sch, SchThreadFunc func, int(*init)(void *), void *arg, int sdp_auto, unsigned thread_queue_size)
Add a muxer to the scheduler.
static void waiter_set(SchWaiter *w, int choked)
static int enc_open(Scheduler *sch, SchEnc *enc, const AVFrame *frame)
Scheduler * sch_alloc(void)
static int dec_send_to_dst(Scheduler *sch, const SchedulerNode dst, uint8_t *dst_finished, AVFrame *frame)
static void task_init(Scheduler *sch, SchTask *task, enum SchedulerNodeType type, unsigned idx, SchThreadFunc func, void *func_arg)
unsigned nb_sub_heartbeat_dst
int sch_add_demux_stream(Scheduler *sch, unsigned demux_idx)
Add a demuxed stream for a previously added demuxer.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
int sch_dec_send(Scheduler *sch, unsigned dec_idx, unsigned out_idx, AVFrame *frame)
Called by decoder tasks to send a decoded frame downstream.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
static int filter_done(Scheduler *sch, unsigned fg_idx)
int sch_enc_receive(Scheduler *sch, unsigned enc_idx, AVFrame *frame)
Called by encoder tasks to obtain frames for encoding.
#define atomic_load(object)
int sch_sdp_filename(Scheduler *sch, const char *sdp_filename)
Set the file path for the SDP.
static int demux_send_for_stream(Scheduler *sch, SchDemux *d, SchDemuxStream *ds, AVPacket *pkt, unsigned flags)
static av_always_inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
PreMuxQueue pre_mux_queue
int sq_add_stream(SyncQueue *sq, int limiting)
Add a new stream to the sync queue.
atomic_int mux_started
Set to 1 after starting the muxer task and flushing the pre-muxing queues.
pthread_cond_t finish_cond
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
void tq_free(ThreadQueue **ptq)
#define LIBAVUTIL_VERSION_INT
static void waiter_uninit(SchWaiter *w)
Describe the class of an AVClass context structure.
static int send_to_enc_sq(Scheduler *sch, SchEnc *enc, AVFrame *frame)
int(* open_cb)(void *opaque, const AVFrame *frame)
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
static void schedule_update_locked(Scheduler *sch)
void tq_receive_finish(ThreadQueue *tq, unsigned int stream_idx)
Mark the given stream finished from the receiving side.
int sch_add_enc(Scheduler *sch, SchThreadFunc func, void *ctx, int(*open_cb)(void *opaque, const AVFrame *frame))
static int dec_done(Scheduler *sch, unsigned dec_idx)
size_t av_fifo_can_read(const AVFifo *f)
int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts)
Add a decoder to the scheduler.
@ DEMUX_SEND_STREAMCOPY_EOF
Treat the packet as an EOF for SCH_NODE_TYPE_MUX destinations send normally to other types.
static const AVClass sch_fg_class
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
int sch_enc_send(Scheduler *sch, unsigned enc_idx, AVPacket *pkt)
Called by encoder tasks to send encoded packets downstream.
#define pthread_mutex_unlock(a)
unsigned * sub_heartbeat_dst
void sq_frame_samples(SyncQueue *sq, unsigned int stream_idx, int frame_samples)
Set a constant output audio frame size, in samples.
unsigned nb_inputs_finished_receive
int tq_send(ThreadQueue *tq, unsigned int stream_idx, void *data)
Send an item for the given stream to the queue.
int(* init)(AVBSFContext *ctx)
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
int max_packets
Maximum number of packets in fifo.
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame)
Submit a frame for the stream with index stream_idx.
void sq_free(SyncQueue **psq)
#define AV_NOPTS_VALUE
Undefined timestamp value.
static const AVClass sch_dec_class
pthread_mutex_t schedule_lock
@ SCH_NODE_TYPE_FILTER_OUT
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
static int enc_send_to_dst(Scheduler *sch, const SchedulerNode dst, uint8_t *dst_finished, AVPacket *pkt)
static const AVClass sch_mux_class
int sch_filter_receive(Scheduler *sch, unsigned fg_idx, unsigned *in_idx, AVFrame *frame)
Called by filtergraph tasks to obtain frames for filtering.
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
static const AVClass scheduler_class
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, unsigned nelem, unsigned elsize)
Allocate a new message queue.
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
@ SCH_NODE_TYPE_FILTER_IN
static int task_start(SchTask *task)
#define i(width, name, range_min, range_max)
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
static int demux_done(Scheduler *sch, unsigned demux_idx)
#define av_malloc_array(a, b)
pthread_mutex_t mux_ready_lock
#define DEFAULT_PACKET_THREAD_QUEUE_SIZE
Default size of a packet thread queue.
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
static int64_t trailing_dts(const Scheduler *sch, int count_finished)
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
static const AVClass sch_enc_class
static int mux_init(Scheduler *sch, SchMux *mux)
static int send_to_filter(Scheduler *sch, SchFilterGraph *fg, unsigned in_idx, AVFrame *frame)
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data)
Read the next item from the queue.
void * av_calloc(size_t nmemb, size_t size)
int sch_connect(Scheduler *sch, SchedulerNode src, SchedulerNode dst)
static int send_to_enc(Scheduler *sch, SchEnc *enc, AVFrame *frame)
int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame)
intptr_t atomic_int_least64_t
int sch_dec_receive(Scheduler *sch, unsigned dec_idx, AVPacket *pkt)
Called by decoder tasks to receive a packet for decoding.
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
static int mux_queue_packet(SchMux *mux, SchMuxStream *ms, AVPacket *pkt)
static const AVClass sch_demux_class
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
static void * task_wrapper(void *arg)
A sync queue provides timestamp synchronization between multiple streams.
int sch_demux_send(Scheduler *sch, unsigned demux_idx, AVPacket *pkt, unsigned flags)
Called by demuxer tasks to communicate with their downstreams.
AVThreadMessageQueue * queue_end_ts
static int demux_stream_send_to_dst(Scheduler *sch, const SchedulerNode dst, uint8_t *dst_finished, AVPacket *pkt, unsigned flags)
#define GROW_ARRAY(array, nb_elems)
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int64_t av_gettime(void)
Get the current time in microseconds.
static int waiter_wait(Scheduler *sch, SchWaiter *w)
Wait until this task is allowed to proceed.
char * av_strdup(const char *s)
Duplicate a string.
int sch_sq_add_enc(Scheduler *sch, unsigned sq_idx, unsigned enc_idx, int limiting, uint64_t max_frames)
int print_sdp(const char *filename)
static int start_prepare(Scheduler *sch)
int sch_mux_sub_heartbeat_add(Scheduler *sch, unsigned mux_idx, unsigned stream_idx, unsigned dec_idx)
void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx)
Called by filter tasks to signal that a filter input will no longer accept input.
int sch_add_dec_output(Scheduler *sch, unsigned dec_idx)
Add another output to decoder (e.g.
int sch_wait(Scheduler *sch, uint64_t timeout_us, int64_t *transcode_ts)
Wait until transcoding terminates or the specified timeout elapses.
This structure stores compressed data.
void av_thread_message_queue_free(AVThreadMessageQueue **mq)
Free a message queue.
static int queue_alloc(ThreadQueue **ptq, unsigned nb_streams, unsigned queue_size, enum QueueType type)
int sch_start(Scheduler *sch)
#define flags(name, subs,...)
void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, int err)
Set the receiving error code.
static av_always_inline int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
int sch_mux_sub_heartbeat(Scheduler *sch, unsigned mux_idx, unsigned stream_idx, const AVPacket *pkt)
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
SyncQueue * sq_alloc(enum SyncQueueType type, int64_t buf_size_us, void *logctx)
Allocate a sync queue of the given type.
#define atomic_init(obj, value)
void sch_mux_stream_buffering(Scheduler *sch, unsigned mux_idx, unsigned stream_idx, size_t data_threshold, int max_packets)
Configure limits on packet buffering performed before the muxer task is started.
static int check_acyclic(Scheduler *sch)
AVRational time_base
Time base of the packet's timestamps.
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
int sch_mux_receive(Scheduler *sch, unsigned mux_idx, AVPacket *pkt)
Called by muxer tasks to obtain packets for muxing.
int sch_add_sq_enc(Scheduler *sch, uint64_t buf_size_us, void *logctx)
Add an pre-encoding sync queue to the scheduler.
#define pthread_mutex_lock(a)
void tq_send_finish(ThreadQueue *tq, unsigned int stream_idx)
Mark the given stream finished from the sending side.