From: Anton Khirnov <anton@khirnov.net> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 08/23] fftools/ffmpeg: use sync queues for enforcing audio frame size Date: Sat, 25 Mar 2023 20:15:14 +0100 Message-ID: <20230325191529.10578-8-anton@khirnov.net> (raw) In-Reply-To: <20230325191529.10578-1-anton@khirnov.net> The code currently uses lavfi for this, which creates a sort of configuration dependency loop - the encoder should be ideally initialized with information from the first audio frame, but to get this frame one needs to first open the encoder to know the frame size. This necessitates an awkward workaround, which causes audio handling to be different from video. With this change, audio encoder initialization is congruent with video. --- fftools/ffmpeg.c | 58 ++++++++------------------------------- fftools/ffmpeg_filter.c | 8 ------ fftools/ffmpeg_mux_init.c | 19 +++++++++---- 3 files changed, 25 insertions(+), 60 deletions(-) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 3a205a3b01..f00b2d44e4 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -1028,6 +1028,8 @@ static void do_audio_out(OutputFile *of, OutputStream *ost, AVCodecContext *enc = ost->enc_ctx; int ret; + init_output_stream_wrapper(ost, frame, 1); + if (frame->pts == AV_NOPTS_VALUE) frame->pts = ost->next_pts; else { @@ -1378,18 +1380,6 @@ static int reap_filters(int flush) continue; filter = ost->filter->filter; - /* - * Unlike video, with audio the audio frame size matters. - * Currently we are fully reliant on the lavfi filter chain to - * do the buffering deed for us, and thus the frame size parameter - * needs to be set accordingly. Where does one get the required - * frame size? From the initialized AVCodecContext of an audio - * encoder. Thus, if we have gotten to an audio stream, initialize - * the encoder earlier than receiving the first AVFrame. - */ - if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_AUDIO) - init_output_stream_wrapper(ost, NULL, 1); - filtered_frame = ost->filtered_frame; while (1) { @@ -1432,6 +1422,7 @@ static int reap_filters(int flush) break; case AVMEDIA_TYPE_AUDIO: if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && + avcodec_is_open(enc) && enc->ch_layout.nb_channels != filtered_frame->ch_layout.nb_channels) { av_log(NULL, AV_LOG_ERROR, "Audio filter graph output is not normalized and encoder does not support parameter changes\n"); @@ -3238,10 +3229,13 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, ost->file_index, ost->index); return ret; } - if (codec->type == AVMEDIA_TYPE_AUDIO && - !(codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) - av_buffersink_set_frame_size(ost->filter->filter, - ost->enc_ctx->frame_size); + + if (ost->enc_ctx->frame_size) { + av_assert0(ost->sq_idx_encode >= 0); + sq_frame_samples(output_files[ost->file_index]->sq_encode, + ost->sq_idx_encode, ost->enc_ctx->frame_size); + } + assert_avoptions(ost->encoder_opts); if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 && ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) @@ -3331,12 +3325,8 @@ static int transcode_init(void) /* * initialize stream copy and subtitle/data streams. - * Encoded AVFrame based streams will get initialized as follows: - * - when the first AVFrame is received in do_video_out - * - just before the first AVFrame is received in either transcode_step - * or reap_filters due to us requiring the filter chain buffer sink - * to be configured with the correct audio frame size, which is only - * known after the encoder is initialized. + * Encoded AVFrame based streams will get initialized when the first AVFrame + * is received in do_video_out */ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) { if (ost->enc_ctx && @@ -3942,30 +3932,6 @@ static int transcode_step(void) } if (ost->filter && ost->filter->graph->graph) { - /* - * Similar case to the early audio initialization in reap_filters. - * Audio is special in ffmpeg.c currently as we depend on lavfi's - * audio frame buffering/creation to get the output audio frame size - * in samples correct. The audio frame size for the filter chain is - * configured during the output stream initialization. - * - * Apparently avfilter_graph_request_oldest (called in - * transcode_from_filter just down the line) peeks. Peeking already - * puts one frame "ready to be given out", which means that any - * update in filter buffer sink configuration afterwards will not - * help us. And yes, even if it would be utilized, - * av_buffersink_get_samples is affected, as it internally utilizes - * the same early exit for peeked frames. - * - * In other words, if avfilter_graph_request_oldest would not make - * further filter chain configuration or usage of - * av_buffersink_get_samples useless (by just causing the return - * of the peeked AVFrame as-is), we could get rid of this additional - * early encoder initialization. - */ - if (av_buffersink_get_type(ost->filter->filter) == AVMEDIA_TYPE_AUDIO) - init_output_stream_wrapper(ost, NULL, 1); - if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0) return ret; if (!ist) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 314b89b585..c9fd65e902 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -1242,14 +1242,6 @@ int configure_filtergraph(FilterGraph *fg) fg->reconfiguration = 1; - for (i = 0; i < fg->nb_outputs; i++) { - OutputStream *ost = fg->outputs[i]->ost; - if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO && - !(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) - av_buffersink_set_frame_size(ost->filter->filter, - ost->enc_ctx->frame_size); - } - for (i = 0; i < fg->nb_inputs; i++) { AVFrame *tmp; while (av_fifo_read(fg->inputs[i]->frame_queue, &tmp, 1) >= 0) { diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index ebc17059f9..385312d4fe 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -1451,7 +1451,7 @@ static void create_streams(Muxer *mux, const OptionsContext *o) static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_us) { OutputFile *of = &mux->of; - int nb_av_enc = 0, nb_interleaved = 0; + int nb_av_enc = 0, nb_audio_fs = 0, nb_interleaved = 0; int limit_frames = 0, limit_frames_av_enc = 0; #define IS_AV_ENC(ost, type) \ @@ -1468,19 +1468,26 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u nb_interleaved += IS_INTERLEAVED(type); nb_av_enc += IS_AV_ENC(ost, type); + nb_audio_fs += (ost->enc_ctx && type == AVMEDIA_TYPE_AUDIO && + !(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); limit_frames |= ms->max_frames < INT64_MAX; limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); } if (!((nb_interleaved > 1 && of->shortest) || - (nb_interleaved > 0 && limit_frames))) + (nb_interleaved > 0 && limit_frames) || + nb_audio_fs)) return 0; - /* if we have more than one encoded audio/video streams, or at least - * one encoded audio/video stream is frame-limited, then we - * synchronize them before encoding */ - if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc) { + /* we use a sync queue before encoding when: + * - 'shortest' is in effect and we have two or more encoded audio/video + * streams + * - 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 + */ + 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); if (!of->sq_encode) return AVERROR(ENOMEM); -- 2.39.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2023-03-25 19:18 UTC|newest] Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top 2023-03-25 19:15 [FFmpeg-devel] [PATCH 01/23] fftools/ffmpeg: drop InputStream.processing_needed Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 02/23] fftools/ffmpeg: move initializing next_[pd]ts to add_input_streams() Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 03/23] fftools/sync_queue: use timebase from input frames/packets Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 04/23] fftools/sync_queue: document overall design Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 05/23] fftools/sync_queue: support operation with no limiting streams Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 06/23] fftools/sync_queue: make sure audio duration matches sample count Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 07/23] fftools/sync_queue: allow requesting a specific number of audio samples Anton Khirnov 2023-03-29 23:41 ` James Almer 2023-03-25 19:15 ` Anton Khirnov [this message] 2023-03-25 21:43 ` [FFmpeg-devel] [PATCH 08/23] fftools/ffmpeg: use sync queues for enforcing audio frame size Michael Niedermayer 2023-03-27 5:15 ` [FFmpeg-devel] [PATCH] fftools/ffmpeg: do not return finished streams from choose_output() Anton Khirnov 2023-03-29 17:59 ` Michael Niedermayer 2023-03-30 8:48 ` Anton Khirnov 2023-04-02 15:58 ` Michael Niedermayer 2023-04-03 10:09 ` [FFmpeg-devel] [PATCH] fftools/ffmpeg: make sure non-lavfi streams are closed on input EOF Anton Khirnov 2023-04-05 22:33 ` Michael Niedermayer 2023-04-06 7:27 ` Anton Khirnov 2023-03-29 18:08 ` [FFmpeg-devel] [PATCH 08/23] fftools/ffmpeg: use sync queues for enforcing audio frame size Michael Niedermayer 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 09/23] fftools/ffmpeg: stop handling AVMEDIA_TYPE_DATA in init_output_stream_encode() Anton Khirnov 2023-03-25 19:43 ` James Almer 2023-03-26 9:20 ` Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 10/23] fftools/ffmpeg: drop unnecessarily indirection Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 11/23] fftools/ffmpeg: use stack variables to shorten code Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 12/23] fftools/ffmpeg: move encoder initialization to init_output_stream_encode Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 13/23] fftools/ffmpeg: reindent after previous commit Anton Khirnov 2023-03-28 22:42 ` Michael Niedermayer 2023-03-29 0:16 ` Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 14/23] fftools/ffmpeg: move initializing encoders to a new file Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 15/23] fftools/ffmpeg: simplify output stream initialization call graph Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 16/23] fftools/ffmpeg: replace ff_dlog() with av_log() Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 17/23] fftools/ffmpeg: move subtitle encoding to ffmpeg_enc.c Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 18/23] fftools/ffmpeg: move audio/video encoding code " Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 19/23] fftools/ffmpeg: add encoder private data Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 20/23] fftools/ffmpeg: stop including os_support.h Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 21/23] fftools/ffmpeg: clean up system header includes Anton Khirnov 2023-03-27 5:35 ` Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 22/23] fftools/ffmpeg: clean up local includes Anton Khirnov 2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 23/23] fftools/ffmpeg_enc: factorize calling enc_init() Anton Khirnov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20230325191529.10578-8-anton@khirnov.net \ --to=anton@khirnov.net \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git