From patchwork Wed Mar 6 11:03:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 46842 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:d90e:b0:19e:cdac:8cce with SMTP id jd14csp313630pzb; Wed, 6 Mar 2024 03:06:52 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCXFAZtODDcle2cfc1R9hvI6070ywbaLvA4f0fPSP+TjU/hVbLpTAgRNhvEN8p8c0IepIsDcWMZKTIl4GmON0NPk5k0dYyvOwDRssA== X-Google-Smtp-Source: AGHT+IGWKfEwhPoodkujZJshIXk8L9OUX0vqzIbsvLDMLVxxwf/jzpnl6lwPOtpBhSEi1Zfsmlo9 X-Received: by 2002:a17:906:1959:b0:a3e:93d0:3443 with SMTP id b25-20020a170906195900b00a3e93d03443mr9069157eje.34.1709723211867; Wed, 06 Mar 2024 03:06:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1709723211; cv=none; d=google.com; s=arc-20160816; b=pRZmS6Z9SdpWVQ57IKCEtA6IMMQE2WODhhwuGgkd208AjJ3CXHm303Yu/f7IkkXtw2 H/bezba/OQtGFJlLGwYEZdE4JZpSF8OPlmnNsc+gD0re6Qe6nPi7QLx7xd9c1ATIizFZ JU4RBfpiVaPNF5A37Mk/4tpeQ3mGTBynIKZ4PzGndLlqQ1T1P7JHMQ0HnD6DXRLzEv9v V1A0FjZuNW+rTeJz7zlJkx/gkJfsu1DdYzspEf5MpIS2N/x9fUwq8/yzp2v6iwqeVB6F NQFl0cXoOstsDBostLj7Ve+GeeNVEQLSJvnLqDrL9caZk5L/SQOeXy0fYEouLQmga9jq 6NUw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=SDa7ZRHUXk5pEQJqsSAdZcLJUYpVcV3pyfyb7iKMD38=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=k0iz+6+eX9/ztNUGnUPMsz9dOFCl6jUmO1aQlzhBhNBK2B7/5/IdB2dW7TOFSR16FB ifj9/f+T9bhsHbqlnRaLp1dLgOfYrO02pPS/n7+SbZhiRoaz/hkduUCqMm8NNAGHdpMN U3Fvl/cVE2apOqRUMA9nC0h+ygG56NpJ2cXZSk6EAP6zxEcOjwkY4MEJsKqDYvStYM6B dUfC9lqL0aiIkM20vOrOa21zFX0JmWMgclMS7n0b2QOQMEYQzyFCoPxl/kVAeiyRkzjk XiAiQfaD14/z55kmh3EUTrsgd56Sqe4bee0bVFIroYpdMKo/Vy6ZEgD1LLmFVgWuuVV4 jBCg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=FNPdJlPw; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id a17-20020a17090680d100b00a45bc0a2394si430659ejx.1049.2024.03.06.03.06.51; Wed, 06 Mar 2024 03:06:51 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=FNPdJlPw; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B5C7D68CDFB; Wed, 6 Mar 2024 13:05:38 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail1.khirnov.net (quelana.khirnov.net [94.230.150.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9B0FD68CAF7 for ; Wed, 6 Mar 2024 13:05:30 +0200 (EET) Authentication-Results: mail1.khirnov.net; dkim=pass (2048-bit key; unprotected) header.d=khirnov.net header.i=@khirnov.net header.a=rsa-sha256 header.s=mail header.b=FNPdJlPw; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id EAABE4D54 for ; Wed, 6 Mar 2024 12:05:26 +0100 (CET) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id nUVs_Rst-a23 for ; Wed, 6 Mar 2024 12:05:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1709723123; bh=meeVTIJk4moi4tc4pMkg9DXCv7Z3nJlnwtAASbh1/Is=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FNPdJlPwQti+PexuFzKYJIY9XjMg0/2cf+TE1BwNf2Ah62cI774/kvq/CaPLSwJa9 HIkkY1OkH/Wm+648TP8d2fJ3vQ6z3QjhoKuVXjo6/nEtQHbdQ30CD1JMJM3Sfvoskb NPeXVzFAPeovt5dypLohv9GlPIhoFmJsul2iX1vPhWLb03wFW2Wxke5x2/xe3L85DG tU/eVCFmctuLqBrm0aQHOqAkbRsZCHz0FzQ/UAtUtytL3RuU4qzwTLx/eyNwJVGGUo Ahk/tzAvBTCZyz17MlLuuqXXy++Wgz7knbnjtzXCK0gnc9q6c3X/RKLUU72D1WLV6C Pnqq/Az0UVOsw== Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail1.khirnov.net (Postfix) with ESMTPS id 247624D5D for ; Wed, 6 Mar 2024 12:05:23 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 16FA43A0582 for ; Wed, 6 Mar 2024 12:05:23 +0100 (CET) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Wed, 6 Mar 2024 12:03:14 +0100 Message-ID: <20240306110319.17339-13-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240306110319.17339-1-anton@khirnov.net> References: <20240306110319.17339-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 13/18] fftools/ffmpeg_sched: allow encoders to send to multiple destinations X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: gwpPp19owCBi Will become useful in following commits. --- fftools/ffmpeg_sched.c | 117 ++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 19 deletions(-) diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c index cf9b0c836e..e5435dd866 100644 --- a/fftools/ffmpeg_sched.c +++ b/fftools/ffmpeg_sched.c @@ -104,7 +104,9 @@ typedef struct SchEnc { const AVClass *class; SchedulerNode src; - SchedulerNode dst; + SchedulerNode *dst; + uint8_t *dst_finished; + unsigned nb_dst; // [0] - index of the sync queue in Scheduler.sq_enc, // [1] - index of this encoder in the sq @@ -134,7 +136,9 @@ typedef struct SchEnc { ThreadQueue *queue; // tq_send() to queue returned EOF int in_finished; - int out_finished; + + // temporary storage used by sch_enc_send() + AVPacket *send_pkt; } SchEnc; typedef struct SchDemuxStream { @@ -569,6 +573,11 @@ void sch_free(Scheduler **psch) SchEnc *enc = &sch->enc[i]; tq_free(&enc->queue); + + av_packet_free(&enc->send_pkt); + + av_freep(&enc->dst); + av_freep(&enc->dst_finished); } av_freep(&sch->enc); @@ -819,6 +828,10 @@ int sch_add_enc(Scheduler *sch, SchThreadFunc func, void *ctx, task_init(sch, &enc->task, SCH_NODE_TYPE_ENC, idx, func, ctx); + enc->send_pkt = av_packet_alloc(); + if (!enc->send_pkt) + return AVERROR(ENOMEM); + ret = queue_alloc(&enc->queue, 1, 0, QUEUE_FRAMES); if (ret < 0) return ret; @@ -1048,9 +1061,14 @@ int sch_connect(Scheduler *sch, SchedulerNode src, SchedulerNode dst) enc = &sch->enc[src.idx]; ms = &sch->mux[dst.idx].streams[dst.idx_stream]; - av_assert0(!enc->dst.type && !ms->src.type); - enc->dst = dst; - ms->src = src; + av_assert0(!ms->src.type); + + ret = GROW_ARRAY(enc->dst, enc->nb_dst); + if (ret < 0) + return ret; + + enc->dst[enc->nb_dst - 1] = dst; + ms->src = src; break; } @@ -1339,12 +1357,16 @@ int sch_start(Scheduler *sch) "Encoder not connected to a source\n"); return AVERROR(EINVAL); } - if (!enc->dst.type) { + if (!enc->nb_dst) { av_log(enc, AV_LOG_ERROR, - "Encoder not connected to a sink\n"); + "Encoder not connected to any sink\n"); return AVERROR(EINVAL); } + enc->dst_finished = av_calloc(enc->nb_dst, sizeof(*enc->dst_finished)); + if (!enc->dst_finished) + return AVERROR(ENOMEM); + ret = task_start(&enc->task); if (ret < 0) return ret; @@ -1518,15 +1540,21 @@ static int send_to_enc_sq(Scheduler *sch, SchEnc *enc, AVFrame *frame) // TODO: consider a cleaner way of passing this information through // the pipeline if (!frame) { - SchMux *mux = &sch->mux[enc->dst.idx]; - SchMuxStream *ms = &mux->streams[enc->dst.idx_stream]; + for (unsigned i = 0; i < enc->nb_dst; i++) { + SchMux *mux; + SchMuxStream *ms; - pthread_mutex_lock(&sch->schedule_lock); - ms->source_finished = 1; - schedule_update_locked(sch); + mux = &sch->mux[enc->dst[i].idx]; + ms = &mux->streams[enc->dst[i].idx_stream]; - pthread_mutex_unlock(&sch->schedule_lock); + pthread_mutex_lock(&sch->schedule_lock); + + ms->source_finished = 1; + schedule_update_locked(sch); + + pthread_mutex_unlock(&sch->schedule_lock); + } } pthread_mutex_lock(&sq->lock); @@ -2080,20 +2108,64 @@ int sch_enc_receive(Scheduler *sch, unsigned enc_idx, AVFrame *frame) return ret; } +static int enc_send_to_dst(Scheduler *sch, const SchedulerNode dst, + uint8_t *dst_finished, AVPacket *pkt) +{ + int ret; + + if (*dst_finished) + return AVERROR_EOF; + + if (!pkt) + goto finish; + + ret = send_to_mux(sch, &sch->mux[dst.idx], dst.idx_stream, pkt); + if (ret == AVERROR_EOF) + goto finish; + + return ret; + +finish: + send_to_mux(sch, &sch->mux[dst.idx], dst.idx_stream, NULL); + + *dst_finished = 1; + + return AVERROR_EOF; +} + int sch_enc_send(Scheduler *sch, unsigned enc_idx, AVPacket *pkt) { SchEnc *enc; int ret; + unsigned nb_done = 0; av_assert0(enc_idx < sch->nb_enc); enc = &sch->enc[enc_idx]; - if (enc->out_finished) - return pkt ? AVERROR_EOF : 0; + for (unsigned i = 0; i < enc->nb_dst; i++) { + uint8_t *finished = &enc->dst_finished[i]; + AVPacket *to_send = pkt; - ret = send_to_mux(sch, &sch->mux[enc->dst.idx], enc->dst.idx_stream, pkt); - if (ret < 0) - enc->out_finished = 1; + // sending a packet consumes it, so make a temporary reference if needed + if (i < enc->nb_dst - 1) { + to_send = enc->send_pkt; + + ret = av_packet_ref(to_send, pkt); + if (ret < 0) + return ret; + } + + ret = enc_send_to_dst(sch, enc->dst[i], finished, to_send); + if (ret < 0) { + av_packet_unref(to_send); + if (ret == AVERROR_EOF) { + nb_done++; + ret = 0; + continue; + } + return ret; + } + } return ret; } @@ -2101,10 +2173,17 @@ int sch_enc_send(Scheduler *sch, unsigned enc_idx, AVPacket *pkt) static int enc_done(Scheduler *sch, unsigned enc_idx) { SchEnc *enc = &sch->enc[enc_idx]; + int ret = 0; tq_receive_finish(enc->queue, 0); - return send_to_mux(sch, &sch->mux[enc->dst.idx], enc->dst.idx_stream, NULL); + for (unsigned i = 0; i < enc->nb_dst; i++) { + int err = enc_send_to_dst(sch, enc->dst[i], &enc->dst_finished[i], NULL); + if (err < 0 && err != AVERROR_EOF) + ret = err_merge(ret, err); + } + + return ret; } int sch_filter_receive(Scheduler *sch, unsigned fg_idx,