From patchwork Mon Jul 12 11:07:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28895 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2812094ybk; Mon, 12 Jul 2021 04:08:46 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxPZyNicp0AwwEUBo03YpkxMD6uVC4NULunkOVTHZw730EDs+lAEok1eacbbx2/D6qPq17W X-Received: by 2002:a05:6402:49a:: with SMTP id k26mr64304259edv.279.1626088126653; Mon, 12 Jul 2021 04:08:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088126; cv=none; d=google.com; s=arc-20160816; b=HuRo3e3KkSLgyGwkZenpF8VCkjwhyRZjDd3LJzht5JUaJEXV24L13MHepePtWtx+Zu RSy8JXltn5tA0fd/vW2OHWQpxkhSX5/cJa5cGrgsH02Y6LfzPO8yGpOU6djaB1faeldJ xFoYEiZVYhr/IJkclPdTUou6ZYXvw5Xz51T6aDOXFeRV2HDtCZGfNsrZfXKrvDUfCDMU Ood+NVuJnTciiihwJhayxIkzuRu27L7jh/xk9vEKktpQjdZMFW1+OlEJwQwMtzQ218Kf HtxOLdJG8vTFg+1FsQ8bWcCUJqOvsC6pN6u+K1PNmLcCb2ZJJsTCgSYXo6h3VKcjPOS6 AVcQ== 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:delivered-to; bh=b++2g2thxZiV/z5ED8x0EG6YIuGJmpfwy8MHe1S0mHc=; b=Cpc3zVXR1HlVCda5Y8YjxWmpPLdl3ncCaLKFPk63PrUhz1caFmAosgSDSfcGD+eWnA DQIqIorWN1h8v0tY9tSABnzhCUT1wF0Wokp3Frq5tIsMMIpOhcS0iccCXmA40GzZVpDR tjW22y/39e49dFvgXOCLUKiCnbvIVb8sTG8BKK0/HKOIVdRc7bSP6kc98EKMM7P3yxYD AWpGw/PYOEi3n8sL0B9T6164Z2aJLfFKCuTgn8SDOwrauwjGqKavOmDlFB1Wq+yglBWM c60iM+mWYLGV8+ArXp16tlirzU16MPweA411XplJQYcgWqZeRtq++eq/VT5tXO3G9xVo PZdA== ARC-Authentication-Results: i=1; mx.google.com; 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 d9si16245049ede.533.2021.07.12.04.08.46; Mon, 12 Jul 2021 04:08:46 -0700 (PDT) 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; 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 4E88768A962; Mon, 12 Jul 2021 14:08:05 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B307C6898E4 for ; Mon, 12 Jul 2021 14:07:55 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 67F9C240692 for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id sLtf-76LplLG for ; Mon, 12 Jul 2021 13:07:54 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id 6C31F240694 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id 98D9E3A08EC; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:02 +0200 Message-Id: <20210712110709.15532-2-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/8] tools/venc_data_dump: factor out demux/decode code 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: QFzQs80LonOn Content-Length: 14247 It can be shared with other simple demux/decode tools. --- tests/ref/fate/source | 1 + tools/Makefile | 2 + tools/decode_simple.c | 157 +++++++++++++++++++++++++++++++++++++++++ tools/decode_simple.h | 53 ++++++++++++++ tools/venc_data_dump.c | 156 +++++++++------------------------------- 5 files changed, 248 insertions(+), 121 deletions(-) create mode 100644 tools/decode_simple.c create mode 100644 tools/decode_simple.h diff --git a/tests/ref/fate/source b/tests/ref/fate/source index c64bc05241..69dcdc4f27 100644 --- a/tests/ref/fate/source +++ b/tests/ref/fate/source @@ -20,5 +20,6 @@ Headers without standard inclusion guards: compat/djgpp/math.h compat/float/float.h compat/float/limits.h +tools/decode_simple.h Use of av_clip() where av_clip_uintp2() could be used: Use of av_clip() where av_clip_intp2() could be used: diff --git a/tools/Makefile b/tools/Makefile index 82baa8eadb..ec260f254e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -17,6 +17,8 @@ tools/target_dem_fuzzer.o: tools/target_dem_fuzzer.c tools/target_io_dem_fuzzer.o: tools/target_dem_fuzzer.c $(COMPILE_C) -DIO_FLAT=0 +tools/venc_data_dump$(EXESUF): tools/decode_simple.o + OUTDIRS += tools clean:: diff --git a/tools/decode_simple.c b/tools/decode_simple.c new file mode 100644 index 0000000000..b679fd7ce6 --- /dev/null +++ b/tools/decode_simple.c @@ -0,0 +1,157 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* shared code for simple demux/decode tools */ + +#include +#include + +#include "decode_simple.h" + +#include "libavformat/avformat.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/packet.h" + +#include "libavutil/dict.h" +#include "libavutil/error.h" +#include "libavutil/frame.h" + +static int decode_read(DecodeContext *dc, int flush) +{ + const int ret_done = flush ? AVERROR_EOF : AVERROR(EAGAIN); + int ret = 0; + + while (ret >= 0 && + (dc->max_frames == 0 || dc->decoder->frame_number < dc->max_frames)) { + ret = avcodec_receive_frame(dc->decoder, dc->frame); + if (ret < 0) { + if (ret == AVERROR_EOF) { + int err = dc->process_frame(dc, NULL); + if (err < 0) + return err; + } + + return (ret == ret_done) ? 0 : ret; + } + + ret = dc->process_frame(dc, dc->frame); + av_frame_unref(dc->frame); + if (ret < 0) + return ret; + + if (dc->max_frames && dc->decoder->frame_number == dc->max_frames) + return 1; + } + + return (dc->max_frames == 0 || dc->decoder->frame_number < dc->max_frames) ? 0 : 1; +} + +int ds_run(DecodeContext *dc) +{ + int ret; + + ret = avcodec_open2(dc->decoder, NULL, &dc->decoder_opts); + if (ret < 0) + return ret; + + while (ret >= 0) { + ret = av_read_frame(dc->demuxer, dc->pkt); + if (ret < 0) + goto flush; + if (dc->pkt->stream_index != dc->stream->index) { + av_packet_unref(dc->pkt); + continue; + } + + ret = avcodec_send_packet(dc->decoder, dc->pkt); + if (ret < 0) { + fprintf(stderr, "Error decoding: %d\n", ret); + return ret; + } + av_packet_unref(dc->pkt); + + ret = decode_read(dc, 0); + if (ret < 0) { + fprintf(stderr, "Error decoding: %d\n", ret); + return ret; + } else if (ret > 0) + return 0; + } + +flush: + avcodec_send_packet(dc->decoder, NULL); + ret = decode_read(dc, 1); + if (ret < 0) { + fprintf(stderr, "Error flushing: %d\n", ret); + return ret; + } + + return 0; +} + +void ds_free(DecodeContext *dc) +{ + av_dict_free(&dc->decoder_opts); + + av_frame_free(&dc->frame); + av_packet_free(&dc->pkt); + + avcodec_free_context(&dc->decoder); + avformat_close_input(&dc->demuxer); +} + +int ds_open(DecodeContext *dc, const char *url, int stream_idx) +{ + const AVCodec *codec; + int ret; + + memset(dc, 0, sizeof(*dc)); + + dc->pkt = av_packet_alloc(); + dc->frame = av_frame_alloc(); + if (!dc->pkt || !dc->frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = avformat_open_input(&dc->demuxer, url, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error opening input file: %d\n", ret); + return ret; + } + + if (stream_idx < 0 || stream_idx >= dc->demuxer->nb_streams) + return AVERROR(EINVAL); + + dc->stream = dc->demuxer->streams[stream_idx]; + + codec = avcodec_find_decoder(dc->stream->codecpar->codec_id); + if (!codec) + return AVERROR_DECODER_NOT_FOUND; + + dc->decoder = avcodec_alloc_context3(codec); + if (!dc->decoder) + return AVERROR(ENOMEM); + + return 0; + +fail: + ds_free(dc); + return ret; +} diff --git a/tools/decode_simple.h b/tools/decode_simple.h new file mode 100644 index 0000000000..d480489a6c --- /dev/null +++ b/tools/decode_simple.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* shared code for simple demux/decode tools */ + +#ifndef DECODE_SIMPLE_H +#define DECODE_SIMPLE_H + +#include "libavformat/avformat.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/packet.h" + +#include "libavutil/dict.h" +#include "libavutil/frame.h" + + +typedef struct DecodeContext { + AVFormatContext *demuxer; + AVStream *stream; + AVCodecContext *decoder; + + AVPacket *pkt; + AVFrame *frame; + + int (*process_frame)(struct DecodeContext *dc, AVFrame *frame); + void *opaque; + + AVDictionary *decoder_opts; + int max_frames; +} DecodeContext; + +int ds_open(DecodeContext *dc, const char *url, int stream_idx); +void ds_free(DecodeContext *dc); + +int ds_run(DecodeContext *dc); + +#endif /* DECODE_SIMPLE_H */ diff --git a/tools/venc_data_dump.c b/tools/venc_data_dump.c index 3a6ce94268..3a3543f80f 100644 --- a/tools/venc_data_dump.c +++ b/tools/venc_data_dump.c @@ -20,6 +20,8 @@ #include #include +#include "decode_simple.h" + #include "libavutil/common.h" #include "libavutil/dict.h" #include "libavutil/error.h" @@ -29,85 +31,44 @@ #include "libavcodec/avcodec.h" -static int decode_read(AVCodecContext *decoder, AVFrame *frame, int flush, int max_frames) +static int process_frame(DecodeContext *dc, AVFrame *frame) { - const int ret_done = flush ? AVERROR_EOF : AVERROR(EAGAIN); - int ret = 0; - - while (ret >= 0 && - (max_frames == 0 || decoder->frame_number < max_frames)) { - AVFrameSideData *sd; + AVFrameSideData *sd; - ret = avcodec_receive_frame(decoder, frame); - if (ret < 0) - return (ret == ret_done) ? 0 : ret; + if (!frame) + return 0; - fprintf(stdout, "frame %d\n", decoder->frame_number - 1); + fprintf(stdout, "frame %d\n", dc->decoder->frame_number - 1); - sd = av_frame_get_side_data(frame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); - if (sd) { - AVVideoEncParams *par = (AVVideoEncParams*)sd->data; + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); + if (sd) { + AVVideoEncParams *par = (AVVideoEncParams*)sd->data; - fprintf(stdout, "AVVideoEncParams %d\n", par->type); - fprintf(stdout, "qp %d\n", par->qp); - for (int i = 0; i < FF_ARRAY_ELEMS(par->delta_qp); i++) - for (int j = 0; j < FF_ARRAY_ELEMS(par->delta_qp[i]); j++) { - if (par->delta_qp[i][j]) - fprintf(stdout, "delta_qp[%d][%d] %"PRId32"\n", i, j, par->delta_qp[i][j]); - } + fprintf(stdout, "AVVideoEncParams %d\n", par->type); + fprintf(stdout, "qp %d\n", par->qp); + for (int i = 0; i < FF_ARRAY_ELEMS(par->delta_qp); i++) + for (int j = 0; j < FF_ARRAY_ELEMS(par->delta_qp[i]); j++) { + if (par->delta_qp[i][j]) + fprintf(stdout, "delta_qp[%d][%d] %"PRId32"\n", i, j, par->delta_qp[i][j]); + } - if (par->nb_blocks) { - fprintf(stdout, "nb_blocks %d\n", par->nb_blocks); - for (int i = 0; i < par->nb_blocks; i++) { - AVVideoBlockParams *b = av_video_enc_params_block(par, i); + if (par->nb_blocks) { + fprintf(stdout, "nb_blocks %d\n", par->nb_blocks); + for (int i = 0; i < par->nb_blocks; i++) { + AVVideoBlockParams *b = av_video_enc_params_block(par, i); - fprintf(stdout, "block %d %d:%d %dx%d %"PRId32"\n", - i, b->src_x, b->src_y, b->w, b->h, b->delta_qp); - } + fprintf(stdout, "block %d %d:%d %dx%d %"PRId32"\n", + i, b->src_x, b->src_y, b->w, b->h, b->delta_qp); } } - - av_frame_unref(frame); - - if (max_frames && decoder->frame_number == max_frames) - return 1; } - return (max_frames == 0 || decoder->frame_number < max_frames) ? 0 : 1; -} - -static int decoder_init(AVFormatContext *demuxer, int stream_idx, - AVCodecContext **dec, AVDictionary **opts) -{ - const AVCodec *codec; - int ret; - - if (stream_idx < 0 || stream_idx >= demuxer->nb_streams) - return AVERROR(EINVAL); - - codec = avcodec_find_decoder(demuxer->streams[stream_idx]->codecpar->codec_id); - if (!codec) - return AVERROR_DECODER_NOT_FOUND; - - *dec = avcodec_alloc_context3(codec); - if (!*dec) - return AVERROR(ENOMEM); - - ret = avcodec_open2(*dec, NULL, opts); - if (ret < 0) - return ret; - return 0; } int main(int argc, char **argv) { - AVFormatContext *demuxer = NULL; - AVCodecContext *decoder = NULL; - AVDictionary *opts = NULL; - - AVPacket *pkt = NULL; - AVFrame *frame = NULL; + DecodeContext dc; unsigned int stream_idx, max_frames; const char *filename, *thread_type = NULL, *nb_threads = NULL; @@ -126,70 +87,23 @@ int main(int argc, char **argv) thread_type = argv[5]; } - ret = av_dict_set(&opts, "threads", nb_threads, 0); - ret |= av_dict_set(&opts, "thread_type", thread_type, 0); - ret |= av_dict_set(&opts, "export_side_data", "venc_params", 0); - - ret = avformat_open_input(&demuxer, filename, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error opening input file: %d\n", ret); - return ret; - } - - ret = decoder_init(demuxer, stream_idx, &decoder, &opts); - if (ret < 0) { - fprintf(stderr, "Error initializing decoder\n"); - goto finish; - } - - pkt = av_packet_alloc(); - frame = av_frame_alloc(); - if (!pkt || !frame) { - ret = AVERROR(ENOMEM); + ret = ds_open(&dc, filename, stream_idx); + if (ret < 0) goto finish; - } - while (ret >= 0) { - ret = av_read_frame(demuxer, pkt); - if (ret < 0) - goto flush; - if (pkt->stream_index != stream_idx) { - av_packet_unref(pkt); - continue; - } + dc.process_frame = process_frame; + dc.max_frames = max_frames; - ret = avcodec_send_packet(decoder, pkt); - if (ret < 0) { - fprintf(stderr, "Error decoding: %d\n", ret); - goto finish; - } - av_packet_unref(pkt); - - ret = decode_read(decoder, frame, 0, max_frames); - if (ret < 0) { - fprintf(stderr, "Error decoding: %d\n", ret); - goto finish; - } else if (ret > 0) { - ret = 0; - goto finish; - } - } + ret = av_dict_set(&dc.decoder_opts, "threads", nb_threads, 0); + ret |= av_dict_set(&dc.decoder_opts, "thread_type", thread_type, 0); + ret |= av_dict_set(&dc.decoder_opts, "export_side_data", "venc_params", 0); -flush: - avcodec_send_packet(decoder, NULL); - ret = decode_read(decoder, frame, 1, max_frames); - if (ret < 0) { - fprintf(stderr, "Error flushing: %d\n", ret); + if (ret < 0) goto finish; - } - ret = 0; -finish: - av_dict_free(&opts); - av_packet_free(&pkt); - av_frame_free(&frame); - avcodec_free_context(&decoder); - avformat_close_input(&demuxer); + ret = ds_run(&dc); +finish: + ds_free(&dc); return ret; } From patchwork Mon Jul 12 11:07:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28910 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2811703ybk; Mon, 12 Jul 2021 04:08:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx3yVtPFDuHi3C8q80HYKmD+dpNQbcme7zC8EvTRFYXI7GlmqoIasr/B9CQIySJsFrvmBqr X-Received: by 2002:a17:906:190c:: with SMTP id a12mr26803236eje.37.1626088092813; Mon, 12 Jul 2021 04:08:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088092; cv=none; d=google.com; s=arc-20160816; b=p6LmvazgyVv0TP2jHPnh8jUf2kgJkki4qPhMnphMxaBqX7QaqS7o+e6ICpF2RiZQwU zv0ldOStl3wq52DZcZBEFrizilw4YcFWl1TYHE8s1z+k3ZEmkxFVaY3gsLV7L3dcJrEQ +beO/cBQhIxan89SFZOuF0+rQ3VJBCWhSCn2fnIZxC+l3uZdxEMdDuOfjEEkLHnN/5kl 6h1wLD7VAlcMP5naQlHDhFp5IyxcKeMLr+PulhMGX7PfOUbZgmCRXRYYI3i8OMVLXoS6 N/xidFQ6OLRbcEy1TKy/9YK+WB+EO8qVWDujz+ASrGzlYYtzmMOptWIXBtfXesdFXNR2 jY2w== 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:delivered-to; bh=ZkciRnzpVANEQu7RCtT/zCVe/0l6Vd/uroXrvkc9hHo=; b=DsVojzXIPn+qepWWvIHzAMlZLroXa0p4K49s6Ud3XSQRJnet3QRf3AI2zuO8wHjzCe duF7UBAcqzPDfxMa8SuxiCQ2tEm9f3TCJrBGhKWBoO47fijooy+Wnd/7QFkJ/wRzH1UZ jMNO+wKCiJgekWLIY4lRBoBAJcIOQxykYcinSDrb88z9DGIGY2PAtWemwk+MqN7/oTpT I/uULQnDJvKeCMcpmrxdciEW6nvohzxIoVVkHeqrrM9LurDEwYcBqHdI9EaP8jFMV5XM gUAKaHilWfq+eC3qJ+VvWUFez+WZWuETKl2TY4uGTkcV3GCyIZpIekdF3q4w1ounwMWf xSkg== ARC-Authentication-Results: i=1; mx.google.com; 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 r14si14216586edw.524.2021.07.12.04.08.12; Mon, 12 Jul 2021 04:08:12 -0700 (PDT) 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; 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 E9EA468A938; Mon, 12 Jul 2021 14:08:01 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C91B76898E4 for ; Mon, 12 Jul 2021 14:07:54 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 8303E240693 for ; Mon, 12 Jul 2021 13:07:54 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id TwwtOugf8l7K for ; Mon, 12 Jul 2021 13:07:53 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id 651B72404B2 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id 9CC253A0909; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:03 +0200 Message-Id: <20210712110709.15532-3-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/8] FATE: add a test for sliced scaling 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: Ks5kxNiNuTds Content-Length: 9267 --- Makefile | 2 + tests/Makefile | 1 + tests/fate/libswscale.mak | 11 +++ tools/Makefile | 3 +- tools/scale_slice_test.c | 190 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 tools/scale_slice_test.c diff --git a/Makefile b/Makefile index 1e3da6271b..26c9107237 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,8 @@ tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o $(FF_DEP_LIBS) tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/enum_options$(EXESUF): $(FF_DEP_LIBS) +tools/scale_slice_test$(EXESUF): $(FF_DEP_LIBS) +tools/scale_slice_test$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) diff --git a/tests/Makefile b/tests/Makefile index d726484b3a..e42e66d81b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -221,6 +221,7 @@ $(FATE_FFPROBE) $(FATE_FFMPEG_FFPROBE) $(FATE_SAMPLES_FFPROBE) $(FATE_SAMPLES_FF $(FATE_SAMPLES_FASTSTART): tools/qt-faststart$(EXESUF) $(FATE_SAMPLES_DUMP_DATA): tools/venc_data_dump$(EXESUF) +$(FATE_SAMPLES_SCALE_SLICE): tools/scale_slice_test$(EXESUF) ifdef SAMPLES FATE += $(FATE_EXTERN) diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak index 5ec5f34cc4..599d27b0a5 100644 --- a/tests/fate/libswscale.mak +++ b/tests/fate/libswscale.mak @@ -6,6 +6,17 @@ FATE_LIBSWSCALE += fate-sws-floatimg-cmp fate-sws-floatimg-cmp: libswscale/tests/floatimg_cmp$(EXESUF) fate-sws-floatimg-cmp: CMD = run libswscale/tests/floatimg_cmp$(EXESUF) +SWS_SLICE_TEST-$(call DEMDEC, MATROSKA, VP9) += fate-sws-slice-yuv422-12bit-rgb48 +fate-sws-slice-yuv422-12bit-rgb48: CMD = run tools/scale_slice_test$(EXESUF) $(TARGET_SAMPLES)/vp9-test-vectors/vp93-2-20-12bit-yuv422.webm 150 100 rgb48 + +SWS_SLICE_TEST-$(call DEMDEC, IMAGE_BMP_PIPE, BMP) += fate-sws-slice-bgr0-nv12 +fate-sws-slice-bgr0-nv12: CMD = run tools/scale_slice_test$(EXESUF) $(TARGET_SAMPLES)/bmp/test32bf.bmp 32 64 nv12 + +fate-sws-slice: $(SWS_SLICE_TEST-yes) +$(SWS_SLICE_TEST-yes): tools/scale_slice_test$(EXESUF) +$(SWS_SLICE_TEST-yes): REF = /dev/null +FATE_LIBSWSCALE += $(SWS_SLICE_TEST-yes) + FATE_LIBSWSCALE += $(FATE_LIBSWSCALE-yes) FATE-$(CONFIG_SWSCALE) += $(FATE_LIBSWSCALE) fate-libswscale: $(FATE_LIBSWSCALE) diff --git a/tools/Makefile b/tools/Makefile index ec260f254e..f4d1327b9f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,4 @@ -TOOLS = enum_options qt-faststart trasher uncoded_frame +TOOLS = enum_options qt-faststart scale_slice_test trasher uncoded_frame TOOLS-$(CONFIG_LIBMYSOFA) += sofa2wavs TOOLS-$(CONFIG_ZLIB) += cws2fws @@ -18,6 +18,7 @@ tools/target_io_dem_fuzzer.o: tools/target_dem_fuzzer.c $(COMPILE_C) -DIO_FLAT=0 tools/venc_data_dump$(EXESUF): tools/decode_simple.o +tools/scale_slice_test$(EXESUF): tools/decode_simple.o OUTDIRS += tools diff --git a/tools/scale_slice_test.c b/tools/scale_slice_test.c new file mode 100644 index 0000000000..d869eaae74 --- /dev/null +++ b/tools/scale_slice_test.c @@ -0,0 +1,190 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "decode_simple.h" + +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/error.h" +#include "libavutil/lfg.h" +#include "libavutil/random_seed.h" +#include "libavutil/video_enc_params.h" + +#include "libavformat/avformat.h" + +#include "libavcodec/avcodec.h" + +#include "libswscale/swscale.h" + +typedef struct PrivData { + unsigned int random_seed; + AVLFG lfg; + + struct SwsContext *scaler; + + int v_shift_dst, h_shift_dst; + int v_shift_src, h_shift_src; + + AVFrame *frame_ref; + AVFrame *frame_dst; +} PrivData; + +static int process_frame(DecodeContext *dc, AVFrame *frame) +{ + PrivData *pd = dc->opaque; + int slice_start = 0; + int ret; + + if (!frame) + return 0; + + if (!pd->scaler) { + pd->scaler = sws_getContext(frame->width, frame->height, frame->format, + pd->frame_ref->width, pd->frame_ref->height, + pd->frame_ref->format, 0, NULL, NULL, NULL); + if (!pd->scaler) + return AVERROR(ENOMEM); + + av_pix_fmt_get_chroma_sub_sample(frame->format, &pd->h_shift_src, &pd->v_shift_src); + } + + /* scale the whole input frame as reference */ + ret = sws_scale(pd->scaler, (const uint8_t **)frame->data, frame->linesize, 0, frame->height, + pd->frame_ref->data, pd->frame_ref->linesize); + if (ret < 0) + return ret; + + /* scale slices with randomly generated heights */ + while (slice_start < frame->height) { + int slice_height; + const uint8_t *src[4]; + + slice_height = av_lfg_get(&pd->lfg) % (frame->height - slice_start); + slice_height = FFALIGN(FFMAX(1, slice_height), 1 << pd->v_shift_src); + + for (int j = 0; j < FF_ARRAY_ELEMS(src) && frame->data[j]; j++) { + int shift = (j == 1 || j == 2) ? pd->v_shift_src : 0; + src[j] = frame->data[j] + frame->linesize[j] * (slice_start >> shift); + } + + ret = sws_scale(pd->scaler, src, frame->linesize, slice_start, slice_height, + pd->frame_dst->data, pd->frame_dst->linesize); + if (ret < 0) + return ret; + + slice_start += slice_height; + } + + /* compare the two results */ + for (int i = 0; i < 4 && pd->frame_ref->data[i]; i++) { + int shift = (i == 1 || i == 2) ? pd->v_shift_dst : 0; + + if (memcmp(pd->frame_ref->data[i], pd->frame_dst->data[i], + pd->frame_ref->linesize[i] * (pd->frame_ref->height >> shift))) { + fprintf(stderr, "mismatch frame %d seed %u\n", + dc->decoder->frame_number - 1, pd->random_seed); + return AVERROR(EINVAL); + } + } + + return 0; +} + +int main(int argc, char **argv) +{ + PrivData pd; + DecodeContext dc; + + int width, height; + enum AVPixelFormat pix_fmt; + const char *filename; + int ret = 0; + + if (argc <= 4) { + fprintf(stderr, + "Usage: %s [] \n", + argv[0]); + return 0; + } + + memset(&pd, 0, sizeof(pd)); + + filename = argv[1]; + width = strtol(argv[2], NULL, 0); + height = strtol(argv[3], NULL, 0); + pix_fmt = av_get_pix_fmt(argv[4]); + + /* init RNG for generating slice sizes */ + if (argc >= 6) + pd.random_seed = strtoul(argv[5], NULL, 0); + else + pd.random_seed = av_get_random_seed(); + + av_lfg_init(&pd.lfg, pd.random_seed); + + av_pix_fmt_get_chroma_sub_sample(pix_fmt, &pd.h_shift_dst, &pd.v_shift_dst); + + /* allocate the frames for scaler output */ + for (int i = 0; i < 2; i++) { + AVFrame *frame = av_frame_alloc(); + if (!frame) { + fprintf(stderr, "Error allocating frames\n"); + return AVERROR(ENOMEM); + } + + frame->width = width; + frame->height = height; + frame->format = pix_fmt; + + ret = av_frame_get_buffer(frame, 0); + if (ret < 0) { + fprintf(stderr, "Error allocating frame data\n"); + return ret; + } + + /* make sure the padding is zeroed */ + for (int j = 0; j < 4 && frame->data[j]; j++) { + int shift = (j == 1 || j == 2) ? pd.v_shift_dst : 0; + memset(frame->data[j], 0, + frame->linesize[j] * (height >> shift)); + } + if (i) pd.frame_ref = frame; + else pd.frame_dst = frame; + } + + ret = ds_open(&dc, filename, 0); + if (ret < 0) { + fprintf(stderr, "Error opening the file\n"); + return ret; + } + + dc.process_frame = process_frame; + dc.opaque = &pd; + + ret = ds_run(&dc); + + av_frame_free(&pd.frame_dst); + av_frame_free(&pd.frame_ref); + sws_freeContext(pd.scaler); + ds_free(&dc); + return ret; +} From patchwork Mon Jul 12 11:07:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28897 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2811887ybk; Mon, 12 Jul 2021 04:08:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyCLZekNATUQ4pbgI7CmHwzF7x0+9y+BBu1B6PqxtMnTNMjO6/M8LihhfOm1X2wtjSH39C5 X-Received: by 2002:a05:6402:1a3c:: with SMTP id be28mr24572621edb.15.1626088106478; Mon, 12 Jul 2021 04:08:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088106; cv=none; d=google.com; s=arc-20160816; b=oQ2ToGJwLGYswPiiHjwjOIMwYaqEbGtuBHm95CxcXj8aH5iOhhHHah01d4UorJyIPX xruFhnKoIyzxh0jB7D6MR6RjnL358W6zJm+xnSAfETOXCGZExgFOokVT7s8+t/WJMyGo gRcKIEdcodESEykFfoC/wfaIYdHUjEJKpbIefPbCxeUjT1+AQhiOK+zQnNyelJYMubgT w0eJhbcn9/94xLLX1ULHUFLeX3DnP6I3aN5CuDwRmAyg9jolsJdSAgItYjid8Tf4/8+a BnkHi6v4/7I2cu/B6R6E1tQbLoNlb3FiumL+VNIrsVVPt/EO04XH/1UO0daXuO0XgSaG GO3g== 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:delivered-to; bh=298tljHZ+CIBrR4svUmWvFPCkRn7psjpt5DYfMei4vg=; b=kHLtfR5neCyc4l+uHIVugjUxotrwQolXNAcM/HWTdv0FnO++fPedFkk6zBVw8buGJP FrZTy7IUScbD7x8iS1K/K8507JI+7/0FI4cXCDRQXHGdCOpwPSrHmXusWmrGe/VaVcWK oUWjvl1zUyS8HGVCaT8jNp1/spqdS9C6EKfM2WzOdvcR7ZByoQdmZYeoRnsxPpPDmMMg rswYFzIgaZtID1DpSGiaheahcyikepjQFRuLNdYgrniTIxiEU2Ilj++ebWwolHXfdh+G gV0bzGbYsOA/BfE0Xb+MOSmtLXq79hgeXqtBdzlI5+u2ugnmDDRvOjH4wLJ2Tsy5zM0Q QYdA== ARC-Authentication-Results: i=1; mx.google.com; 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 p21si1134995eds.89.2021.07.12.04.08.25; Mon, 12 Jul 2021 04:08:26 -0700 (PDT) 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; 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 62D8268A943; Mon, 12 Jul 2021 14:08:03 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2F3F76898E4 for ; Mon, 12 Jul 2021 14:07:55 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id D29972404B2 for ; Mon, 12 Jul 2021 13:07:54 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id tgyWAgaz-Y2j for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id 6707B2404C8 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id A0D453A0B51; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:04 +0200 Message-Id: <20210712110709.15532-4-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/8] lavfi/vf_scale: remove the nb_slices option 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: Pcom58YP92wI Content-Length: 2811 It was intended for debugging only and has been superseded by the standalone tool for testing sliced scaling. --- libavfilter/vf_scale.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 71d7fa2890..39ab3a4b28 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -149,8 +149,6 @@ typedef struct ScaleContext { int force_original_aspect_ratio; int force_divisible_by; - int nb_slices; - int eval_mode; ///< expression evaluation mode } ScaleContext; @@ -794,17 +792,6 @@ scale: ret = scale_slice(scale, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0); if (ret >= 0) ret = scale_slice(scale, out, in, scale->isws[1], 0, link->h /2, 2, 1); - } else if (scale->nb_slices) { - int i, slice_h, slice_start, slice_end = 0; - const int nb_slices = FFMIN(scale->nb_slices, link->h); - for (i = 0; i < nb_slices; i++) { - slice_start = slice_end; - slice_end = (link->h * (i+1)) / nb_slices; - slice_h = slice_end - slice_start; - ret = scale_slice(scale, out, in, scale->sws, slice_start, slice_h, 1, 0); - if (ret < 0) - break; - } } else { ret = scale_slice(scale, out, in, scale->sws, 0, link->h, 1, 0); } @@ -936,7 +923,6 @@ static const AVOption scale_options[] = { { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS }, { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, - { "nb_slices", "set the number of slices (debug purpose only)", OFFSET(nb_slices), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" }, { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" }, { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" }, From patchwork Mon Jul 12 11:07:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28908 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2811954ybk; Mon, 12 Jul 2021 04:08:34 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx8xqVoLsnsTFop+8B5XfX2f8LSWoHDlf7qCt+d0BfUvbCNutOaMLnHWk9wxqR5OBxBTdXf X-Received: by 2002:a17:907:1b06:: with SMTP id mp6mr53893329ejc.188.1626088114038; Mon, 12 Jul 2021 04:08:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088114; cv=none; d=google.com; s=arc-20160816; b=aNBhUzqOsc4LsIphcB8fG02zBLBBNhifsDdPyAb03prulCzCsiapgSqqqTBUJm36UP 6pAy4ldj1KCiFw6neUGmEgxX7iAhlyBr8+XhEbnbXe8IAqF1gYw3kIx1pVfOYxBMkutU FnlN7RNrADid3PNKE3prABdIZLHqCAybLb+Su62OWsJjUXQl7okenIW/TFGxQYUFVdMQ cf0v/GUqYTn20g3Epb++GtsVcKHtcR1He9NUKn+ZDdNjf/SJZO/9RfVexJyyHWKcZcdc X/8UXKYWgVQqPoCZv0xZmsuMuTq0/tEHklVZkpHxOzi1j1ouDxAvzB+0fajkLRKtLJLz a0/g== 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:delivered-to; bh=AiOsH2ieJ8b7AGqyKz8kLLpihHsTA0ujohnATmmEarI=; b=aYQFBlgHCTKl6M3CeZXa0vIHOmFSypwaDBlyc28mpmfkEBzW64K0XSeMmt4WuGx41W LE3VQsPeJ8Lb44Io0Ijdc0Tva2TVs3/o65Ef7YrQ3wZwcz7UtoXd6v/NKQLm1wrr+cf5 kY2GwAQ5aUFB2kQx/LxH7Y4LAy7bjKhUm9Jfp+3r5yjUjo400Je4+k9D/N0+59dTj9F6 fcNEtFKG1g/vXl9BQ8ynVEdSmx0w4WKKE4LGjd5J4xlkFUvzDUA8bIXS/C/JO0MJtItP NUVFnUgQ5FDRbzcxjb59mh2602pp2T6ElBpdiQ8FA0depmjFZZUkn3npAHedjPdAmBc0 Kxow== ARC-Authentication-Results: i=1; mx.google.com; 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 ka15si16198958ejc.148.2021.07.12.04.08.31; Mon, 12 Jul 2021 04:08:34 -0700 (PDT) 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; 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 C06AD68A947; Mon, 12 Jul 2021 14:08:03 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8CCD86898E4 for ; Mon, 12 Jul 2021 14:07:55 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 3DE1B2404C8 for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id iGX94t1HBUVi for ; Mon, 12 Jul 2021 13:07:54 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id 68EC5240692 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id A4FC93A0BA4; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:05 +0200 Message-Id: <20210712110709.15532-5-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 4/8] lavu/slicethread: return ENOSYS rather than EINVAL in the dummy func 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: 4NAEKribuT4v Content-Length: 990 EINVAL is the wrong error code here, since the arguments passed to the function are valid. The error is that the function is not implemented in the build, which corresponds to ENOSYS. --- libavutil/slicethread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c index dfbe551ef2..fd2145040d 100644 --- a/libavutil/slicethread.c +++ b/libavutil/slicethread.c @@ -239,7 +239,7 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, int nb_threads) { *pctx = NULL; - return AVERROR(EINVAL); + return AVERROR(ENOSYS); } void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) From patchwork Mon Jul 12 11:07:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28898 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2812555ybk; Mon, 12 Jul 2021 04:09:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxXPVWwHJrWlODK9lfLxt7ZeVjPxf08cGcWGRld76NWpYcJhaOO8Lm7JFLzMCGO8jXYf/QY X-Received: by 2002:a05:6402:1d37:: with SMTP id dh23mr12708728edb.360.1626088164034; Mon, 12 Jul 2021 04:09:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088164; cv=none; d=google.com; s=arc-20160816; b=ZY5sU6z2eBoHNyfXW5rlWsLPEKGMXCzkKyTFSdtLd2WmFBJo0DAWquCNjGdQOLF9oF 3BGWhC5OQGoTQYBFHh/7pucHL4lPRx9BXN0g6SQ4LsiM8U9Y7fL661un119LFhQk46nT avqcWlZ/w1dmoSxrrsEp9go9Nq+JyVKDVg6goDAyR98FLOIA10WUVtKmp7GJe/yoIYlR ckTkb5/6fHixJK55mPMLhr5NPd9zz6nc165O/O0oh4BGVvD3RjdhlFjPUaUUY92/ZnwQ Va9Iz57vPpNmuy75cVSEGSjWTkJjJFjsa4cN10qp6EFn1yK1JIppBjlIUJaiLxlFVuSY t7iA== 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:delivered-to; bh=yZhbeNxsEahbLbmIAwMOQ59uShFcACgty/derPY0eqQ=; b=WXvjgiU1KiWTejYZqO+2BvqvnOZd9j3uUdELo8u/5jE0y7iAwayqhVW53tR5ry7BQi tL05iyPQHT0XX/8nnOABwPY3v/duCYSN6nzD0CbwVIe/2lQQyCDBeBEUe+IYgJL0IuXG lOy+eOo4hQxCBrnY/mfAMmaUfFTO0Bq2ZUOHZworhCKJT7H5LGEYBVQZFk0e0g9QuIG4 5szhEsDnGAZElH2Lp2pD44w33CyRPKtz2tbXSJAdT+4UGXKNoAuChe9/M244QUIn9bXy 8NmWattCPiV/z1cMQYX/rhcflpfxOZeVOsXGiBCYgqZsl3BE97hnQuE46dTi07jZyijf Q4Ow== ARC-Authentication-Results: i=1; mx.google.com; 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 ho44si15969492ejc.217.2021.07.12.04.09.23; Mon, 12 Jul 2021 04:09:24 -0700 (PDT) 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; 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 9EDD568A995; Mon, 12 Jul 2021 14:08:08 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1794D68A962 for ; Mon, 12 Jul 2021 14:08:00 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 25832240699 for ; Mon, 12 Jul 2021 13:07:57 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id h--8LbIAKXw3 for ; Mon, 12 Jul 2021 13:07:56 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id AF47E240698 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id A9BF83A0BBE; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:06 +0200 Message-Id: <20210712110709.15532-6-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 5/8] sws: add a new scaling API 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: thwXfvQ8zyZU Content-Length: 27254 --- libswscale/swscale.c | 263 ++++++++++++++++++++++++++-------- libswscale/swscale.h | 80 +++++++++++ libswscale/swscale_internal.h | 19 +++ libswscale/utils.c | 70 +++++++++ 4 files changed, 374 insertions(+), 58 deletions(-) diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 61dfcb4dff..8b32ce5a40 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -236,13 +236,16 @@ static void lumRangeFromJpeg16_c(int16_t *_dst, int width) av_log(c, AV_LOG_DEBUG, __VA_ARGS__) static int swscale(SwsContext *c, const uint8_t *src[], - int srcStride[], int srcSliceY, - int srcSliceH, uint8_t *dst[], int dstStride[]) + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[], + int dstSliceY, int dstSliceH) { + const int scale_dst = dstSliceY > 0 || dstSliceH < c->dstH; + /* load a few things into local vars to make the code more readable? * and faster */ const int dstW = c->dstW; - const int dstH = c->dstH; + int dstH = c->dstH; const enum AVPixelFormat dstFormat = c->dstFormat; const int flags = c->flags; @@ -331,10 +334,15 @@ static int swscale(SwsContext *c, const uint8_t *src[], } } - /* Note the user might start scaling the picture in the middle so this - * will not get executed. This is not really intended but works - * currently, so people might do it. */ - if (srcSliceY == 0) { + if (scale_dst) { + dstY = dstSliceY; + dstH = dstY + dstSliceH; + lastInLumBuf = -1; + lastInChrBuf = -1; + } else if (srcSliceY == 0) { + /* Note the user might start scaling the picture in the middle so this + * will not get executed. This is not really intended but works + * currently, so people might do it. */ dstY = 0; lastInLumBuf = -1; lastInChrBuf = -1; @@ -352,8 +360,8 @@ static int swscale(SwsContext *c, const uint8_t *src[], srcSliceY, srcSliceH, chrSrcSliceY, chrSrcSliceH, 1); ff_init_slice_from_src(vout_slice, (uint8_t**)dst, dstStride, c->dstW, - dstY, dstH, dstY >> c->chrDstVSubSample, - AV_CEIL_RSHIFT(dstH, c->chrDstVSubSample), 0); + dstY, dstSliceH, dstY >> c->chrDstVSubSample, + AV_CEIL_RSHIFT(dstSliceH, c->chrDstVSubSample), scale_dst); if (srcSliceY == 0) { hout_slice->plane[0].sliceY = lastInLumBuf + 1; hout_slice->plane[1].sliceY = lastInChrBuf + 1; @@ -373,7 +381,7 @@ static int swscale(SwsContext *c, const uint8_t *src[], // First line needed as input const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]); - const int firstLumSrcY2 = FFMAX(1 - vLumFilterSize, vLumFilterPos[FFMIN(dstY | ((1 << c->chrDstVSubSample) - 1), dstH - 1)]); + const int firstLumSrcY2 = FFMAX(1 - vLumFilterSize, vLumFilterPos[FFMIN(dstY | ((1 << c->chrDstVSubSample) - 1), c->dstH - 1)]); // First line needed as input const int firstChrSrcY = FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]); @@ -477,7 +485,7 @@ static int swscale(SwsContext *c, const uint8_t *src[], c->chrDither8 = ff_dither_8x8_128[chrDstY & 7]; c->lumDither8 = ff_dither_8x8_128[dstY & 7]; } - if (dstY >= dstH - 2) { + if (dstY >= c->dstH - 2) { /* hmm looks like we can't use MMX here without overwriting * this array's tail */ ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX, @@ -491,21 +499,22 @@ static int swscale(SwsContext *c, const uint8_t *src[], desc[i].process(c, &desc[i], dstY, 1); } if (isPlanar(dstFormat) && isALPHA(dstFormat) && !needAlpha) { + int offset = lastDstY - dstSliceY; int length = dstW; int height = dstY - lastDstY; if (is16BPS(dstFormat) || isNBPS(dstFormat)) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat); - fillPlane16(dst[3], dstStride[3], length, height, lastDstY, + fillPlane16(dst[3], dstStride[3], length, height, offset, 1, desc->comp[3].depth, isBE(dstFormat)); } else if (is32BPS(dstFormat)) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat); - fillPlane32(dst[3], dstStride[3], length, height, lastDstY, + fillPlane32(dst[3], dstStride[3], length, height, offset, 1, desc->comp[3].depth, isBE(dstFormat), desc->flags & AV_PIX_FMT_FLAG_FLOAT); } else - fillPlane(dst[3], dstStride[3], length, height, lastDstY, 255); + fillPlane(dst[3], dstStride[3], length, height, offset, 255); } #if HAVE_MMXEXT_INLINE @@ -809,33 +818,42 @@ static void update_palette(SwsContext *c, const uint32_t *pal) } } +static int scale_internal(SwsContext *c, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH); + static int scale_gamma(SwsContext *c, const uint8_t * const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, - uint8_t * const dst[], const int dstStride[]) + uint8_t * const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) { - int ret = sws_scale(c->cascaded_context[0], - srcSlice, srcStride, srcSliceY, srcSliceH, - c->cascaded_tmp, c->cascaded_tmpStride); + int ret = scale_internal(c->cascaded_context[0], + srcSlice, srcStride, srcSliceY, srcSliceH, + c->cascaded_tmp, c->cascaded_tmpStride, 0, c->srcH); if (ret < 0) return ret; if (c->cascaded_context[2]) - ret = sws_scale(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, - c->cascaded_tmpStride, srcSliceY, srcSliceH, c->cascaded1_tmp, - c->cascaded1_tmpStride); + ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, + c->cascaded_tmpStride, srcSliceY, srcSliceH, + c->cascaded1_tmp, c->cascaded1_tmpStride, 0, c->dstH); else - ret = sws_scale(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, - c->cascaded_tmpStride, srcSliceY, srcSliceH, dst, dstStride); + ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, + c->cascaded_tmpStride, srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); if (ret < 0) return ret; if (c->cascaded_context[2]) { - ret = sws_scale(c->cascaded_context[2], (const uint8_t * const *)c->cascaded1_tmp, - c->cascaded1_tmpStride, c->cascaded_context[1]->dstY - ret, - c->cascaded_context[1]->dstY, dst, dstStride); + ret = scale_internal(c->cascaded_context[2], (const uint8_t * const *)c->cascaded1_tmp, + c->cascaded1_tmpStride, c->cascaded_context[1]->dstY - ret, + c->cascaded_context[1]->dstY, + dstSlice, dstStride, dstSliceY, dstSliceH); } return ret; } @@ -843,56 +861,64 @@ static int scale_gamma(SwsContext *c, static int scale_cascaded(SwsContext *c, const uint8_t * const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, - uint8_t * const dst[], const int dstStride[]) + uint8_t * const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) { - int ret = sws_scale(c->cascaded_context[0], - srcSlice, srcStride, srcSliceY, srcSliceH, - c->cascaded_tmp, c->cascaded_tmpStride); + int ret = scale_internal(c->cascaded_context[0], + srcSlice, srcStride, srcSliceY, srcSliceH, + c->cascaded_tmp, c->cascaded_tmpStride, + 0, c->cascaded_context[0]->dstH); if (ret < 0) return ret; - ret = sws_scale(c->cascaded_context[1], - (const uint8_t * const * )c->cascaded_tmp, c->cascaded_tmpStride, - 0, c->cascaded_context[0]->dstH, dst, dstStride); + ret = scale_internal(c->cascaded_context[1], + (const uint8_t * const * )c->cascaded_tmp, c->cascaded_tmpStride, + 0, c->cascaded_context[0]->dstH, + dstSlice, dstStride, dstSliceY, dstSliceH); return ret; } -/** - * swscale wrapper, so we don't need to export the SwsContext. - * Assumes planar YUV to be in YUV order instead of YVU. - */ -int attribute_align_arg sws_scale(struct SwsContext *c, - const uint8_t * const srcSlice[], - const int srcStride[], int srcSliceY, - int srcSliceH, uint8_t *const dst[], - const int dstStride[]) +static int scale_internal(SwsContext *c, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) { - const int frame_start = !c->sliceDir; + const int scale_dst = dstSliceY > 0 || dstSliceH < c->dstH; + const int frame_start = scale_dst || !c->sliceDir; int i, ret; const uint8_t *src2[4]; uint8_t *dst2[4]; - int macro_height = isBayer(c->srcFormat) ? 2 : (1 << c->chrSrcVSubSample); + int macro_height_src = isBayer(c->srcFormat) ? 2 : (1 << c->chrSrcVSubSample); + int macro_height_dst = isBayer(c->dstFormat) ? 2 : (1 << c->chrDstVSubSample); // copy strides, so they can safely be modified int srcStride2[4]; int dstStride2[4]; int srcSliceY_internal = srcSliceY; - if (!srcStride || !dstStride || !dst || !srcSlice) { + if (!srcStride || !dstStride || !dstSlice || !srcSlice) { av_log(c, AV_LOG_ERROR, "One of the input parameters to sws_scale() is NULL, please check the calling code\n"); return AVERROR(EINVAL); } - if ((srcSliceY & (macro_height-1)) || - ((srcSliceH& (macro_height-1)) && srcSliceY + srcSliceH != c->srcH) || + if ((srcSliceY & (macro_height_src - 1)) || + ((srcSliceH & (macro_height_src - 1)) && srcSliceY + srcSliceH != c->srcH) || srcSliceY + srcSliceH > c->srcH) { av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", srcSliceY, srcSliceH); return AVERROR(EINVAL); } + if ((dstSliceY & (macro_height_dst - 1)) || + ((dstSliceH & (macro_height_dst - 1)) && dstSliceY + dstSliceH != c->dstH) || + dstSliceY + dstSliceH > c->dstH) { + av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", dstSliceY, dstSliceH); + return AVERROR(EINVAL); + } + if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) { av_log(c, AV_LOG_ERROR, "bad src image pointers\n"); return AVERROR(EINVAL); } - if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) { + if (!check_image_pointers((const uint8_t* const*)dstSlice, c->dstFormat, dstStride)) { av_log(c, AV_LOG_ERROR, "bad dst image pointers\n"); return AVERROR(EINVAL); } @@ -902,10 +928,12 @@ int attribute_align_arg sws_scale(struct SwsContext *c, return 0; if (c->gamma_flag && c->cascaded_context[0]) - return scale_gamma(c, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride); + return scale_gamma(c, srcSlice, srcStride, srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); if (c->cascaded_context[0] && srcSliceY == 0 && srcSliceH == c->cascaded_context[0]->srcH) - return scale_cascaded(c, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride); + return scale_cascaded(c, srcSlice, srcStride, srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); if (!srcSliceY && (c->flags & SWS_BITEXACT) && c->dither == SWS_DITHER_ED && c->dither_error[0]) for (i = 0; i < 4; i++) @@ -915,18 +943,19 @@ int attribute_align_arg sws_scale(struct SwsContext *c, update_palette(c, (const uint32_t *)srcSlice[1]); memcpy(src2, srcSlice, sizeof(src2)); - memcpy(dst2, dst, sizeof(dst2)); + memcpy(dst2, dstSlice, sizeof(dst2)); memcpy(srcStride2, srcStride, sizeof(srcStride2)); memcpy(dstStride2, dstStride, sizeof(dstStride2)); - if (frame_start) { + if (frame_start && !scale_dst) { if (srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) { av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n"); return AVERROR(EINVAL); } c->sliceDir = (srcSliceY == 0) ? 1 : -1; - } + } else if (scale_dst) + c->sliceDir = 1; if (c->src0Alpha && !c->dst0Alpha && isALPHA(c->dstFormat)) { uint8_t *base; @@ -985,11 +1014,28 @@ int attribute_align_arg sws_scale(struct SwsContext *c, reset_ptr(src2, c->srcFormat); reset_ptr((void*)dst2, c->dstFormat); - if (c->convert_unscaled) - ret = c->convert_unscaled(c, src2, srcStride2, srcSliceY_internal, srcSliceH, + if (c->convert_unscaled) { + int offset = srcSliceY_internal; + int slice_h = srcSliceH; + + // for dst slice scaling, offset the src pointers to match the dst slice + if (scale_dst) { + av_assert0(offset == 0); + for (i = 0; i < 4 && src2[i]; i++) { + if (!src2[i] || (i > 0 && usePal(c->srcFormat))) + break; + src2[i] += (dstSliceY >> ((i == 1 || i == 2) ? c->chrSrcVSubSample : 0)) * srcStride2[i]; + } + offset = 0; + slice_h = dstSliceH; + } + + ret = c->convert_unscaled(c, src2, srcStride2, offset, slice_h, dst2, dstStride2); - else - ret = swscale(c, src2, srcStride2, srcSliceY_internal, srcSliceH, dst2, dstStride2); + } else { + ret = swscale(c, src2, srcStride2, srcSliceY_internal, srcSliceH, + dst2, dstStride2, dstSliceY, dstSliceH); + } if (c->dstXYZ && !(c->srcXYZ && c->srcW==c->dstW && c->srcH==c->dstH)) { int dstY = c->dstY ? c->dstY : srcSliceY + srcSliceH; @@ -1003,8 +1049,109 @@ int attribute_align_arg sws_scale(struct SwsContext *c, } /* reset slice direction at end of frame */ - if (srcSliceY_internal + srcSliceH == c->srcH) + if ((srcSliceY_internal + srcSliceH == c->srcH) || scale_dst) c->sliceDir = 0; return ret; } + +void sws_frame_end(struct SwsContext *c) +{ + av_frame_unref(c->frame_src); + av_frame_unref(c->frame_dst); + c->src_ranges.nb_ranges = 0; +} + +int sws_frame_start(struct SwsContext *c, AVFrame *dst, const AVFrame *src) +{ + int ret, allocated = 0; + + ret = av_frame_ref(c->frame_src, src); + if (ret < 0) + return ret; + + if (!dst->buf[0]) { + dst->width = c->dstW; + dst->height = c->dstH; + dst->format = c->dstFormat; + + ret = av_frame_get_buffer(dst, 0); + if (ret < 0) + return ret; + allocated = 1; + } + + ret = av_frame_ref(c->frame_dst, dst); + if (ret < 0) { + if (allocated) + av_frame_unref(dst); + + return ret; + } + + return 0; +} + +int sws_send_slice(struct SwsContext *c, unsigned int slice_start, + unsigned int slice_height) +{ + int ret; + + ret = ff_range_add(&c->src_ranges, slice_start, slice_height); + if (ret < 0) + return ret; + + return 0; +} + +int sws_receive_slice(struct SwsContext *c, unsigned int slice_start, + unsigned int slice_height) +{ + uint8_t *dst[4]; + + /* wait until complete input has been received */ + if (!(c->src_ranges.nb_ranges == 1 && + c->src_ranges.ranges[0].start == 0 && + c->src_ranges.ranges[0].len == c->srcH)) + return AVERROR(EAGAIN); + + for (int i = 0; i < FF_ARRAY_ELEMS(dst) && c->frame_dst->data[i]; i++) { + dst[i] = c->frame_dst->data[i] + + c->frame_dst->linesize[i] * (slice_start >> c->chrDstVSubSample); + } + + return scale_internal(c, (const uint8_t * const *)c->frame_src->data, + c->frame_src->linesize, 0, c->srcH, + dst, c->frame_dst->linesize, slice_start, slice_height); +} + +int sws_scale_frame(struct SwsContext *c, AVFrame *dst, const AVFrame *src) +{ + int ret; + + ret = sws_frame_start(c, dst, src); + if (ret < 0) + return ret; + + ret = sws_send_slice(c, 0, src->height); + if (ret >= 0) + ret = sws_receive_slice(c, 0, dst->height); + + sws_frame_end(c); + + return ret; +} + +/** + * swscale wrapper, so we don't need to export the SwsContext. + * Assumes planar YUV to be in YUV order instead of YVU. + */ +int attribute_align_arg sws_scale(struct SwsContext *c, + const uint8_t * const srcSlice[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dst[], + const int dstStride[]) +{ + return scale_internal(c, srcSlice, srcStride, srcSliceY, srcSliceH, + dst, dstStride, 0, c->dstH); +} diff --git a/libswscale/swscale.h b/libswscale/swscale.h index 50d6d46553..41eacd2dea 100644 --- a/libswscale/swscale.h +++ b/libswscale/swscale.h @@ -30,6 +30,7 @@ #include #include "libavutil/avutil.h" +#include "libavutil/frame.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" #include "version.h" @@ -218,6 +219,85 @@ int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]); +/** + * Scale source data from src and write the output to dst. + * + * This is merely a convenience wrapper around + * - sws_frame_start() + * - sws_send_slice(0, src->height) + * - sws_receive_slice(0, dst->height) + * - sws_frame_end() + * + * @param dst The destination frame. See documentation for sws_frame_start() for + * more details. + * @param src The source frame. + * + * @return 0 on success, a negative AVERROR code on failure + */ +int sws_scale_frame(struct SwsContext *c, AVFrame *dst, const AVFrame *src); + +/** + * Initialize the scaling process for a given pair of source/destination frames. + * Must be called before any calls to sws_send_slice() and sws_receive_slice(). + * + * This function will retain references to src and dst. + * + * @param dst The destination frame. + * + * The data buffers may either be already allocated by the caller or + * left clear, in which case they will be allocated by the scaler. + * The latter may have performance advantages - e.g. in certain cases + * some output planes may be references to input planes, rather than + * copies. + * + * Output data will be written into this frame in successful + * sws_receive_slice() calls. + * @param src The source frame. The data buffers must be allocated, but the + * frame data does not have to be ready at this point. Data + * availability is then signalled by sws_send_slice(). + * @return 0 on success, a negative AVERROR code on failure + * + * @see sws_frame_end() + */ +int sws_frame_start(struct SwsContext *c, AVFrame *dst, const AVFrame *src); + +/** + * Finish the scaling process for a pair of source/destination frames previously + * submitted with sws_frame_start(). Must be called after all sws_send_slice() + * and sws_receive_slice() calls are done, before any new sws_frame_start() + * calls. + */ +void sws_frame_end(struct SwsContext *c); + +/** + * Indicate that a horizontal slice of input data is available in the source + * frame previously provided to sws_frame_start(). The slices may be provided in + * any order, but may not overlap. For vertically subsampled pixel formats, the + * slices must be aligned according to subsampling. + * + * @param slice_start first row of the slice + * @param slice_height number of rows in the slice + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int sws_send_slice(struct SwsContext *c, unsigned int slice_start, + unsigned int slice_height); + +/** + * Request a horizontal slice of the output data to be written into the frame + * previously provided to sws_frame_start(). + * + * @param slice_start first row of the slice + * @param slice_height number of rows in the slice + * + * @return 0 if the data was successfully written into the output + * AVERROR(EAGAIN) if more input data needs to be provided before the + * output can be produced + * another negative AVERROR code on other kinds of scaling failure + */ +int sws_receive_slice(struct SwsContext *c, unsigned int slice_start, + unsigned int slice_height); + /** * @param dstRange flag indicating the while-black range of the output (1=jpeg / 0=mpeg) * @param srcRange flag indicating the while-black range of the input (1=jpeg / 0=mpeg) diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index 673407636a..c1098d6026 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -27,6 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/avutil.h" #include "libavutil/common.h" +#include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/mem_internal.h" @@ -80,6 +81,19 @@ typedef enum SwsAlphaBlend { SWS_ALPHA_BLEND_NB, } SwsAlphaBlend; +typedef struct Range { + unsigned int start; + unsigned int len; +} Range; + +typedef struct RangeList { + Range *ranges; + unsigned int nb_ranges; + int ranges_allocated; +} RangeList; + +int ff_range_add(RangeList *r, unsigned int start, unsigned int len); + typedef int (*SwsFunc)(struct SwsContext *context, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]); @@ -313,6 +327,11 @@ typedef struct SwsContext { int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top). double param[2]; ///< Input parameters for scaling algorithms that need them. + AVFrame *frame_src; + AVFrame *frame_dst; + + RangeList src_ranges; + /* The cascaded_* fields allow spliting a scaler task into multiple * sequential steps, this is for example used to limit the maximum * downscaling factor that needs to be supported in one scaler. diff --git a/libswscale/utils.c b/libswscale/utils.c index 176fc6fd63..dbb907d761 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -1761,6 +1761,11 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, if (!FF_ALLOCZ_TYPED_ARRAY(c->dither_error[i], c->dstW + 2)) goto nomem; + c->frame_src = av_frame_alloc(); + c->frame_dst = av_frame_alloc(); + if (!c->frame_src || !c->frame_dst) + goto nomem; + c->needAlpha = (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat) && isALPHA(c->dstFormat)) ? 1 : 0; // 64 / c->scalingBpp is the same as 16 / sizeof(scaling_intermediate) @@ -2250,6 +2255,11 @@ void sws_freeContext(SwsContext *c) for (i = 0; i < 4; i++) av_freep(&c->dither_error[i]); + av_frame_free(&c->frame_src); + av_frame_free(&c->frame_dst); + + av_freep(&c->src_ranges.ranges); + av_freep(&c->vLumFilter); av_freep(&c->vChrFilter); av_freep(&c->hLumFilter); @@ -2364,3 +2374,63 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW, } return context; } + +int ff_range_add(RangeList *rl, unsigned int start, unsigned int len) +{ + Range *tmp; + unsigned int idx; + + /* find the first existing range after the new one */ + for (idx = 0; idx < rl->nb_ranges; idx++) + if (rl->ranges[idx].start > start) + break; + + /* check for overlap */ + if (idx > 0) { + Range *prev = &rl->ranges[idx - 1]; + if (prev->start + prev->len > start) + return AVERROR(EINVAL); + } + if (idx < rl->nb_ranges) { + Range *next = &rl->ranges[idx]; + if (start + len > next->start) + return AVERROR(EINVAL); + } + + tmp = av_fast_realloc(rl->ranges, &rl->ranges_allocated, + (rl->nb_ranges + 1) * sizeof(*rl->ranges)); + if (!tmp) + return AVERROR(ENOMEM); + rl->ranges = tmp; + + memmove(rl->ranges + idx + 1, rl->ranges + idx, + sizeof(*rl->ranges) * (rl->nb_ranges - idx)); + rl->ranges[idx].start = start; + rl->ranges[idx].len = len; + rl->nb_ranges++; + + /* merge ranges */ + if (idx > 0) { + Range *prev = &rl->ranges[idx - 1]; + Range *cur = &rl->ranges[idx]; + if (prev->start + prev->len == cur->start) { + prev->len += cur->len; + memmove(rl->ranges + idx - 1, rl->ranges + idx, + sizeof(*rl->ranges) * (rl->nb_ranges - idx)); + rl->nb_ranges--; + idx--; + } + } + if (idx < rl->nb_ranges - 1) { + Range *cur = &rl->ranges[idx]; + Range *next = &rl->ranges[idx + 1]; + if (cur->start + cur->len == next->start) { + cur->len += next->len; + memmove(rl->ranges + idx, rl->ranges + idx + 1, + sizeof(*rl->ranges) * (rl->nb_ranges - idx - 1)); + rl->nb_ranges--; + } + } + + return 0; +} From patchwork Mon Jul 12 11:07:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28911 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2812337ybk; Mon, 12 Jul 2021 04:09:07 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzfDpw5/4xpAgY2fRbnRqIxr4p6wNKsf64gWTTKyPvlxSIWkUFwijkMaylF8Y6JSaRF6h4p X-Received: by 2002:aa7:da4f:: with SMTP id w15mr4357735eds.266.1626088147285; Mon, 12 Jul 2021 04:09:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088147; cv=none; d=google.com; s=arc-20160816; b=vLXhhwu6YHPRDlOZHvnYPlAZja9B8SHVhspXnUhP1o6KsEEoy/7LgeNezIfU2zrsYy YoK+82WYloajkWv/kpP05xTHnUuvesmfEF0LNdXyuhLVAcNDPy8xRlm6vhaQZJQrRrqU zI0v5aFnF0gro2+qureQk5kIYF5x5HBJAA7KLZ6xEMLCdoSV/KJA7DY0n/RazH6N6bmV OHYJY/ECgNDQHRkZNQob+xfAc1cOOs1Zix488sdeex76Sg6cqvC6tE7vRf624zA8OLQ2 sO0MdgwuCoLcS3ayRwlMY503WGPQlAESEpe/M4xDjA2Qp6PkEplPMFBCyabIzGfw5X8M WfWw== 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:delivered-to; bh=fssuzNxo40bhBWXSNY8/4MCbglTivaUZHwmvzrO0+OU=; b=1Eos8tYarrhF3IvcE6xSTa9G+EUqPlVfpmKfP9GG+9Lo0QHVe4CgBW4FTzCzNHn+zS 4jTi/ZoPD63dLaPM8PoAUcaHOUOjQ7abI6DnZc51aEoO4n8cC/aAyK6v7asLeGm89IzE WKmXhJ8dHl6+IS0oYiaI8u9jfJ/iDYxjfpKZDVjv1bTCdEL1N6/qnHopGo5Pwa2pRGBa phLEVY8alTJNkzJ2BRLTsBKhFrGHggMpBWOgYn5nXqipdepPYJTrrHDdDxE/xwDbsIXl TG6Dk/D51PGfzWDTpm/Xu1DgB8EWZSqoA/QMdxPnuyN1Umz7p1JYdcOuyEvDrjHSZ0CS J7ZA== ARC-Authentication-Results: i=1; mx.google.com; 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 eb9si16559157ejc.720.2021.07.12.04.09.07; Mon, 12 Jul 2021 04:09:07 -0700 (PDT) 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; 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 4CA3968A980; Mon, 12 Jul 2021 14:08:07 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 67CD568A94D for ; Mon, 12 Jul 2021 14:07:59 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 0F25D240695 for ; Mon, 12 Jul 2021 13:07:56 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id cIQCcSUaxaqa for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id AF0F9240697 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id ADEDB3A0BCA; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:07 +0200 Message-Id: <20210712110709.15532-7-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 6/8] lavfi/vf_scale: convert to the frame-based sws API 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: 9UzOr+dL96ju Content-Length: 3551 --- libavfilter/vf_scale.c | 73 ++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 39ab3a4b28..cdff3ab7ed 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -620,29 +620,54 @@ static int request_frame_ref(AVFilterLink *outlink) return ff_request_frame(outlink->src->inputs[1]); } -static int scale_slice(ScaleContext *scale, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field) +static void frame_offset(AVFrame *frame, int dir, int is_pal) { - const uint8_t *in[4]; - uint8_t *out[4]; - int in_stride[4],out_stride[4]; - int i; - - for (i=0; i<4; i++) { - int vsub= ((i+1)&2) ? scale->vsub : 0; - ptrdiff_t in_offset = ((y>>vsub)+field) * cur_pic->linesize[i]; - ptrdiff_t out_offset = field * out_buf->linesize[i]; - in_stride[i] = cur_pic->linesize[i] * mul; - out_stride[i] = out_buf->linesize[i] * mul; - in[i] = FF_PTR_ADD(cur_pic->data[i], in_offset); - out[i] = FF_PTR_ADD(out_buf->data[i], out_offset); - } - if (scale->input_is_pal) - in[1] = cur_pic->data[1]; - if (scale->output_is_pal) - out[1] = out_buf->data[1]; + for (int i = 0; i < 4 && frame->data[i]; i++) { + if (i == 1 && is_pal) + break; + frame->data[i] += frame->linesize[i] * dir; + } +} + +static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src, + int field) +{ + int orig_h_src = src->height; + int orig_h_dst = dst->height; + int ret; + + // offset the data pointers for the bottom field + if (field) { + frame_offset(src, 1, scale->input_is_pal); + frame_offset(dst, 1, scale->output_is_pal); + } + + // take every second line + for (int i = 0; i < 4; i++) { + src->linesize[i] *= 2; + dst->linesize[i] *= 2; + } + src->height /= 2; + dst->height /= 2; - return sws_scale(sws, in, in_stride, y/mul, h, - out,out_stride); + ret = sws_scale_frame(scale->isws[field], dst, src); + if (ret < 0) + return ret; + + // undo the changes we made above + for (int i = 0; i < 4; i++) { + src->linesize[i] /= 2; + dst->linesize[i] /= 2; + } + src->height = orig_h_src; + dst->height = orig_h_dst; + + if (field) { + frame_offset(src, -1, scale->input_is_pal); + frame_offset(dst, -1, scale->output_is_pal); + } + + return 0; } static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) @@ -789,11 +814,11 @@ scale: INT_MAX); if (scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)) { - ret = scale_slice(scale, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0); + ret = scale_field(scale, out, in, 0); if (ret >= 0) - ret = scale_slice(scale, out, in, scale->isws[1], 0, link->h /2, 2, 1); + ret = scale_field(scale, out, in, 1); } else { - ret = scale_slice(scale, out, in, scale->sws, 0, link->h, 1, 0); + ret = sws_scale_frame(scale->sws, out, in); } av_frame_free(&in); From patchwork Mon Jul 12 11:07:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28902 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2812180ybk; Mon, 12 Jul 2021 04:08:55 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwai3GHE3bh+yGXdwUs23aLiiDdGT1VMru3G6dR+nL7KwdxPRvLMNAfM+OE3kN7iqz4ysKO X-Received: by 2002:a17:906:498b:: with SMTP id p11mr52577799eju.295.1626088134868; Mon, 12 Jul 2021 04:08:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088134; cv=none; d=google.com; s=arc-20160816; b=b3kIlfO9aooS4MaNILoR3u7N5/wHpk9Hp+wyA3GKy4BgzoQJIgPWgA3PYzZ0x0i1Oa 1MQgVQ7hIA78RjpUuy6Z99YN9e81eGqo8mghGk0C2Zrr3pzihMXjOOC634R47h/P+CHX zty7G1pHHIbiH7AUbfMSlYDjvbByDgx/2wF2yCsuqWeHoo/o1EQ4AXLhLWN/SZghELCe 2RLFj6TOAN8cn8iET2lUv7FnWl4bJa5XyKzZ6O3S3PiAZ8y1kXjixpkV9TIXrY3zPYuG GwnT0M76LajZxXQTJ5Xg1gFvf5GKnMf2g6ELOX8rTwcB79VywDNUpNqq/ccyni2Q/IHT bu/w== 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:delivered-to; bh=PYm/6aDud0pjwuzTHr5bFS0dhIK5qqrHMF0QSWXe3/M=; b=TBaNrq9IyaoYHHmrXG2DukvZH3zM28KQDWfDyMZBxvb9Q/NdBHF8Mtevis1lZ+Mgzz SbYgu2ome0wWFfux97EKy9DUu99b7xZJgLUzP6kQji/6W6feCQRd33u3UuDGhtbBcTgO l1B0bC1q/O4GLkUCW2/PohymrKKiqBX9nKiGe357oXpYcwav1zmAGhCYYfP/s0jNFe49 6i/NitKksQvvNUUnNUkx+LHwqSntbj6e2dHBs1wdMt55uagcnhbnEtUFCWv/4rKLoUBI EiKWSdpB6ZYlP6OjN0BLBFQxHEUoE6tbKASC7tmdKdJZ11gelPX38Cac0JH+d6tLe86B fl+Q== ARC-Authentication-Results: i=1; mx.google.com; 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 m22si2577056ejj.666.2021.07.12.04.08.54; Mon, 12 Jul 2021 04:08:54 -0700 (PDT) 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; 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 C644D68A970; Mon, 12 Jul 2021 14:08:05 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 61E1C68A94C for ; Mon, 12 Jul 2021 14:07:59 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id D0B1A240694 for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id DX0Edz35djtq for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id AD07C240695 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id B2C993A0C14; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:08 +0200 Message-Id: <20210712110709.15532-8-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 7/8] sws: implement slice threading 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: DnDpdn6g+DwD Content-Length: 10460 --- libswscale/options.c | 3 ++ libswscale/swscale.c | 56 ++++++++++++++++++++++++ libswscale/swscale_internal.h | 14 ++++++ libswscale/utils.c | 82 +++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/libswscale/options.c b/libswscale/options.c index 7eb2752543..4b71a23e37 100644 --- a/libswscale/options.c +++ b/libswscale/options.c @@ -81,6 +81,9 @@ static const AVOption swscale_options[] = { { "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM},INT_MIN, INT_MAX, VE, "alphablend" }, { "checkerboard", "blend onto a checkerboard", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_CHECKERBOARD},INT_MIN, INT_MAX, VE, "alphablend" }, + { "threads", "number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, VE, "threads" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = VE, "threads" }, + { NULL } }; diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 8b32ce5a40..ee57684675 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1115,6 +1115,27 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start, c->src_ranges.ranges[0].len == c->srcH)) return AVERROR(EAGAIN); + if (c->slicethread) { + int nb_jobs = c->slice_ctx[0]->dither == SWS_DITHER_ED ? 1 : c->nb_slice_ctx; + int ret = 0; + + c->dst_slice_start = slice_start; + c->dst_slice_height = slice_height; + + avpriv_slicethread_execute(c->slicethread, nb_jobs, 0); + + for (int i = 0; i < c->nb_slice_ctx; i++) { + if (c->slice_err[i] < 0) { + ret = c->slice_err[i]; + break; + } + } + + memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err)); + + return ret; + } + for (int i = 0; i < FF_ARRAY_ELEMS(dst) && c->frame_dst->data[i]; i++) { dst[i] = c->frame_dst->data[i] + c->frame_dst->linesize[i] * (slice_start >> c->chrDstVSubSample); @@ -1152,6 +1173,41 @@ int attribute_align_arg sws_scale(struct SwsContext *c, int srcSliceH, uint8_t *const dst[], const int dstStride[]) { + if (c->nb_slice_ctx) + c = c->slice_ctx[0]; + return scale_internal(c, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride, 0, c->dstH); } + +void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, + int nb_jobs, int nb_threads) +{ + SwsContext *parent = priv; + SwsContext *c = parent->slice_ctx[threadnr]; + + const int slice_height = FFALIGN(FFMAX((parent->dst_slice_height + nb_jobs - 1) / nb_jobs, 1), + 1 << c->chrDstVSubSample); + const int slice_start = jobnr * slice_height; + const int slice_end = FFMIN((jobnr + 1) * slice_height, parent->dst_slice_height); + int err = 0; + + if (slice_end > slice_start) { + uint8_t *dst[4] = { NULL }; + + for (int i = 0; i < FF_ARRAY_ELEMS(dst) && parent->frame_dst->data[i]; i++) { + const int vshift = (i == 1 || i == 2) ? c->chrDstVSubSample : 0; + const ptrdiff_t offset = parent->frame_dst->linesize[i] * + ((slice_start + parent->dst_slice_start) >> vshift); + + dst[i] = parent->frame_dst->data[i] + offset; + } + + err = scale_internal(c, (const uint8_t * const *)parent->frame_src->data, + parent->frame_src->linesize, 0, c->srcH, + dst, parent->frame_dst->linesize, + parent->dst_slice_start + slice_start, slice_end - slice_start); + } + + parent->slice_err[threadnr] = err; +} diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index c1098d6026..6ca44b710e 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -33,6 +33,7 @@ #include "libavutil/mem_internal.h" #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" +#include "libavutil/slicethread.h" #include "libavutil/ppc/util_altivec.h" #define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long @@ -300,6 +301,15 @@ typedef struct SwsContext { */ const AVClass *av_class; + AVSliceThread *slicethread; + struct SwsContext **slice_ctx; + int *slice_err; + int nb_slice_ctx; + + // values passed to current sws_receive_slice() call + unsigned int dst_slice_start; + unsigned int dst_slice_height; + /** * Note that src, dst, srcStride, dstStride will be copied in the * sws_scale() wrapper so they can be freely modified here. @@ -325,6 +335,7 @@ typedef struct SwsContext { int chrDstVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination image. int vChrDrop; ///< Binary logarithm of extra vertical subsampling factor in source image chroma planes specified by user. int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top). + int nb_threads; ///< Number of threads used for scaling double param[2]; ///< Input parameters for scaling algorithms that need them. AVFrame *frame_src; @@ -1080,6 +1091,9 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2, yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx); +void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, + int nb_jobs, int nb_threads); + //number of extra lines to process #define MAX_LINES_AHEAD 4 diff --git a/libswscale/utils.c b/libswscale/utils.c index dbb907d761..fe4dcf8ace 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -49,6 +49,7 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/slicethread.h" #include "libavutil/thread.h" #include "libavutil/aarch64/cpu.h" #include "libavutil/ppc/cpu.h" @@ -871,6 +872,18 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], const AVPixFmtDescriptor *desc_src; int need_reinit = 0; + if (c->nb_slice_ctx) { + for (int i = 0; i < c->nb_slice_ctx; i++) { + int ret = sws_setColorspaceDetails(c->slice_ctx[i], inv_table, + srcRange, table, dstRange, + brightness, contrast, saturation); + if (ret < 0) + return ret; + } + + return 0; + } + handle_formats(c); desc_dst = av_pix_fmt_desc_get(c->dstFormat); desc_src = av_pix_fmt_desc_get(c->srcFormat); @@ -1005,6 +1018,12 @@ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, if (!c ) return -1; + if (c->nb_slice_ctx) { + return sws_getColorspaceDetails(c->slice_ctx[0], inv_table, srcRange, + table, dstRange, brightness, contrast, + saturation); + } + *inv_table = c->srcColorspaceTable; *table = c->dstColorspaceTable; *srcRange = range_override_needed(c->srcFormat) ? 1 : c->srcRange; @@ -1170,6 +1189,55 @@ static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt) } } +static int context_init_threaded(SwsContext *c, + SwsFilter *src_filter, SwsFilter *dst_filter) +{ + int ret; + + ret = avpriv_slicethread_create(&c->slicethread, (void*)c, + ff_sws_slice_worker, NULL, c->nb_threads); + if (ret == AVERROR(ENOSYS)) { + c->nb_threads = 1; + return 0; + } else if (ret < 0) + return ret; + + c->nb_threads = ret; + + c->slice_ctx = av_mallocz_array(c->nb_threads, sizeof(*c->slice_ctx)); + c->slice_err = av_mallocz_array(c->nb_threads, sizeof(*c->slice_err)); + if (!c->slice_ctx || !c->slice_err) + return AVERROR(ENOMEM); + + for (int i = 0; i < c->nb_threads; i++) { + c->slice_ctx[i] = sws_alloc_context(); + if (!c->slice_ctx[i]) + return AVERROR(ENOMEM); + + ret = av_opt_copy((void*)c->slice_ctx[i], (void*)c); + if (ret < 0) + return ret; + + c->slice_ctx[i]->nb_threads = 1; + + ret = sws_init_context(c->slice_ctx[i], src_filter, dst_filter); + if (ret < 0) + return ret; + + c->nb_slice_ctx++; + + if (c->slice_ctx[i]->dither == SWS_DITHER_ED) + break; + } + + c->frame_src = av_frame_alloc(); + c->frame_dst = av_frame_alloc(); + if (!c->frame_src || !c->frame_dst) + return AVERROR(ENOMEM); + + return 0; +} + av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter) { @@ -1192,6 +1260,13 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, static const float float_mult = 1.0f / 255.0f; static AVOnce rgb2rgb_once = AV_ONCE_INIT; + if (c->nb_threads != 1) { + ret = context_init_threaded(c, srcFilter, dstFilter); + if (ret < 0 || c->nb_threads > 1) + return ret; + // threading disabled in this build, init as single-threaded + } + cpu_flags = av_get_cpu_flags(); flags = c->flags; emms_c(); @@ -2252,6 +2327,13 @@ void sws_freeContext(SwsContext *c) if (!c) return; + for (i = 0; i < c->nb_slice_ctx; i++) + sws_freeContext(c->slice_ctx[i]); + av_freep(&c->slice_ctx); + av_freep(&c->slice_err); + + avpriv_slicethread_free(&c->slicethread); + for (i = 0; i < 4; i++) av_freep(&c->dither_error[i]); From patchwork Mon Jul 12 11:07:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 28906 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:bbc9:0:0:0:0:0 with SMTP id c9csp2812406ybk; Mon, 12 Jul 2021 04:09:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy+P6o2RbY3KG7o+nLWwrTtaDEVltgipX7HPGqjzPCm3KsRgz5lAgADQsCuhCRzJHugW2NP X-Received: by 2002:aa7:c043:: with SMTP id k3mr63378374edo.160.1626088153533; Mon, 12 Jul 2021 04:09:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626088153; cv=none; d=google.com; s=arc-20160816; b=ZUYTHfZBU+wj/V/tVJx4nlEi3iAiM2sc6S4lZMYpkz6SoEFNrqmu9EmaEuq0Fyi5kV xt0TGtS/VQ46dHsPm8akPiRC3YmywuVmzdPaFNB619LzR/5lAtP1hU4/WFSO/tXHr44G vyoQYgMOZz4o7c8nJS9kTJOWNNon912As/A8HYWWFynlhvkNTUNmQjcV5J/xkWZfU8aB H6AEuAtSYrMKSY0mM7zMn6PDzFWn0RLfC+XrSLnPYOHss4HVJPaZ4CwpAJhpBkgAiP0V vnsCH2DQM3Rem1KHSaCuqkeovZSmnewdjJtD7EC7YWDb9Wei+/AUTR8kAcKwWwhpzzl9 XYpg== 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:delivered-to; bh=PG33DRrGpbdvRR0g+EfONzhRTHWxl/X5PD5q2LeEfPo=; b=q6nNgBIUNV2EHQIskq8F537fUUb9Crm2vro62F80s0OU/QsEtwD0ApZTFfEcw+UZmA +vs8t7UhaSnitZPciLaZvcjb5IDgtnKrEmpUPhAFk35TbE7HtRM70BTMpscRwv1+9fkx SXJurFJT9rvmEc5uOS38DYbc15tN1BnAWgK8vwvpNA8YGSU+Ej8GH7xVs/oNfwH8R0tZ 2N7z6sjdHTGqeaL2NmaDIzWbkhwmnywuWy9PxEAQBdX3bA6KF+JtffBsoYQCaQOvZVI3 88lsWoXgalLFuS/fihIhFgFCKcbhrfXDj7nJWTo0pMK9SN6+ZP619kmxkmEQEoRzVHWQ 6MRg== ARC-Authentication-Results: i=1; mx.google.com; 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 h2si10605050ejx.355.2021.07.12.04.09.13; Mon, 12 Jul 2021 04:09:13 -0700 (PDT) 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; 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 AC00368A987; Mon, 12 Jul 2021 14:08:07 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0D4C368A959 for ; Mon, 12 Jul 2021 14:08:00 +0300 (EEST) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 2ED81240697 for ; Mon, 12 Jul 2021 13:07:56 +0200 (CEST) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id 7eoK4WTP21VE for ; Mon, 12 Jul 2021 13:07:55 +0200 (CEST) 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 mail0.khirnov.net (Postfix) with ESMTPS id B60D2240699 for ; Mon, 12 Jul 2021 13:07:52 +0200 (CEST) Received: by libav.khirnov.net (Postfix, from userid 1000) id B6A553A0E99; Mon, 12 Jul 2021 13:07:50 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 Jul 2021 13:07:09 +0200 Message-Id: <20210712110709.15532-9-anton@khirnov.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210712110709.15532-1-anton@khirnov.net> References: <20210712110709.15532-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 8/8] lavfi/vf_scale: pass the thread count to the scaler 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: A0XYz8Z5f8Mv Content-Length: 1002 --- libavfilter/vf_scale.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index cdff3ab7ed..f676f5d82e 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -543,6 +543,7 @@ static int config_props(AVFilterLink *outlink) av_opt_set_int(*s, "sws_flags", scale->flags, 0); av_opt_set_int(*s, "param0", scale->param[0], 0); av_opt_set_int(*s, "param1", scale->param[1], 0); + av_opt_set_int(*s, "threads", ff_filter_get_nb_threads(ctx), 0); if (scale->in_range != AVCOL_RANGE_UNSPECIFIED) av_opt_set_int(*s, "src_range", scale->in_range == AVCOL_RANGE_JPEG, 0);