fftools/ffmpeg: convert to a threaded architecture

Change the main loop and every component (demuxers, decoders, filters,
encoders, muxers) to use the previously added transcode scheduler. Every
instance of every such component was already running in a separate
thread, but now they can actually run in parallel.

Changes the results of ffmpeg-fix_sub_duration_heartbeat - tested by
JEEB to be more correct and deterministic.
This commit is contained in:
Anton Khirnov
2023-07-18 16:37:52 +02:00
parent 9b8cc36ce0
commit d119ae2fd8
12 changed files with 609 additions and 2030 deletions

View File

@@ -924,13 +924,6 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
return 0;
}
static int new_stream_attachment(Muxer *mux, const OptionsContext *o,
OutputStream *ost)
{
ost->finished = 1;
return 0;
}
static int new_stream_subtitle(Muxer *mux, const OptionsContext *o,
OutputStream *ost)
{
@@ -1168,9 +1161,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (!ost->par_in)
return AVERROR(ENOMEM);
ms->muxing_queue = av_fifo_alloc2(8, sizeof(AVPacket*), 0);
if (!ms->muxing_queue)
return AVERROR(ENOMEM);
ms->last_mux_dts = AV_NOPTS_VALUE;
ost->st = st;
@@ -1190,7 +1180,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (!ost->enc_ctx)
return AVERROR(ENOMEM);
ret = sch_add_enc(mux->sch, encoder_thread, ost, NULL);
ret = sch_add_enc(mux->sch, encoder_thread, ost,
ost->type == AVMEDIA_TYPE_SUBTITLE ? NULL : enc_open);
if (ret < 0)
return ret;
ms->sch_idx_enc = ret;
@@ -1414,9 +1405,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx,
max_muxing_queue_size, muxing_queue_data_threshold);
ms->max_muxing_queue_size = max_muxing_queue_size;
ms->muxing_queue_data_threshold = muxing_queue_data_threshold;
}
MATCH_PER_STREAM_OPT(bits_per_raw_sample, i, ost->bits_per_raw_sample,
@@ -1434,8 +1422,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ost->enc_ctx && av_get_exact_bits_per_sample(ost->enc_ctx->codec_id) == 24)
av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
ost->last_mux_dts = AV_NOPTS_VALUE;
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i,
ms->copy_initial_nonkeyframes, oc, st);
@@ -1443,7 +1429,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost); break;
case AVMEDIA_TYPE_AUDIO: ret = new_stream_audio (mux, o, ost); break;
case AVMEDIA_TYPE_SUBTITLE: ret = new_stream_subtitle (mux, o, ost); break;
case AVMEDIA_TYPE_ATTACHMENT: ret = new_stream_attachment(mux, o, ost); break;
}
if (ret < 0)
return ret;
@@ -1938,7 +1923,6 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u
MuxStream *ms = ms_from_ost(ost);
enum AVMediaType type = ost->type;
ost->sq_idx_encode = -1;
ost->sq_idx_mux = -1;
nb_interleaved += IS_INTERLEAVED(type);
@@ -1961,11 +1945,17 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u
* - at least one encoded audio/video stream is frame-limited, since
* that has similar semantics to 'shortest'
* - at least one audio encoder requires constant frame sizes
*
* Note that encoding sync queues are handled in the scheduler, because
* different encoders run in different threads and need external
* synchronization, while muxer sync queues can be handled inside the muxer
*/
if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc || nb_audio_fs) {
of->sq_encode = sq_alloc(SYNC_QUEUE_FRAMES, buf_size_us, mux);
if (!of->sq_encode)
return AVERROR(ENOMEM);
int sq_idx, ret;
sq_idx = sch_add_sq_enc(mux->sch, buf_size_us, mux);
if (sq_idx < 0)
return sq_idx;
for (int i = 0; i < oc->nb_streams; i++) {
OutputStream *ost = of->streams[i];
@@ -1975,13 +1965,11 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u
if (!IS_AV_ENC(ost, type))
continue;
ost->sq_idx_encode = sq_add_stream(of->sq_encode,
of->shortest || ms->max_frames < INT64_MAX);
if (ost->sq_idx_encode < 0)
return ost->sq_idx_encode;
if (ms->max_frames != INT64_MAX)
sq_limit_frames(of->sq_encode, ost->sq_idx_encode, ms->max_frames);
ret = sch_sq_add_enc(mux->sch, sq_idx, ms->sch_idx_enc,
of->shortest || ms->max_frames < INT64_MAX,
ms->max_frames);
if (ret < 0)
return ret;
}
}
@@ -2652,23 +2640,6 @@ static int validate_enc_avopt(Muxer *mux, const AVDictionary *codec_avopt)
return 0;
}
static int init_output_stream_nofilter(OutputStream *ost)
{
int ret = 0;
if (ost->enc_ctx) {
ret = enc_open(ost, NULL);
if (ret < 0)
return ret;
} else {
ret = of_stream_init(output_files[ost->file_index], ost);
if (ret < 0)
return ret;
}
return ret;
}
static const char *output_file_item_name(void *obj)
{
const Muxer *mux = obj;
@@ -2751,8 +2722,6 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch)
av_strlcat(mux->log_name, "/", sizeof(mux->log_name));
av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name));
if (strcmp(oc->oformat->name, "rtp"))
want_sdp = 0;
of->format = oc->oformat;
if (recording_time != INT64_MAX)
@@ -2768,7 +2737,7 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch)
AVFMT_FLAG_BITEXACT);
}
err = sch_add_mux(sch, muxer_thread, NULL, mux,
err = sch_add_mux(sch, muxer_thread, mux_check_init, mux,
!strcmp(oc->oformat->name, "rtp"));
if (err < 0)
return err;
@@ -2854,26 +2823,15 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch)
of->url = filename;
/* initialize stream copy and subtitle/data streams.
* Encoded AVFrame based streams will get initialized when the first AVFrame
* is received in do_video_out
*/
/* initialize streamcopy streams. */
for (int i = 0; i < of->nb_streams; i++) {
OutputStream *ost = of->streams[i];
if (ost->filter)
continue;
err = init_output_stream_nofilter(ost);
if (err < 0)
return err;
}
/* write the header for files with no streams */
if (of->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) {
int ret = mux_check_init(mux);
if (ret < 0)
return ret;
if (!ost->enc) {
err = of_stream_init(of, ost);
if (err < 0)
return err;
}
}
return 0;