From patchwork Tue Nov 10 10:58:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 23575 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 44EDC44B529 for ; Tue, 10 Nov 2020 13:16:08 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2425D68BFF2; Tue, 10 Nov 2020 12:59:41 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f67.google.com (mail-wr1-f67.google.com [209.85.221.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2841868BFDD for ; Tue, 10 Nov 2020 12:59:33 +0200 (EET) Received: by mail-wr1-f67.google.com with SMTP id b8so12178945wrn.0 for ; Tue, 10 Nov 2020 02:59:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references:reply-to :mime-version:content-transfer-encoding; bh=DVrNJ3JXtBHj/jatnS5QL6t8DQX23hiQrOjIQS+5gtU=; b=m2lJaNEmgu2qEBrMHRlJ1KRoVNRJhFOkGBakY919pOvZ8MwAEHZVSn/iCGwtVibX8w GuHRwygCL1BqHIn5G18rSCN6a9ZAIZlLi2/kRX2fQ0qzP+X2GqVbdCYbTQlWJnq97rwh eqPQLKJuxj7fXo7txskfZCvkcEQvmlmsRrSeOte+c2JuM/i54HyYZlUfVP3bl/dc1vSj A0ie9ateyjQlbX4ZjjLUv7VLupW7l57Lt5vig0BGP1IWSaU7BUj8e142+j5xX2MRCR43 uBJRJxmHIL2YwJCrdfZO1wMRtJTmrC4d9g4m9rE7hGzUQN0FRpJ2T8oNIkPrq5y8HDwL ttIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:reply-to:mime-version:content-transfer-encoding; bh=DVrNJ3JXtBHj/jatnS5QL6t8DQX23hiQrOjIQS+5gtU=; b=AipoRv7bO7CvuFx5+8bv4xH5UyPhQD/gZOZjTYNJIjdpHwN96r7k1Em2ykDUWaLwih qfcKynN36NlrAHjh5SOCkVy7mbXndtK+WY/WQW1bLwAykMjBnVFs0v9+oFT6F8lRJ323 9BCj/fn95HnXIHp1XYNiaZAxkMrl3rF4yfnf4lwQCOlAjchXphVX6hgflhD+5cQCkjZm halKXlb7xY2HD+gExfEeliwMuZcs5WM6pyT6hH6DKt9e21AL2cDQABnlVXZGQpJWWNYw nKBhXy6rnfeKpzkVb43XUWQgn2NFeDmTmFmSb74yBGxXUOx6gHsfJNS1gZnDnFBNVakn YUCA== X-Gm-Message-State: AOAM530SXr9Uawt/XjoKCO4jOC/gmtS7RSvC2AcZ6dXDdl6uUN7jt3Sh 8NIQO0JkfidyJeelLbT0KQq7Pf3tGjw= X-Google-Smtp-Source: ABdhPJy99hgEUj6UxIZKcGESiGiUdBgnRKQbBSWmqQW5rggfxwH3bXfCgXAoipRiZFZfYPrVQgnp6Q== X-Received: by 2002:a5d:66c3:: with SMTP id k3mr18337640wrw.123.1605005972418; Tue, 10 Nov 2020 02:59:32 -0800 (PST) Received: from sblaptop.fritz.box (ipbcc1aa4b.dynamic.kabel-deutschland.de. [188.193.170.75]) by smtp.gmail.com with ESMTPSA id o197sm2561308wme.17.2020.11.10.02.59.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Nov 2020 02:59:31 -0800 (PST) From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Tue, 10 Nov 2020 11:58:31 +0100 Message-Id: <20201110105836.321916-18-andreas.rheinhardt@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201110104851.321029-1-andreas.rheinhardt@gmail.com> References: <20201110104851.321029-1-andreas.rheinhardt@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 109/114] avcodec/utvideodec: Avoid implicit qsort when creating Huffman tables X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" The Huffman trees used by Ut Video have two important characteristics: (i) Longer codes are on the left of the tree and (ii) for codes of the same length, the symbol is descending from left to right in the tree. Therefore all the information that needs to be transmitted is how long the code corresponding to a given symbol is; and this is also all that is transmitted. Before 341914495e5c2f60bc920b0c6f660e5948a47f5a, the decoder used qsort to sort the (length, symbol) pairs by ascending length and for equal lengths by ascending symbol. Since said commit, the decoder uses the first pass over the lengths table to count how many symbols of each length there are; with (i) one can then easily calculate the code of the left-most code with a given length in the tree and from there one can calculate the codes for all entries, using one running counter for each possible length. This eliminated the explicit qsort in build_huff(). Yet ff_init_vlc_sparse() sorts the table itself as it has to ensure that all the entries that will be placed in the same subtable are contiguous. The tables created now are non-contiguous (they are ordered by symbol and codes of different length aren't ordered at all; only codes of the same length are ordered according to (ii)). This commit therefore modifies the algorithm used to automatically create tables whose codes are sorted from left to right in the tree. The key to do so is the observation that the counts obtained in the first pass can be used to contain the range of the codes of each length in the second pass: If counts[i] is the count of codes with length i, then the first counts[32] codes are of length 32, the next counts[31] codes are of length 31 etc. So one knows the index of the lowest symbol whose code has length 32 (if any): It is counts[32] - 1 due to (ii), whereas the index of the lowest symbol whose code has length 31 (if any) is counts[32] + counts[31] - 1; the index of the second-to-lowest symbol of length 32 (if existing) is counts[32] - 2 etc. If one follows the algorithm outlined above, one can switch to ff_init_vlc_from_lengths() which has no implicit qsort; it also means that one can offload the computation of the codes. This turned out to be beneficial for performance: For the sample from ticket #4044 it decreased the decicycles spent on one call to build_huff() from 508480 to 340688 (GCC 9.3, looping 10 times over the file to get enough runs and then repeating this ten times); for another sample; for another sample (YUV420p, natural content, 5500 frames, also ten iterations) the time went down from 382346 to 275533 decicycles. Signed-off-by: Andreas Rheinhardt --- libavcodec/utvideodec.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 8b47c14d98..3d505ea2a3 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -40,10 +40,15 @@ #include "thread.h" #include "utvideo.h" +typedef struct HuffEntry { + uint8_t len; + uint16_t sym; +} HuffEntry; + static int build_huff(const uint8_t *src, VLC *vlc, int *fsym, unsigned nb_elems) { int i; - uint32_t codes[1024]; + HuffEntry he[1024]; uint8_t bits[1024]; uint16_t codes_count[33] = { 0 }; @@ -64,23 +69,21 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym, unsigned nb_elems if (codes_count[0] == nb_elems) return AVERROR_INVALIDDATA; - for (unsigned i = 32, nb_codes = 0; i > 0; i--) { - uint16_t curr = codes_count[i]; // # of leafs of length i - codes_count[i] = nb_codes / 2; // # of non-leaf nodes on level i - nb_codes = codes_count[i] + curr; // # of nodes on level i - } + /* For Ut Video, longer codes are to the left of the tree and + * for codes with the same length the symbol is descending from + * left to right. So after the next loop --codes_count[i] will + * be the index of the first (lowest) symbol of length i when + * indexed by the position in the tree with left nodes being first. */ + for (int i = 31; i >= 0; i--) + codes_count[i] += codes_count[i + 1]; + + for (unsigned i = 0; i < nb_elems; i++) + he[--codes_count[bits[i]]] = (HuffEntry) { bits[i], i }; - for (unsigned i = nb_elems; i-- > 0;) { - if (!bits[i]) { - codes[i] = 0; - continue; - } - codes[i] = codes_count[bits[i]]++; - } #define VLC_BITS 11 - return init_vlc(vlc, VLC_BITS, nb_elems, - bits, sizeof(*bits), sizeof(*bits), - codes, sizeof(*codes), sizeof(*codes), 0); + return ff_init_vlc_from_lengths(vlc, VLC_BITS, codes_count[0], + &he[0].len, sizeof(*he), + &he[0].sym, sizeof(*he), 2, 0, 0); } static int decode_plane10(UtvideoContext *c, int plane_no,