From patchwork Fri Sep 16 20:14:13 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: 37971 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3b1c:b0:96:9ee8:5cfd with SMTP id c28csp1196370pzh; Fri, 16 Sep 2022 13:15:21 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5++KOzZoGpQWJiHMr3xgdc1hSLhfscv17dOs3TyzBvhBfR0C3k+UtRGaO2mouzgDbouDjV X-Received: by 2002:a17:907:a40f:b0:77b:b3c7:28b6 with SMTP id sg15-20020a170907a40f00b0077bb3c728b6mr4638266ejc.637.1663359321635; Fri, 16 Sep 2022 13:15:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1663359321; cv=none; d=google.com; s=arc-20160816; b=0uZo+KR1VFjuliIir5tqwERvCpm4ACi0TeLJW4/urQYwWsq9MF7g3vufDcCdw4I05k OSSHmtk5gWPBTkiWICzHJ5q0Dh+iGkzRMdL+tkEn59qsxq05baWHxtZ3Ntw8aOrt2MS+ MsvZfEOVqZwabglNB48T9BJBFyrouW1xxeg8zVJrGh5ZeseEiFq+c57I2v1lKMbOIH+K 2Ovyr1ErJ4CtXsqnFh9VPOidzjCWncbCcm4qTFR3MmYqrGSMv1LC+ZLL9UdbE2nBjYeH hrB1Olfzo+Mt/JzT5Ef1B0efPN3LA3ERXqeCglPEgRAUQiYqX2eOFCTmQTtFn8Ibtdgy Iqmg== 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:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=SHlCtLuMp2OO+axWkhr2Ol+5oPj+K2k7KZIB42ax1PE=; b=AmreQKeFWHyFUuN37yaSpIcYKVIIOeTlZGajWQQo3lcTtPgECMJpBAyYMinU7kv5uJ tQ31UKHMS1D8kzh/47tqE2PkXQteVWpiXEF7B1bJL5RfLc1pTZg82Xqw+SM8lQNUqwRA OwUCb77ncQqv9sAwYS2dp9gbvPejK4dsSOrkfE73PCpI7TrMZjD24GYEao3GJp5IWnP3 MSCD7tfawaU5se78oRLSs1fqe0jhQW6tJw6RAFUTWYxXOI1t4PDTtAhbds795SCvd5jZ 8upeMUn9Cfj9okyFMTkuimEdgzJ1oYgNcf+UY2ESpIsJTWEt3edBBubB+ufKKvNAyFZ1 izHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="da3t+M/x"; 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 rk14-20020a170907214e00b007808393cf7fsi2629369ejb.413.2022.09.16.13.15.00; Fri, 16 Sep 2022 13:15:21 -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="da3t+M/x"; 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 8E95968BC41; Fri, 16 Sep 2022 23:14:50 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 99A1D68BBE7 for ; Fri, 16 Sep 2022 23:14:43 +0300 (EEST) Received: by mail-ej1-f45.google.com with SMTP id kr11so5819651ejc.8 for ; Fri, 16 Sep 2022 13:14:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=dvxHsVlUkxe5uHcSw8kOjYMARJxdGJOH30vvo7G9bzc=; b=da3t+M/xVJpRJRWqB2CtyCa2MkGnUOUpAo8vZP5p8AxD2Pgb6Ifa4XQJ4HC+rQd1AX +RyBdq8YSqE9uPG1f8e/J28qRJ/RvOtQvSrLVUm/X52rMTt3k3Udqjbnok4yD8mYWULv 5wsRNL5tvPwUh08yJvNm8abd2uz7fuWuoCdAf3/sd7wnh6EVLo77REwM35YanBMY08kQ nuDaYw59ziQYEIsN14LQjQcE6ZFkIpvAATto+oCs9w/7mcZwy5JFKsGbEIv6ea/LvmAx IWwezDyaNn6VgAsqjc1ZCmlKuJQDKLyRTdyxZmcjklFFFJEky1LdbQ+FiNDUrUjiaY71 z5iQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=dvxHsVlUkxe5uHcSw8kOjYMARJxdGJOH30vvo7G9bzc=; b=fMPotjiS3M/XIOxjM5vGvIzU+BkPa8dD2VU7egBfShDbz4oajxk1ECicdYtRj7UBiR 5uN8qOcwT0Xx4sSF0V3RXG90L3POu7zBtZGDm+uL02oKPMjjyp3Ydo9AuFndMCA3ldTk p6s03rUi7jhbmfGWimtYWluKhTwQpywpYV4OixgLbaue8eTPgL79X0kqig7dJ2R9JJc1 99ZBf8HatHXaztKaG4uhQbzBt+DUASU3QISeU1B78kkmm4lxl4hmaqQ3aRiIAHSedSCv fcH/iH82d6+K+ZC3Tj82PKIrRRFASkmkobWyXevJabn+x6ImbFB9YM+rZv+yMTHEyBQ0 OFGQ== X-Gm-Message-State: ACrzQf2Z6PsnFSoR//LtTSUWwnXXbPtJbjg8vfNYvo5c9WCrEp3U85Ot e8Y/JYGHCP/XexyZAAQg/VNzSe42KBR4vw== X-Received: by 2002:a17:907:a40a:b0:77e:f3ee:c791 with SMTP id sg10-20020a170907a40a00b0077ef3eec791mr4655359ejc.384.1663359282630; Fri, 16 Sep 2022 13:14:42 -0700 (PDT) Received: from localhost.localdomain (92-64-99-37.biz.kpn.net. [92.64.99.37]) by smtp.googlemail.com with ESMTPSA id kw4-20020a170907770400b0073dcdf9b0bcsm11112433ejc.17.2022.09.16.13.14.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Sep 2022 13:14:42 -0700 (PDT) From: Martijn van Beurden To: ffmpeg-devel@ffmpeg.org Date: Fri, 16 Sep 2022 22:14:13 +0200 Message-Id: <20220916201415.2583646-2-mvanb1@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220916201415.2583646-1-mvanb1@gmail.com> References: <20220916201415.2583646-1-mvanb1@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v6 1/3] libavcodec/flacdec: Implement decoding of 32 bit-per-sample PCM 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: wql86qYwmlk5 Add decoding of FLAC files coding for 32 bit-per-sample PCM to libavcodec. --- libavcodec/flac.c | 4 +- libavcodec/flacdec.c | 250 ++++++++++++++++++++++++++++++++++++++---- libavcodec/get_bits.h | 12 ++ libavcodec/mathops.h | 9 ++ 4 files changed, 251 insertions(+), 24 deletions(-) diff --git a/libavcodec/flac.c b/libavcodec/flac.c index 352d663c67..174b4801be 100644 --- a/libavcodec/flac.c +++ b/libavcodec/flac.c @@ -28,7 +28,7 @@ #include "flacdata.h" #include "flac_parse.h" -static const int8_t sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 }; +static const int8_t sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 32 }; static const AVChannelLayout flac_channel_layouts[8] = { AV_CHANNEL_LAYOUT_MONO, @@ -82,7 +82,7 @@ int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, /* bits per sample */ bps_code = get_bits(gb, 3); - if (bps_code == 3 || bps_code == 7) { + if (bps_code == 3) { av_log(avctx, AV_LOG_ERROR + log_level_offset, "invalid sample size code (%d)\n", bps_code); diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index 5b8547a98f..bc5c06b73d 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -64,6 +64,9 @@ typedef struct FLACContext { int32_t *decoded[FLAC_MAX_CHANNELS]; ///< decoded samples uint8_t *decoded_buffer; unsigned int decoded_buffer_size; + int64_t *decoded_33bps; ///< decoded samples for a 33 bps subframe + uint8_t *decoded_buffer_33bps; + unsigned int decoded_buffer_size_33bps; int buggy_lpc; ///< use workaround for old lavc encoded files FLACDSPContext dsp; @@ -154,6 +157,24 @@ static int allocate_buffers(FLACContext *s) s->stream_info.channels, s->stream_info.max_blocksize, AV_SAMPLE_FMT_S32P, 0); + if (ret >= 0 && s->stream_info.bps == 32 && s->stream_info.channels == 2) { + buf_size = av_samples_get_buffer_size(NULL, 1, + s->stream_info.max_blocksize, + AV_SAMPLE_FMT_S64P, 0); + if (buf_size < 0) + return buf_size; + + av_fast_malloc(&s->decoded_buffer_33bps, &s->decoded_buffer_size_33bps, buf_size); + if (!s->decoded_buffer_33bps) + return AVERROR(ENOMEM); + + ret = av_samples_fill_arrays((uint8_t **)&s->decoded_33bps, NULL, + s->decoded_buffer_33bps, + 1, + s->stream_info.max_blocksize, + AV_SAMPLE_FMT_S64P, 0); + + } return ret < 0 ? ret : 0; } @@ -331,6 +352,94 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded, return 0; } +static int decode_subframe_fixed_wide(FLACContext *s, int32_t *decoded, + int pred_order, int bps) +{ + const int blocksize = s->blocksize; + int i; + int ret; + + /* warm up samples */ + for (i = 0; i < pred_order; i++) { + decoded[i] = get_sbits_long(&s->gb, bps); + } + + if ((ret = decode_residuals(s, decoded, pred_order)) < 0) + return ret; + + switch (pred_order) { + case 0: + break; + case 1: + for (i = pred_order; i < blocksize; i++) + decoded[i] += decoded[i-1]; + break; + case 2: + for (i = pred_order; i < blocksize; i++) + decoded[i] = (int64_t)decoded[i] + 2*(int64_t)decoded[i-1] - (int64_t)decoded[i-2]; + break; + case 3: + for (i = pred_order; i < blocksize; i++) + decoded[i] = (int64_t)decoded[i] + 3*(int64_t)decoded[i-1] - 3*(int64_t)decoded[i-2] + (int64_t)decoded[i-3]; + break; + case 4: + for (i = pred_order; i < blocksize; i++) + decoded[i] = (int64_t)decoded[i] + 4*(int64_t)decoded[i-1] - 6*(int64_t)decoded[i-2] + 4*(int64_t)decoded[i-3] - (int64_t)decoded[i-4]; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order); + return AVERROR_INVALIDDATA; + } + + return 0; +} + + +static int decode_subframe_fixed_33bps(FLACContext *s, int64_t *decoded, + int32_t *residual, int pred_order) +{ + const int blocksize = s->blocksize; + int i; + int ret; + + /* warm up samples */ + for (i = 0; i < pred_order; i++) { + decoded[i] = get_sbits64(&s->gb, 33); + av_log(s->avctx, AV_LOG_DEBUG, "warm-up %d = %" PRId64 "\n", i, decoded[i]); + } + + if ((ret = decode_residuals(s, residual, pred_order)) < 0) + return ret; + + switch (pred_order) { + case 0: + for (i = pred_order; i < blocksize; i++) + decoded[i] = residual[i]; + break; + case 1: + for (i = pred_order; i < blocksize; i++) + decoded[i] = residual[i] + decoded[i-1]; + break; + case 2: + for (i = pred_order; i < blocksize; i++) + decoded[i] = residual[i] + 2*decoded[i-1] - decoded[i-2]; + break; + case 3: + for (i = pred_order; i < blocksize; i++) + decoded[i] = residual[i] + 3*decoded[i-1] - 3*decoded[i-2] + decoded[i-3]; + break; + case 4: + for (i = pred_order; i < blocksize; i++) + decoded[i] = residual[i] + 4*decoded[i-1] - 6*decoded[i-2] + 4*decoded[i-3] - decoded[i-4]; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order); + return AVERROR_INVALIDDATA; + } + + return 0; +} + static void lpc_analyze_remodulate(SUINT32 *decoded, const int coeffs[32], int order, int qlevel, int len, int bps) { @@ -402,12 +511,53 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order, return 0; } +static int decode_subframe_lpc_33bps(FLACContext *s, int64_t *decoded, + int32_t *residual, int pred_order) +{ + int i, j, ret; + int coeff_prec, qlevel; + int coeffs[32]; + + /* warm up samples */ + for (i = 0; i < pred_order; i++) { + decoded[i] = get_sbits64(&s->gb, 33); + } + + coeff_prec = get_bits(&s->gb, 4) + 1; + if (coeff_prec == 16) { + av_log(s->avctx, AV_LOG_ERROR, "invalid coeff precision\n"); + return AVERROR_INVALIDDATA; + } + qlevel = get_sbits(&s->gb, 5); + if (qlevel < 0) { + av_log(s->avctx, AV_LOG_ERROR, "qlevel %d not supported, maybe buggy stream\n", + qlevel); + return AVERROR_INVALIDDATA; + } + + for (i = 0; i < pred_order; i++) { + coeffs[pred_order - i - 1] = get_sbits(&s->gb, coeff_prec); + } + + if ((ret = decode_residuals(s, residual, pred_order)) < 0) + return ret; + + for (i = pred_order; i < s->blocksize; 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); + } + + return 0; +} + static inline int decode_subframe(FLACContext *s, int channel) { int32_t *decoded = s->decoded[channel]; int type, wasted = 0; int bps = s->stream_info.bps; - int i, tmp, ret; + int i, ret; if (channel == 0) { if (s->ch_mode == FLAC_CHMODE_RIGHT_SIDE) @@ -427,7 +577,7 @@ static inline int decode_subframe(FLACContext *s, int channel) int left = get_bits_left(&s->gb); if ( left <= 0 || (left < bps && !show_bits_long(&s->gb, left)) || - !show_bits_long(&s->gb, bps)) { + !show_bits_long(&s->gb, bps-1)) { av_log(s->avctx, AV_LOG_ERROR, "Invalid number of wasted bits > available bits (%d) - left=%d\n", bps, left); @@ -436,34 +586,63 @@ static inline int decode_subframe(FLACContext *s, int channel) wasted = 1 + get_unary(&s->gb, 1, get_bits_left(&s->gb)); bps -= wasted; } - if (bps > 32) { - avpriv_report_missing_feature(s->avctx, "Decorrelated bit depth > 32"); - return AVERROR_PATCHWELCOME; - } //FIXME use av_log2 for types if (type == 0) { - tmp = get_sbits_long(&s->gb, bps); - for (i = 0; i < s->blocksize; i++) - decoded[i] = tmp; + if (bps < 33) { + int32_t tmp = get_sbits_long(&s->gb, bps); + for (i = 0; i < s->blocksize; i++) + decoded[i] = tmp; + } else { + int64_t tmp = get_sbits64(&s->gb, 33); + for (i = 0; i < s->blocksize; i++) + s->decoded_33bps[i] = tmp; + } } else if (type == 1) { - for (i = 0; i < s->blocksize; i++) - decoded[i] = get_sbits_long(&s->gb, bps); + if (bps < 33) { + for (i = 0; i < s->blocksize; i++) + decoded[i] = get_sbits_long(&s->gb, bps); + } else { + for (i = 0; i < s->blocksize; i++) + s->decoded_33bps[i] = get_sbits64(&s->gb, 33); + } } else if ((type >= 8) && (type <= 12)) { - if ((ret = decode_subframe_fixed(s, decoded, type & ~0x8, bps)) < 0) - return ret; + int order = type & ~0x8; + if (bps < 33) { + if (bps + order <= 32) { + if ((ret = decode_subframe_fixed(s, decoded, order, bps)) < 0) + return ret; + } else { + if ((ret = decode_subframe_fixed_wide(s, decoded, order, bps)) < 0) + return ret; + } + } else { + if ((ret = decode_subframe_fixed_33bps(s, s->decoded_33bps, decoded, order)) < 0) + return ret; + } } else if (type >= 32) { - if ((ret = decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps)) < 0) - return ret; + if (bps < 33) { + if ((ret = decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps)) < 0) + return ret; + } else { + if ((ret = decode_subframe_lpc_33bps(s, s->decoded_33bps, decoded, (type & ~0x20)+1)) < 0) + return ret; + } } else { av_log(s->avctx, AV_LOG_ERROR, "invalid coding type\n"); return AVERROR_INVALIDDATA; } - if (wasted && wasted < 32) { - int i; - for (i = 0; i < s->blocksize; i++) - decoded[i] = (unsigned)decoded[i] << wasted; + if (wasted) { + if (wasted+bps == 33) { + int i; + for (i = 0; i < s->blocksize; i++) + s->decoded_33bps[i] = (uint64_t)decoded[i] << wasted; + } else if (wasted < 32) { + int i; + for (i = 0; i < s->blocksize; i++) + decoded[i] = (unsigned)decoded[i] << wasted; + } } return 0; @@ -554,6 +733,26 @@ static int decode_frame(FLACContext *s) return 0; } +static void decorrelate_33bps(int ch_mode, int32_t **decoded, int64_t *decoded_33bps, int len) +{ + int i; + if (ch_mode == FLAC_CHMODE_LEFT_SIDE ) { + for (i = 0; i < len; i++) + decoded[1][i] = decoded[0][i] - decoded_33bps[i]; + } else if (ch_mode == FLAC_CHMODE_RIGHT_SIDE ) { + for (i = 0; i < len; i++) + decoded[0][i] = decoded[1][i] + decoded_33bps[i]; + } else if (ch_mode == FLAC_CHMODE_MID_SIDE ) { + for (i = 0; i < len; i++) { + uint64_t a = decoded[0][i]; + int64_t b = decoded_33bps[i]; + a -= b >> 1; + decoded[0][i] = (a + b); + decoded[1][i] = a; + } + } +} + static int flac_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { @@ -612,9 +811,15 @@ static int flac_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0) return ret; - s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded, - s->stream_info.channels, - s->blocksize, s->sample_shift); + if (s->stream_info.bps == 32 && s->ch_mode > 0) { + decorrelate_33bps(s->ch_mode, s->decoded, s->decoded_33bps, s->blocksize); + s->dsp.decorrelate[0](frame->data, s->decoded, s->stream_info.channels, + s->blocksize, s->sample_shift); + } else { + s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded, + s->stream_info.channels, + s->blocksize, s->sample_shift); + } if (bytes_read > buf_size) { av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", bytes_read - buf_size); @@ -635,6 +840,7 @@ static av_cold int flac_decode_close(AVCodecContext *avctx) FLACContext *s = avctx->priv_data; av_freep(&s->decoded_buffer); + av_freep(&s->decoded_buffer_33bps); return 0; } diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h index 992765dc92..52d13b8242 100644 --- a/libavcodec/get_bits.h +++ b/libavcodec/get_bits.h @@ -596,6 +596,18 @@ static inline int get_sbits_long(GetBitContext *s, int n) return sign_extend(get_bits_long(s, n), n); } +/** + * Read 0-64 bits as a signed integer. + */ +static inline int64_t get_sbits64(GetBitContext *s, int n) +{ + // sign_extend(x, 0) is undefined + if (!n) + return 0; + + return sign_extend64(get_bits64(s, n), n); +} + /** * Show 0-32 bits. */ diff --git a/libavcodec/mathops.h b/libavcodec/mathops.h index c89054d6ed..a1dc323304 100644 --- a/libavcodec/mathops.h +++ b/libavcodec/mathops.h @@ -138,6 +138,15 @@ static inline av_const int sign_extend(int val, unsigned bits) } #endif +#ifndef sign_extend64 +static inline av_const int64_t sign_extend64(int64_t val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int64_t) - bits; + union { uint64_t u; int64_t s; } v = { (uint64_t) val << shift }; + return v.s >> shift; +} +#endif + #ifndef zero_extend static inline av_const unsigned zero_extend(unsigned val, unsigned bits) { From patchwork Fri Sep 16 20:14:14 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: 37969 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3b1c:b0:96:9ee8:5cfd with SMTP id c28csp1196244pzh; Fri, 16 Sep 2022 13:15:10 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5uFwCYdtBiBbwl4L6PXkQMir3ZleGYnNg+JoH90y/ar2bs9ejA8FcKSWiRewYuA/ZA0WQJ X-Received: by 2002:a05:6402:2816:b0:434:ed38:16f3 with SMTP id h22-20020a056402281600b00434ed3816f3mr5244090ede.116.1663359310486; Fri, 16 Sep 2022 13:15:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1663359310; cv=none; d=google.com; s=arc-20160816; b=lhogrTkoVa5QuL4IcvoqFapf5wpJZqreUgwoZLwz+/PW9+JZMalNezfUquWzq3BmtN txBKNZAvNnXTIwWGkYGjTJZUalzp1kimfdcw56wCKvuRsf87cBkL/hIPCT2t4We52+iU gJAsa3Nb7GihrnFGwC77jIgmCvikk2focJAG9CoqGrqYhEhL7T/BdVP8KwY3uCMUe5eF B9poC/kH+NqDsP7GDwdBcYXNLltH5aJCFDlwp9TRIuMcficfMScaEFDFDw15EdyW4D8Z jVEsPWMghrKeM0ydhNB34B2hoyBZtrBoq6WD34cmghfppgqMpAmJtBUYLbL2jqCoF67R 7Ztw== 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:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=0imf5+0LSI23jTuaqBIgAlOzTrmLrlAr7bgfdSio/fQ=; b=ploRopj8LugANy7nTjJ65sHDreaa1VVZ7dnkyPkQ2aY0vFciN7LdJ+g54RNHT0sbMx JN2Kci5RbDeUIMqhz590GpEzi4v5Ja4C72FHM/zF/Vt8BzEoSgsV4O7pFg8cGjBAL+9V ldUvZZm42X4U/wnhlAAgkyw91s2qZZ6BRpzGLBhHrKlh/gNPbkzYHozIapiOTxaO/eIk +qTifRYci1MyQ19jNlkQQBVZoABU+snE0aWPM/8Q/Y1HPamcSJs/MANOgZ2U9ZBwz8/z EHJQQYL9umjOLI0XXrsddtUJlnKRRQCwmXM3BMEP5fx1uT3/Z6sD+cn7ScfRT5YxLRVY yUwA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=ksxm7uFJ; 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 hs27-20020a1709073e9b00b00770872942d8si10788644ejc.958.2022.09.16.13.15.10; Fri, 16 Sep 2022 13:15:10 -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=ksxm7uFJ; 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 7ABEE68BC3D; Fri, 16 Sep 2022 23:14:52 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BF56068BC45 for ; Fri, 16 Sep 2022 23:14:44 +0300 (EEST) Received: by mail-ej1-f54.google.com with SMTP id a26so23193027ejc.4 for ; Fri, 16 Sep 2022 13:14:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=BoVHSHPMds04/ihLWJCpJveK0k+JRsGHQrxczqwwsP0=; b=ksxm7uFJUToy/BbpmxWHW/MtgwHLyRO0rMvkwhtiGCFcqxGCN8Wz6QUeEhojj7kp9L LsjygOuiTjTo4ksvzwkSa/IwRYjZgrp9Qpe3UD6BgcrLRR28xT2/+VZ5dARMfn6ylJ3X ArqGnHC5f2eCbByv1lyAAR7GyjLD2drtvOtOImEcJ/N6vITVIekjIJGkY325A011AhWh rK88YVvyBShZj+ApwSMt6TF8GuVOke2AxAEY2DFjrUemRVxjKN4D7+L747NzaYadoO4L D77SWG/oT3sN0DUj3/sgXLppAZBScbQ2eA4M7oPMOa/fylchDIScAMFpBHwZXSz8dYU+ dx1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=BoVHSHPMds04/ihLWJCpJveK0k+JRsGHQrxczqwwsP0=; b=iWSOlPbontUSxO7U3+jQ0fOHJVAYS9ms8DtmcWvSX8ooWT69UqzkT1XVX4B2YdV+ba kTqiN24G4yhEWNP86Ag9GT5tp+LHJlyRF2XuXGzVheWS3BsOyCk6kgRaFwEwry2qIAf5 ZN2VPL5aurhld6zu874/9foNUC8/zOEz4jyKf5rlvZvXX5h/pCmk92pZvtXhd0fSTJLd n0j1DtcIbbompjkzlgIQDKghdsTxBmz38LQqUhJdjpih+zTSy7XispLKFCmTkctDTYy6 xzX9g9Kyim/tPDKHTmA8ZV9qfipHO33Ev1g5DZDGnkPpmeq+OlqHBW+wz0cln2Gs91sS 3dOQ== X-Gm-Message-State: ACrzQf1IW7eNLwLo1qIeXIaI/XzgBc+M4iYJxOfjgszc57orNHQ9UZbL pGdhNAFg5MWP2lZDWzwiD533zWKriOmNZw== X-Received: by 2002:a17:907:7ea6:b0:77a:c72a:b851 with SMTP id qb38-20020a1709077ea600b0077ac72ab851mr4868756ejc.220.1663359283553; Fri, 16 Sep 2022 13:14:43 -0700 (PDT) Received: from localhost.localdomain (92-64-99-37.biz.kpn.net. [92.64.99.37]) by smtp.googlemail.com with ESMTPSA id kw4-20020a170907770400b0073dcdf9b0bcsm11112433ejc.17.2022.09.16.13.14.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Sep 2022 13:14:43 -0700 (PDT) From: Martijn van Beurden To: ffmpeg-devel@ffmpeg.org Date: Fri, 16 Sep 2022 22:14:14 +0200 Message-Id: <20220916201415.2583646-3-mvanb1@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220916201415.2583646-1-mvanb1@gmail.com> References: <20220916201415.2583646-1-mvanb1@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v6 2/3] libavcodec/flacenc: Implement encoding of 32 bit-per-sample PCM 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: qni4rsJffxOY Add encoding of 32 bit-per-sample PCM to FLAC files to libavcodec. Coding to this format is at this point considered experimental and -strict experimental is needed to get ffmpeg to encode such files. --- libavcodec/flacenc.c | 518 ++++++++++++++++++++++++++++++++-------- libavcodec/put_bits.h | 7 + libavcodec/put_golomb.h | 14 -- 3 files changed, 423 insertions(+), 116 deletions(-) diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c index 5d8c3f82be..b69adaf4ba 100644 --- a/libavcodec/flacenc.c +++ b/libavcodec/flacenc.c @@ -31,7 +31,6 @@ #include "codec_internal.h" #include "encode.h" #include "put_bits.h" -#include "put_golomb.h" #include "lpc.h" #include "flac.h" #include "flacdata.h" @@ -95,6 +94,7 @@ typedef struct FlacSubframe { typedef struct FlacFrame { FlacSubframe subframes[FLAC_MAX_CHANNELS]; + int64_t samples_33bps[FLAC_MAX_BLOCKSIZE]; int blocksize; int bs_code[2]; uint8_t crc8; @@ -282,10 +282,22 @@ static av_cold int flac_encode_init(AVCodecContext *avctx) s->bps_code = 4; break; case AV_SAMPLE_FMT_S32: - if (avctx->bits_per_raw_sample != 24) - av_log(avctx, AV_LOG_WARNING, "encoding as 24 bits-per-sample\n"); - avctx->bits_per_raw_sample = 24; - s->bps_code = 6; + if (avctx->bits_per_raw_sample <= 24) { + if (avctx->bits_per_raw_sample < 24) + av_log(avctx, AV_LOG_WARNING, "encoding as 24 bits-per-sample\n"); + avctx->bits_per_raw_sample = 24; + s->bps_code = 6; + } else if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_WARNING, + "encoding as 24 bits-per-sample, more is considered " + "experimental. Add -strict experimental if you want " + "to encode more than 24 bits-per-sample\n"); + avctx->bits_per_raw_sample = 24; + s->bps_code = 6; + } else { + avctx->bits_per_raw_sample = 32; + s->bps_code = 7; + } break; } @@ -533,8 +545,7 @@ static uint64_t rice_count_exact(const int32_t *res, int n, int k) uint64_t count = 0; for (i = 0; i < n; i++) { - int32_t v = -2 * res[i] - 1; - v ^= v >> 31; + unsigned v = ((unsigned)(res[i]) << 1) ^ (res[i] >> 31); count += (v >> k) + 1 + k; } return count; @@ -713,8 +724,8 @@ static uint64_t calc_rice_params(RiceContext *rc, tmp_rc.coding_mode = rc->coding_mode; - for (i = 0; i < n; i++) - udata[i] = (2 * data[i]) ^ (data[i] >> 31); + for (i = pred_order; i < n; i++) + udata[i] = ((unsigned)(data[i]) << 1) ^ (data[i] >> 31); calc_sum_top(pmax, exact ? kmax : 0, udata, n, pred_order, sums); @@ -812,6 +823,180 @@ static void encode_residual_fixed(int32_t *res, const int32_t *smp, int n, } +static int encode_residual_fixed_with_residual_limit(int32_t *res, const int32_t *smp, + int n, int order) +{ + /* This function checks for every residual whether it can be + * contained in INT32_MAX) + return 1; + res[i] = res64; + } + } else if (order == 2) { + for (i = order; i < n; i++) { + res64 = (int64_t)smp[i] - 2*(int64_t)smp[i-1] + smp[i-2]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } else if (order == 3) { + for (i = order; i < n; i++) { + res64 = (int64_t)smp[i] - 3*(int64_t)smp[i-1] + 3*(int64_t)smp[i-2] - smp[i-3]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } else { + for (i = order; i < n; i++) { + res64 = (int64_t)smp[i] - 4*(int64_t)smp[i-1] + 6*(int64_t)smp[i-2] - 4*(int64_t)smp[i-3] + smp[i-4]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } + return 0; +} + + +static int encode_residual_fixed_with_residual_limit_33bps(int32_t *res, const int64_t *smp, + int n, int order) +{ + /* This function checks for every residual whether it can be + * contained in INT32_MAX) + return 1; + res[i] = smp[i]; + } + } else if (order == 1) { + for (i = order; i < n; i++) { + res64 = smp[i] - smp[i-1]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } else if (order == 2) { + for (i = order; i < n; i++) { + res64 = smp[i] - 2*smp[i-1] + smp[i-2]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } else if (order == 3) { + for (i = order; i < n; i++) { + res64 = smp[i] - 3*smp[i-1] + 3*smp[i-2] - smp[i-3]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } else { + for (i = order; i < n; i++) { + res64 = smp[i] - 4*smp[i-1] + 6*smp[i-2] - 4*smp[i-3] + smp[i-4]; + if (res64 <= INT32_MIN || res64 > INT32_MAX) + return 1; + res[i] = res64; + } + } + return 0; +} + + +static int lpc_encode_with_residual_limit(int32_t *res, const int32_t *smp, int len, + int order, int32_t *coefs, int shift) +{ + /* This function checks for every residual whether it can be + * contained in >= shift; + tmp = smp[i] - p; + if (tmp <= INT32_MIN || tmp > INT32_MAX) + return 1; + res[i] = tmp; + } + return 0; +} + +static int lpc_encode_with_residual_limit_33bps(int32_t *res, const int64_t *smp, int len, + int order, int32_t *coefs, int shift) +{ + /* This function checks for every residual whether it can be + * contained in >= shift; + tmp = smp[i] - p; + if (tmp <= INT32_MIN || tmp > INT32_MAX) + return 1; + res[i] = tmp; + } + return 0; +} + +static int lpc_encode_choose_datapath(FlacEncodeContext *s, int32_t bps, + int32_t *res, const int32_t *smp, + const int64_t *smp_33bps, int len, + int order, int32_t *coefs, int shift) +{ + uint64_t max_residual_value = 0; + int64_t max_sample_value = ((int64_t)(1) << (bps-1)); + /* This calculates the max size of any residual with the current + * predictor, so we know whether we need to check the residual */ + for (int i = 0; i < order; i++) + max_residual_value += FFABS(max_sample_value * coefs[i]); + max_residual_value >>= shift; + max_residual_value += max_sample_value; + if (bps > 32) { + if (lpc_encode_with_residual_limit_33bps(res, smp_33bps, len, order, coefs, shift)) + return 1; + } else if (max_residual_value > INT32_MAX) { + if (lpc_encode_with_residual_limit(res, smp, len, order, coefs, shift)) + return 1; + } else if (bps + s->options.lpc_coeff_precision + av_log2(order) <= 32) { + s->flac_dsp.lpc16_encode(res, smp, len, order, coefs, shift); + } else { + s->flac_dsp.lpc32_encode(res, smp, len, order, coefs, shift); + } + return 0; +} + +#define DEFAULT_TO_VERBATIM() \ +{ \ + sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; \ + if (sub->obits <= 32) \ + memcpy(res, smp, n * sizeof(int32_t)); \ + return subframe_count_exact(s, sub, 0); \ +} + static int encode_residual_ch(FlacEncodeContext *s, int ch) { int i, n; @@ -821,28 +1006,38 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) int32_t coefs[MAX_LPC_ORDER][MAX_LPC_ORDER]; int shift[MAX_LPC_ORDER]; int32_t *res, *smp; + int64_t *smp_33bps; - frame = &s->frame; - sub = &frame->subframes[ch]; - res = sub->residual; - smp = sub->samples; - n = frame->blocksize; + frame = &s->frame; + sub = &frame->subframes[ch]; + res = sub->residual; + smp = sub->samples; + smp_33bps = frame->samples_33bps; + n = frame->blocksize; /* CONSTANT */ - for (i = 1; i < n; i++) - if(smp[i] != smp[0]) - break; - if (i == n) { - sub->type = sub->type_code = FLAC_SUBFRAME_CONSTANT; - res[0] = smp[0]; - return subframe_count_exact(s, sub, 0); + if (sub->obits > 32) { + for (i = 1; i < n; i++) + if(smp_33bps[i] != smp_33bps[0]) + break; + if (i == n) { + sub->type = sub->type_code = FLAC_SUBFRAME_CONSTANT; + return subframe_count_exact(s, sub, 0); + } + } else { + for (i = 1; i < n; i++) + if(smp[i] != smp[0]) + break; + if (i == n) { + sub->type = sub->type_code = FLAC_SUBFRAME_CONSTANT; + res[0] = smp[0]; + return subframe_count_exact(s, sub, 0); + } } /* VERBATIM */ if (frame->verbatim_only || n < 5) { - sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; - memcpy(res, smp, n * sizeof(int32_t)); - return subframe_count_exact(s, sub, 0); + DEFAULT_TO_VERBATIM(); } min_order = s->options.min_prediction_order; @@ -859,15 +1054,32 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) opt_order = 0; bits[0] = UINT32_MAX; for (i = min_order; i <= max_order; i++) { - encode_residual_fixed(res, smp, n, i); + if (sub->obits == 33) { + if (encode_residual_fixed_with_residual_limit_33bps(res, smp_33bps, n, i)) + continue; + } else if (sub->obits + i >= 32) { + if (encode_residual_fixed_with_residual_limit(res, smp, n, i)) + continue; + } else + encode_residual_fixed(res, smp, n, i); bits[i] = find_subframe_rice_params(s, sub, i); if (bits[i] < bits[opt_order]) opt_order = i; } + if (opt_order == 0 && bits[0] == UINT32_MAX) { + /* No predictor found with residuals within order = opt_order; sub->type_code = sub->type | sub->order; if (sub->order != max_order) { - encode_residual_fixed(res, smp, n, sub->order); + if (sub->obits == 33) + encode_residual_fixed_with_residual_limit_33bps(res, smp_33bps, n, sub->order); + else if (sub->obits + i >= 32) + encode_residual_fixed_with_residual_limit(res, smp, n, sub->order); + else + encode_residual_fixed(res, smp, n, sub->order); find_subframe_rice_params(s, sub, sub->order); } return subframe_count_exact(s, sub, sub->order); @@ -875,6 +1087,14 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) /* LPC */ sub->type = FLAC_SUBFRAME_LPC; + if (sub->obits == 33) + /* As ff_lpc_calc_coefs is shared with other codecs and the LSB + * probably isn't predictable anyway, throw away LSB for analysis + * so it fits 32 bit int and existing function can be used + * unmodified */ + for (i = 0; i < n; i++) + smp[i] = smp_33bps[i] >> 1; + opt_order = ff_lpc_calc_coefs(&s->lpc_ctx, smp, n, min_order, max_order, s->options.lpc_coeff_precision, coefs, shift, s->options.lpc_type, s->options.lpc_passes, omethod, @@ -895,13 +1115,8 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) order = av_clip(order, min_order - 1, max_order - 1); if (order == last_order) continue; - if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(order) <= 32) { - s->flac_dsp.lpc16_encode(res, smp, n, order+1, coefs[order], - shift[order]); - } else { - s->flac_dsp.lpc32_encode(res, smp, n, order+1, coefs[order], - shift[order]); - } + if(lpc_encode_choose_datapath(s, sub->obits, res, smp, smp_33bps, n, order+1, coefs[order], shift[order])) + continue; bits[i] = find_subframe_rice_params(s, sub, order+1); if (bits[i] < bits[opt_index]) { opt_index = i; @@ -915,11 +1130,8 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) opt_order = 0; bits[0] = UINT32_MAX; for (i = min_order-1; i < max_order; i++) { - if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) { - s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]); - } else { - s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]); - } + if(lpc_encode_choose_datapath(s, sub->obits, res, smp, smp_33bps, n, i+1, coefs[i], shift[i])) + continue; bits[i] = find_subframe_rice_params(s, sub, i+1); if (bits[i] < bits[opt_order]) opt_order = i; @@ -937,11 +1149,8 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) for (i = last-step; i <= last+step; i += step) { if (i < min_order-1 || i >= max_order || bits[i] < UINT32_MAX) continue; - if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) { - s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]); - } else { - s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]); - } + if(lpc_encode_choose_datapath(s, sub->obits, res, smp, smp_33bps, n, i+1, coefs[i], shift[i])) + continue; bits[i] = find_subframe_rice_params(s, sub, i+1); if (bits[i] < bits[opt_order]) opt_order = i; @@ -978,11 +1187,8 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) if (diffsum >8) continue; - if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order - 1) <= 32) { - s->flac_dsp.lpc16_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]); - } else { - s->flac_dsp.lpc32_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]); - } + if(lpc_encode_choose_datapath(s, sub->obits, res, smp, smp_33bps, n, opt_order, lpc_try, shift[opt_order-1])) + continue; score = find_subframe_rice_params(s, sub, opt_order); if (score < best_score) { best_score = score; @@ -999,10 +1205,10 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch) for (i = 0; i < sub->order; i++) sub->coefs[i] = coefs[sub->order-1][i]; - if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order) <= 32) { - s->flac_dsp.lpc16_encode(res, smp, n, sub->order, sub->coefs, sub->shift); - } else { - s->flac_dsp.lpc32_encode(res, smp, n, sub->order, sub->coefs, sub->shift); + if(lpc_encode_choose_datapath(s, sub->obits, res, smp, smp_33bps, n, sub->order, sub->coefs, sub->shift)) { + /* No predictor found with residuals within order); @@ -1069,54 +1275,88 @@ static int encode_frame(FlacEncodeContext *s) static void remove_wasted_bits(FlacEncodeContext *s) { - int ch, i; + int ch, i, wasted_bits; for (ch = 0; ch < s->channels; ch++) { FlacSubframe *sub = &s->frame.subframes[ch]; - int32_t v = 0; - for (i = 0; i < s->frame.blocksize; i++) { - v |= sub->samples[i]; - if (v & 1) - break; - } + if (sub->obits > 32) { + int64_t v = 0; + for (i = 0; i < s->frame.blocksize; i++) { + v |= s->frame.samples_33bps[i]; + if (v & 1) + break; + } + + if (!v || (v & 1)) + return; - if (v && !(v & 1)) { v = ff_ctz(v); + /* If any wasted bits are found, samples are moved + * from frame.samples_33bps to frame.subframes[ch] */ for (i = 0; i < s->frame.blocksize; i++) - sub->samples[i] >>= v; + sub->samples[i] = s->frame.samples_33bps[i] >> v; + wasted_bits = v; + } else { + int32_t v = 0; + for (i = 0; i < s->frame.blocksize; i++) { + v |= sub->samples[i]; + if (v & 1) + break; + } + + if (!v || (v & 1)) + return; - sub->wasted = v; - sub->obits -= v; + v = ff_ctz(v); - /* for 24-bit, check if removing wasted bits makes the range better - suited for using RICE instead of RICE2 for entropy coding */ - if (sub->obits <= 17) - sub->rc.coding_mode = CODING_MODE_RICE; + for (i = 0; i < s->frame.blocksize; i++) + sub->samples[i] >>= v; + wasted_bits = v; } + + sub->wasted = wasted_bits; + sub->obits -= wasted_bits; + + /* for 24-bit, check if removing wasted bits makes the range better + * suited for using RICE instead of RICE2 for entropy coding */ + if (sub->obits <= 17) + sub->rc.coding_mode = CODING_MODE_RICE; } } static int estimate_stereo_mode(const int32_t *left_ch, const int32_t *right_ch, int n, - int max_rice_param) + int max_rice_param, int bps) { int i, best; - int32_t lt, rt; uint64_t sum[4]; uint64_t score[4]; int k; /* calculate sum of 2nd order residual for each channel */ sum[0] = sum[1] = sum[2] = sum[3] = 0; - for (i = 2; i < n; i++) { - lt = left_ch[i] - 2*left_ch[i-1] + left_ch[i-2]; - rt = right_ch[i] - 2*right_ch[i-1] + right_ch[i-2]; - sum[2] += FFABS((lt + rt) >> 1); - sum[3] += FFABS(lt - rt); - sum[0] += FFABS(lt); - sum[1] += FFABS(rt); + if(bps < 30) { + int32_t lt, rt; + for (i = 2; i < n; i++) { + lt = left_ch[i] - 2*left_ch[i-1] + left_ch[i-2]; + rt = right_ch[i] - 2*right_ch[i-1] + right_ch[i-2]; + sum[2] += FFABS((lt + rt) >> 1); + sum[3] += FFABS(lt - rt); + sum[0] += FFABS(lt); + sum[1] += FFABS(rt); + } + } else { + int64_t lt, rt; + for (i = 2; i < n; i++) { + lt = (int64_t)left_ch[i] - 2*(int64_t)left_ch[i-1] + left_ch[i-2]; + rt = (int64_t)right_ch[i] - 2*(int64_t)right_ch[i-1] + right_ch[i-2]; + sum[2] += FFABS((lt + rt) >> 1); + sum[3] += FFABS(lt - rt); + sum[0] += FFABS(lt); + sum[1] += FFABS(rt); + } } /* estimate bit counts */ for (i = 0; i < 4; i++) { @@ -1147,12 +1387,14 @@ static void channel_decorrelation(FlacEncodeContext *s) { FlacFrame *frame; int32_t *left, *right; + int64_t *side_33bps; int i, n; - frame = &s->frame; - n = frame->blocksize; - left = frame->subframes[0].samples; - right = frame->subframes[1].samples; + frame = &s->frame; + n = frame->blocksize; + left = frame->subframes[0].samples; + right = frame->subframes[1].samples; + side_33bps = frame->samples_33bps; if (s->channels != 2) { frame->ch_mode = FLAC_CHMODE_INDEPENDENT; @@ -1161,29 +1403,49 @@ static void channel_decorrelation(FlacEncodeContext *s) if (s->options.ch_mode < 0) { int max_rice_param = (1 << frame->subframes[0].rc.coding_mode) - 2; - frame->ch_mode = estimate_stereo_mode(left, right, n, max_rice_param); + frame->ch_mode = estimate_stereo_mode(left, right, n, max_rice_param, s->avctx->bits_per_raw_sample); } else frame->ch_mode = s->options.ch_mode; /* perform decorrelation and adjust bits-per-sample */ if (frame->ch_mode == FLAC_CHMODE_INDEPENDENT) return; - if (frame->ch_mode == FLAC_CHMODE_MID_SIDE) { - int32_t tmp; - for (i = 0; i < n; i++) { - tmp = left[i]; - left[i] = (tmp + right[i]) >> 1; - right[i] = tmp - right[i]; + if(s->avctx->bits_per_raw_sample == 32) { + if (frame->ch_mode == FLAC_CHMODE_MID_SIDE) { + int64_t tmp; + for (i = 0; i < n; i++) { + tmp = left[i]; + left[i] = (tmp + right[i]) >> 1; + side_33bps[i] = tmp - right[i]; + } + frame->subframes[1].obits++; + } else if (frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) { + for (i = 0; i < n; i++) + side_33bps[i] = (int64_t)left[i] - right[i]; + frame->subframes[1].obits++; + } else { + for (i = 0; i < n; i++) + side_33bps[i] = (int64_t)left[i] - right[i]; + frame->subframes[0].obits++; } - frame->subframes[1].obits++; - } else if (frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) { - for (i = 0; i < n; i++) - right[i] = left[i] - right[i]; - frame->subframes[1].obits++; } else { - for (i = 0; i < n; i++) - left[i] -= right[i]; - frame->subframes[0].obits++; + if (frame->ch_mode == FLAC_CHMODE_MID_SIDE) { + int32_t tmp; + for (i = 0; i < n; i++) { + tmp = left[i]; + left[i] = (tmp + right[i]) >> 1; + right[i] = tmp - right[i]; + } + frame->subframes[1].obits++; + } else if (frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) { + for (i = 0; i < n; i++) + right[i] = left[i] - right[i]; + frame->subframes[1].obits++; + } else { + for (i = 0; i < n; i++) + left[i] -= right[i]; + frame->subframes[0].obits++; + } } } @@ -1232,6 +1494,25 @@ static void write_frame_header(FlacEncodeContext *s) } +static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k) +{ + unsigned v, e; + + v = ((unsigned)(i) << 1) ^ (i >> 31); + + e = (v >> k) + 1; + while (e > 31) { + put_bits(pb, 31, 0); + e -= 31; + } + put_bits(pb, e, 1); + if (k) { + unsigned mask = UINT32_MAX >> (32-k); + put_bits(pb, k, v & mask); + } +} + + static void write_subframes(FlacEncodeContext *s) { int ch; @@ -1252,14 +1533,38 @@ static void write_subframes(FlacEncodeContext *s) /* subframe */ if (sub->type == FLAC_SUBFRAME_CONSTANT) { - put_sbits(&s->pb, sub->obits, res[0]); + if(sub->obits == 33) + put_sbits63(&s->pb, 33, s->frame.samples_33bps[0]); + else if(sub->obits == 32) + put_bits32(&s->pb, res[0]); + else + put_sbits(&s->pb, sub->obits, res[0]); } else if (sub->type == FLAC_SUBFRAME_VERBATIM) { - while (res < frame_end) - put_sbits(&s->pb, sub->obits, *res++); + if (sub->obits == 33) { + int64_t *res64 = s->frame.samples_33bps; + int64_t *frame_end64 = &s->frame.samples_33bps[s->frame.blocksize]; + while (res64 < frame_end64) + put_sbits63(&s->pb, 33, (*res64++)); + } else if (sub->obits == 32) { + while (res < frame_end) + put_bits32(&s->pb, *res++); + } else { + while (res < frame_end) + put_sbits(&s->pb, sub->obits, *res++); + } } else { /* warm-up samples */ - for (i = 0; i < sub->order; i++) - put_sbits(&s->pb, sub->obits, *res++); + if (sub->obits == 33) { + for (i = 0; i < sub->order; i++) + put_sbits63(&s->pb, 33, s->frame.samples_33bps[i]); + res += sub->order; + } else if (sub->obits == 32) { + for (i = 0; i < sub->order; i++) + put_bits32(&s->pb, *res++); + } else { + for (i = 0; i < sub->order; i++) + put_sbits(&s->pb, sub->obits, *res++); + } /* LPC coefficients */ if (sub->type == FLAC_SUBFRAME_LPC) { @@ -1284,7 +1589,7 @@ static void write_subframes(FlacEncodeContext *s) int k = sub->rc.params[p]; put_bits(&s->pb, sub->rc.coding_mode, k); while (res < part_end) - set_sr_golomb_flac(&s->pb, *res++, k, INT32_MAX, 0); + set_sr_golomb_flac(&s->pb, *res++, k); part_end = FFMIN(frame_end, part_end + psize); } } @@ -1332,7 +1637,7 @@ static int update_md5_sum(FlacEncodeContext *s, const void *samples) (const uint16_t *) samples, buf_size / 2); buf = s->md5_buffer; #endif - } else { + } else if (s->avctx->bits_per_raw_sample <= 24) { int i; const int32_t *samples0 = samples; uint8_t *tmp = s->md5_buffer; @@ -1342,6 +1647,15 @@ static int update_md5_sum(FlacEncodeContext *s, const void *samples) AV_WL24(tmp + 3*i, v); } buf = s->md5_buffer; + } else { + /* s->avctx->bits_per_raw_sample <= 32 */ + int i; + const int32_t *samples0 = samples; + uint8_t *tmp = s->md5_buffer; + + for (i = 0; i < s->frame.blocksize * s->channels; i++) + AV_WL32(tmp + 4*i, samples0[i]); + buf = s->md5_buffer; } av_md5_update(s->md5ctx, buf, buf_size); diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h index 4b4f977ad5..4561dc131a 100644 --- a/libavcodec/put_bits.h +++ b/libavcodec/put_bits.h @@ -363,6 +363,13 @@ static inline void put_bits64(PutBitContext *s, int n, uint64_t value) } } +static inline void put_sbits63(PutBitContext *pb, int n, int64_t value) +{ + av_assert2(n >= 0 && n < 64); + + put_bits64(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); +} + /** * Return the pointer to the byte where the bitstream writer will put * the next bit. diff --git a/libavcodec/put_golomb.h b/libavcodec/put_golomb.h index 9ca911fc3c..df47fd2c0a 100644 --- a/libavcodec/put_golomb.h +++ b/libavcodec/put_golomb.h @@ -151,18 +151,4 @@ static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit, set_ur_golomb(pb, v, k, limit, esc_len); } -/** - * write signed golomb rice code (flac). - */ -static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k, - int limit, int esc_len) -{ - int v; - - v = -2 * i - 1; - v ^= (v >> 31); - - set_ur_golomb_jpegls(pb, v, k, limit, esc_len); -} - #endif /* AVCODEC_PUT_GOLOMB_H */ From patchwork Fri Sep 16 20:14:15 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: 37970 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3b1c:b0:96:9ee8:5cfd with SMTP id c28csp1196359pzh; Fri, 16 Sep 2022 13:15:20 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6JoyGY5TMOyCR1R8pqFrtTOtap7cIfGa7yLItAXzqI111JgvB0ffBXbC5gw0WqlfcxDxtX X-Received: by 2002:a17:907:8a04:b0:77c:398c:90fa with SMTP id sc4-20020a1709078a0400b0077c398c90famr4615643ejc.595.1663359319983; Fri, 16 Sep 2022 13:15:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1663359319; cv=none; d=google.com; s=arc-20160816; b=KViI1KV/3GX1Hr1TZ7yASRX2lMd2zow30HxPuLFJzpcDV+xRyJIJpRz1epwINmwIcv WVcHCcFsdq9X8WErR+fG5XTcXlVO6FStL/oxNRnMSBsFXO9Ioav5Z8PlJMDk0o8ZtPsD kzpxqbBo1QPtwaF3IPrFyPUdl2J7p477a5JUBFO6lJ4KIGtZ0VIswNQQM3ZDl9/mFbv1 FjHWh5ZQfkeTK1V0Pzk/IurQhuduMbpFh/G3jpW5bfTgRNUXOMnR4prP5uAdmynAyM10 V/uQaXSoJtWpvr5EZbGeXIxHt12YZHKX13XtRekVxo0graRk82aJ3JmbHb7bTMLymBTq VF+Q== 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:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=msKCww62lZ3dQJmxSXI6rxW+qfodxN1IWHAPlsAe8EE=; b=tl8QU2fMv4Wixlpz3nMq+feIn6XBQxQKxdzVFG0AX9OTsRS4GScc5Ve3W42WDUlXXA hANCOZGLe51ot2J+alVTaAO3H59nngSzmJYp848o9okdAZKa7/wJzu6W1bsHoa0EECv9 1aR6mnFlZIcrPiSbPNhU6ows2hlAupZ57+40/bH9zzXALohccraMldiV9kXomqZfIABI 7GefrIzdIFvLwv0UORe6aGlFx6Y38jXJaaea8WGKzrnBQOV+BoFlkPUdBLbnBsF07Db+ p+hEEHo2ixISAM8Q0XOvUKWiunYlqDgdzYb968c1enBCuwxZffDidwZjKFMESxwXERBP 6HWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=FyD0s+ru; 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 j14-20020a05640211ce00b0043a6e796231si3511465edw.544.2022.09.16.13.15.19; Fri, 16 Sep 2022 13:15:19 -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=FyD0s+ru; 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 6B9BD68BC53; Fri, 16 Sep 2022 23:14:53 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0216A68BC45 for ; Fri, 16 Sep 2022 23:14:45 +0300 (EEST) Received: by mail-ed1-f52.google.com with SMTP id y8so26197805edc.10 for ; Fri, 16 Sep 2022 13:14:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=NNRbks+QKnzDSkeLrfbtYjGrnHB+4v5rMuS6GbBbVYQ=; b=FyD0s+rufq9LFM2sjmUhqrnB31/3nI0gA2hoge2wjWwgYWSg6r1zltEovxZyEDN2NA PwPAWOi/iIpcz7N5DiSZNqqCHro6t0ybcOgH8vAqmEbviuMaPk0RycEqVHl0KXwWsBdN WAtKUEZnBVsaAXxvCx8LI6FV4FZBMwI9Pg28gStHgwG3Cnxg55T7S74jFgcdbtw9XJI7 RiewYyjuwYJ1MOJmmjvF8wsiKU6rYhiUJbo9oc0gzy4mnNeSjvkwMFgqzwAp4crufJb+ K7LG+tNVXR+034d5dDsj7XbxlOkCnJXcQIcCutPnftpOrtJP1e0Gp2rJ5QKsGXZJoeRC Y7aA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=NNRbks+QKnzDSkeLrfbtYjGrnHB+4v5rMuS6GbBbVYQ=; b=2EuYxRkbz7K5Lk9hnoYD/wQu3O/6JMHWw9UferaWvkRXIfPSF89xuydL+L2dyx4BAt d9VBVWjnnWWI+gADNR/GfJmZAfPvoS2fvGQOlnApsprVEmatTbcgu2keTXX9O0pYuJBD rhOatE2uCVPr8ITcmcfSMjzjAhQ7uhQz2qqGm7cTgW9TzbbUsP8BCD3YrfzupkIxdXA4 bwXfmZ6dMDaa/knwNK7ZtCEsZjD+19gp1eqA86X5gm7TIcGQP3z2pj/YIpzHs4staUWz C+I2qWNkh+pu7wY8dHPKapYxSd8kB9bdyYzVbuj1H8Ilb0HTziJiVMJOFXft1qAqtIv9 a/mQ== X-Gm-Message-State: ACrzQf1ULaOwAM5E/foIQuJ5nURpck4QwyNYrH9zqyw+oxODdMBrXuwI 9nYXxYomkeui3aTq23VH3d0NucCWjVqLpQ== X-Received: by 2002:a05:6402:4511:b0:43b:a182:8a0a with SMTP id ez17-20020a056402451100b0043ba1828a0amr5247046edb.410.1663359284167; Fri, 16 Sep 2022 13:14:44 -0700 (PDT) Received: from localhost.localdomain (92-64-99-37.biz.kpn.net. [92.64.99.37]) by smtp.googlemail.com with ESMTPSA id kw4-20020a170907770400b0073dcdf9b0bcsm11112433ejc.17.2022.09.16.13.14.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Sep 2022 13:14:43 -0700 (PDT) From: Martijn van Beurden To: ffmpeg-devel@ffmpeg.org Date: Fri, 16 Sep 2022 22:14:15 +0200 Message-Id: <20220916201415.2583646-4-mvanb1@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220916201415.2583646-1-mvanb1@gmail.com> References: <20220916201415.2583646-1-mvanb1@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v6 3/3] fate/flac: Add test of 32 bps encoding/decoding 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: 1rEIi3kxsTtm --- tests/fate/flac.mak | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/fate/flac.mak b/tests/fate/flac.mak index 115cc965e1..3424b2bf82 100644 --- a/tests/fate/flac.mak +++ b/tests/fate/flac.mak @@ -6,6 +6,7 @@ FATE_FLAC += fate-flac-16-chmode-indep \ fate-flac-16-lpc-cholesky \ fate-flac-16-lpc-levinson \ fate-flac-24-comp-8 \ + fate-flac-32-wasted-bits \ fate-flac-rice-params \ fate-flac-16-chmode-%: OPTS = -ch_mode $(@:fate-flac-16-chmode-%=%) @@ -20,6 +21,9 @@ fate-flac-24-comp-%: OPTS = -compression_level $(@:fate-flac-24-comp-%=%) fate-flac-24-%: REF = $(SAMPLES)/audio-reference/divertimenti_2ch_96kHz_s24.wav fate-flac-24-%: CMD = enc_dec_pcm flac wav s24le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c flac $(OPTS) +fate-flac-32-wasted-bits: REF = $(SAMPLES)/audio-reference/drums_2ch_44kHz_s32_wastedbits.wav +fate-flac-32-wasted-bits: CMD = enc_dec_pcm flac wav s32le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c flac -strict experimental + fate-flac-rice-params: REF = $(SAMPLES)/audio-reference/chorusnoise_2ch_44kHz_s16.wav fate-flac-rice-params: CMD = enc_dec_pcm flac wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c flac