From patchwork Sun Mar 27 13:39:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martijn van Beurden X-Patchwork-Id: 35001 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:6d9d:b0:79:214c:b845 with SMTP id gl29csp3842668pzb; Sun, 27 Mar 2022 06:40:05 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwJpvQVX8rTREJjMk7OI90pZ498qbw0kWAn/WdUGkt2nlsvjhu/VGTx9Kfq2OCqEaBFGg1x X-Received: by 2002:a17:907:2d20:b0:6df:8c3f:730a with SMTP id gs32-20020a1709072d2000b006df8c3f730amr22206594ejc.725.1648388405650; Sun, 27 Mar 2022 06:40:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1648388405; cv=none; d=google.com; s=arc-20160816; b=PO6wcBEhQl++R/OtDXaBw/5/KOkcm54kuEYo0odB2DrdGTD/SlNQP6f7Rzli7pmrJz XyPeuIw5E7BbLXC1hEpwimknDsOrZUgrMYMUvIMTVfbb0Bhu/fa8XAxinGj0pyvkFtwV ysz+VuwV/rTSRW7dQkLNFesN9cHXnW2pr+V69jidiUcTDWCqZAtop5ssBHJbwYjHRNWq Z7Ar//IfvT60kfXUyQCO84C/Y25Qw0ay4dkuQWvXlKqwzYwigtqLXW8CZnCnizz3JdSa fKyT/8ZV7ifYnToRdupFtjSLBFxl/k2myPnpx1kNWRp+mw7ufSplB58MSrkHstF5h8g/ QwJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=oUVmP9XNcImQqxqz/CVbYh+ATe/bOzb3Eb4s+sukquk=; b=A3I85ZO26nwzc8jpmd95B2zDtWHBhrAAhTKK6yiSX1m2Af7uZypKG2yUV2obiZx8QI m0kte6+z4m55pup2Peimuba9f1HqwmoTdPagRdAwPJMDPc7hDQa8/h35IJxCUaFoZmQx Sx9ZfWnvBNx9xO9KE02CtBCe0ENvMAl34yD2WsMWuBNAs7Jfs1X0TX3hTxuOJohwSLk4 NLPeqC0YgYcSQ3MpSXCTQHdev+J7s9soJs41hxgccn7CutUtVGKguLmXGc31dz8+LhK0 HVxBSpUsSkggo54fm/8xnuWZHHnPglnykHxckTpdTjv3Oh6jyZYMpuiEVdyEUdhXtDq8 ORdA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=oRIk6BYn; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id w2-20020a170906130200b006df8927010fsi9343885ejb.777.2022.03.27.06.40.04; Sun, 27 Mar 2022 06:40:05 -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; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=oRIk6BYn; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CE05268A7BB; Sun, 27 Mar 2022 16:40:00 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4BE2068A7BB for ; Sun, 27 Mar 2022 16:39:54 +0300 (EEST) Received: by mail-ej1-f41.google.com with SMTP id o10so23721338ejd.1 for ; Sun, 27 Mar 2022 06:39:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ti8g9kmKp7+0nLu4vXBmAJiNbuUWYjkxtEEUPiwnhZI=; b=oRIk6BYn9ETOy5Dl1xu7GPfrqI7uJbIsJLStAU1THjuWj+qVQDzsRqOjW0Hz1Q7+4F fscjyfeJkQ+lHhHBIg5R6oSVt+XU/WhvMeA1VWwnwN6fcwf/6M/T5rnZfyzbzWFQ67MY zl3RvNCLqCKOGbEckE8rSO4HzGikKBtWqORqpBhXVbiDbjiTXId2AZ7uxmBI3UtQI/9x Sugr3f+3lpCj5ksmNyQWUbLZWiazmJ8YnqTbXjuLLwfyqu8ErRxdZbJJntO6Fr2gbuhb wV7TOuyXlqMWiOvf3rqxc4ux722YABh76XqGAWGJ6cTu0f16OT7eZIp5nb+7m4GrBBza yI/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ti8g9kmKp7+0nLu4vXBmAJiNbuUWYjkxtEEUPiwnhZI=; b=goPiZ6PJIJvxsdp7m3qJ7pEqBWyR8QoonGkzuWk4hQNcb28iTaYe6ULbuotBysZSUo 0yi5vZp1ChyM6WcekK8/m0v1m4IcUDtQHg4iDR8MH1z9OM8+4yZwTfC6UUGYd5Y8vZDE xxOx13opIPYZHbRWfwUHCkmkKbVpQQBbHnMcY4HBF8cBUvE2xkDWF1H8Xc9HhaPHwnO+ yY0BnYF2wYTHMueaDe4rWSKLKgs4OiTHrKeYaF/t4uMWEDlLmnHLOTvz2lKs83KlAo5T h4A+kmBgoXbVAj+E5WKn3gV73Q9JRU7M2hFMt1d7rRCglGbplgzyoU/n023nj+WtDquY /G6Q== X-Gm-Message-State: AOAM532+AnN8/zSjwGOGOhopkypFfkKRuesWXfy68pVnT7QCNeF0zVT9 F4LDEIoYRMzZOOhQjmcK4xhdsfTmUuM= X-Received: by 2002:a17:907:7f94:b0:6da:64ec:fabc with SMTP id qk20-20020a1709077f9400b006da64ecfabcmr22118524ejc.717.1648388393073; Sun, 27 Mar 2022 06:39:53 -0700 (PDT) Received: from localhost.localdomain (92-64-99-37.biz.kpn.net. [92.64.99.37]) by smtp.googlemail.com with ESMTPSA id yy18-20020a170906dc1200b006d6e5c75029sm4585226ejb.187.2022.03.27.06.39.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Mar 2022 06:39:52 -0700 (PDT) From: Martijn van Beurden To: ffmpeg-devel@ffmpeg.org Date: Sun, 27 Mar 2022 15:39:33 +0200 Message-Id: <20220327133933.43039-1-mvanb1@gmail.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] Add decoding of > 32-bit residuals to FLAC 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 Cc: Martijn van Beurden Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: aC51HJS+rlOi The size of residuals in a FLAC file coding for 24-bit PCM can exceed the range of a 32-bit signed integer. One pathological example with residuals exceeding [-2^33,2^33) can be found here: http://www.audiograaf.nl/misc_stuff/Extreme%20residual%20LPC%20order%2014.flac The theorectical maximum bit depth for a residual in a FLAC file is 32 + 1 + 15 + 5 - 0 = 53 bit (max bit depth + extra bit for side channel + max lpc coeff precision + log2(max_order) - min lpc shift) This patch adds detection of the possibilty of such residuals occuring and an alternate data path wide enough to handle them --- libavcodec/flacdec.c | 107 ++++++++++++++++++++++++++++++++++++++----- libavcodec/golomb.h | 56 ++++++++++++++++++++++ 2 files changed, 152 insertions(+), 11 deletions(-) diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index dd6026f9de..3be1b63411 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -64,6 +64,8 @@ typedef struct FLACContext { uint8_t *decoded_buffer; unsigned int decoded_buffer_size; int buggy_lpc; ///< use workaround for old lavc encoded files + int64_t *residual64; ///< to keep residuals exceeding int32_t + unsigned int residual64_size; FLACDSPContext dsp; } FLACContext; @@ -149,6 +151,10 @@ static int allocate_buffers(FLACContext *s) if (!s->decoded_buffer) return AVERROR(ENOMEM); + av_fast_malloc(&s->residual64, &s->residual64_size, 8*s->flac_stream_info.max_blocksize); + if (!s->residual64) + return AVERROR(ENOMEM); + ret = av_samples_fill_arrays((uint8_t **)s->decoded, NULL, s->decoded_buffer, s->flac_stream_info.channels, @@ -279,6 +285,66 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) return 0; } +static int decode_residuals64(FLACContext *s, int64_t *decoded, int pred_order) +{ + GetBitContext gb = s->gb; + int i, tmp, partition, method_type, rice_order; + int rice_bits, rice_esc; + int samples; + + method_type = get_bits(&gb, 2); + rice_order = get_bits(&gb, 4); + + samples = s->blocksize >> rice_order; + rice_bits = 4 + method_type; + rice_esc = (1 << rice_bits) - 1; + + decoded += pred_order; + i = pred_order; + + if (method_type > 1) { + av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n", + method_type); + return AVERROR_INVALIDDATA; + } + + if (samples << rice_order != s->blocksize) { + av_log(s->avctx, AV_LOG_ERROR, "invalid rice order: %i blocksize %i\n", + rice_order, s->blocksize); + return AVERROR_INVALIDDATA; + } + + if (pred_order > samples) { + av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n", + pred_order, samples); + return AVERROR_INVALIDDATA; + } + + for (partition = 0; partition < (1 << rice_order); partition++) { + tmp = get_bits(&gb, rice_bits); + if (tmp == rice_esc) { + tmp = get_bits(&gb, 5); + for (; i < samples; i++) + *decoded++ = get_sbits_long(&gb, tmp); + } else { + for (; i < samples; i++) { + int64_t v = get_sr_golomb64_flac(&gb, tmp, 1); + if (v == INT64_MAX) { + av_log(s->avctx, AV_LOG_ERROR, "invalid residual\n"); + return AVERROR_INVALIDDATA; + } + + *decoded++ = v; + } + } + i = 0; + } + + s->gb = gb; + + return 0; +} + static int decode_subframe_fixed(FLACContext *s, int32_t *decoded, int pred_order, int bps) { @@ -358,6 +424,21 @@ static void lpc_analyze_remodulate(SUINT32 *decoded, const int coeffs[32], } } +static void lpc_residual64(int32_t *decoded, const int64_t *residual, + const int coeffs[32], int pred_order, + int qlevel, int len) +{ + int i, j; + + for (i = pred_order; i < len; i++, decoded++) { + int64_t sum = 0; + for (j = 0; j < pred_order; j++) + sum += (int64_t)coeffs[j] * decoded[j]; + decoded[j] = residual[i] + (sum >> qlevel); + } + +} + static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order, int bps) { @@ -386,19 +467,23 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order, coeffs[pred_order - i - 1] = get_sbits(&s->gb, coeff_prec); } - if ((ret = decode_residuals(s, decoded, pred_order)) < 0) - return ret; - - if ( ( s->buggy_lpc && s->flac_stream_info.bps <= 16) - || ( !s->buggy_lpc && bps <= 16 - && bps + coeff_prec + av_log2(pred_order) <= 32)) { - s->dsp.lpc16(decoded, coeffs, pred_order, qlevel, s->blocksize); + if (bps + coeff_prec + av_log2(pred_order) - qlevel <= 32) { + if ((ret = decode_residuals(s, decoded, pred_order)) < 0) + return ret; + if ( ( s->buggy_lpc && s->flac_stream_info.bps <= 16) + || ( !s->buggy_lpc && bps <= 16 + && bps + coeff_prec + av_log2(pred_order) <= 32)) { + s->dsp.lpc16(decoded, coeffs, pred_order, qlevel, s->blocksize); + } else { + s->dsp.lpc32(decoded, coeffs, pred_order, qlevel, s->blocksize); + if (s->flac_stream_info.bps <= 16) + lpc_analyze_remodulate(decoded, coeffs, pred_order, qlevel, s->blocksize, bps); + } } else { - s->dsp.lpc32(decoded, coeffs, pred_order, qlevel, s->blocksize); - if (s->flac_stream_info.bps <= 16) - lpc_analyze_remodulate(decoded, coeffs, pred_order, qlevel, s->blocksize, bps); + if ((ret = decode_residuals64(s, s->residual64, pred_order)) < 0) + return ret; + lpc_residual64(decoded, s->residual64, coeffs, pred_order, qlevel, s->blocksize); } - return 0; } diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h index 164c2583b6..5ebcdda059 100644 --- a/libavcodec/golomb.h +++ b/libavcodec/golomb.h @@ -543,6 +543,62 @@ static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit, return (v >> 1) ^ -(v & 1); } +static inline int64_t get_sr_golomb64_flac(GetBitContext *gb, int k, + int esc_len) +{ + uint64_t buf; + int log; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + av_assert2(k <= 31); + + if (log - k >= 64 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 64)) { + buf >>= log - k; + buf += (62U - log) << k; + LAST_SKIP_BITS(re, gb, 64 + k - log); + CLOSE_READER(re, gb); + } else { + int64_t i; + for (i = 0; SHOW_UBITS(re, gb, MIN_CACHE_BITS) == 0; i += MIN_CACHE_BITS) { + if (gb->size_in_bits <= re_index) { + CLOSE_READER(re, gb); + return INT64_MAX; + } + LAST_SKIP_BITS(re, gb, MIN_CACHE_BITS); + UPDATE_CACHE(re, gb); + } + for (; SHOW_UBITS(re, gb, 1) == 0; i++) { + SKIP_BITS(re, gb, 1); + } + LAST_SKIP_BITS(re, gb, 1); + UPDATE_CACHE(re, gb); + + if (k) { + if (k > MIN_CACHE_BITS - 1) { + buf = SHOW_UBITS(re, gb, 16) << (k-16); + LAST_SKIP_BITS(re, gb, 16); + UPDATE_CACHE(re, gb); + buf |= SHOW_UBITS(re, gb, k-16); + LAST_SKIP_BITS(re, gb, k-16); + } else { + buf = SHOW_UBITS(re, gb, k); + LAST_SKIP_BITS(re, gb, k); + } + } else { + buf = 0; + } + + buf += (i << k); + CLOSE_READER(re, gb); + } + return (buf >> 1) ^ -(buf & 1); +} + /** * read unsigned golomb rice code (shorten). */