diff --git a/COPYING b/COPYING index a9d8844e42393a8ca9b79fb1cc81aa983b916cc3..0227899c94523ffb16b26e6a85ff55add99123e4 100644 --- a/COPYING +++ b/COPYING @@ -3,7 +3,7 @@ License, included below. This software may be subject to other third party and contributor rights, including patent rights, and no such rights are granted under this license. Â -Copyright (c) 2010-2017, ITU/ISO/IEC +Copyright (c) 2010-2019, ITU/ISO/IEC All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile b/Makefile index d737cd85630e7d19638cf0f2324ca23b86571eb6..d61744bed9a7926118b9107c9e59384d12a3126d 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,8 @@ else UNAME_S := $(shell uname -s) BUILD_CMD := $(BUILD_SCRIPT) ifeq ($(UNAME_S),Linux) + # for Jenkins: run trace build only on Linux + LINUXBUILD := TRUE endif ifeq ($(UNAME_S),Darwin) # MAC @@ -127,6 +129,12 @@ clean-p: configure: $(BUILD_CMD) $(CONFIG_OPTIONS) $(CMAKE_OPTIONS) variant=debug,release,relwithdebinfo +linuxbuild: +ifeq ($(LINUXBUILD),TRUE) + # option for automated jenkins build + $(BUILD_CMD) $(BUILD_JOBS) $(BUILD_OPTIONS) $(CMAKE_OPTIONS) variant=debug +endif + # # project specific targets # diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b695964769c896c17c0b5f6690e79da19d7c0ca3 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +How to build VTM +================ + +The software uses CMake to create platform-specific build files. + +Build instructions for plain CMake (suggested) +---------------------------------------------- + +**Note:** A working CMake installation is required for building the software. + +CMake generates configuration files for the compiler environment/development environment on each platform. +The following is a list of examples for Windows (MS Visual Studio), macOS (Xcode) and Linux (make). + +Open a command prompt on your system and change into the root directory of this project. + +Create a build directory in the root directory: +```bash +mkdir build +``` + +Use one of the following CMake commands, based on your platform. Feel free to change the commands to satisfy +your needs. + +**Windows Visual Studio 2015 64 Bit:** +```bash +cd build +cmake .. -G "Visual Studio 14 2015 Win64" +``` +Then open the generated solution file in MS Visual Studio. + +**macOS Xcode:** +```bash +cd build +cmake .. -G "Xcode" +``` +Then open the generated work space in Xcode. + +**Linux** + +For generating Linux Release Makefile: +```bash +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +``` +For generating Linux Debug Makefile: +```bash +cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug +``` + +Then type +```bash +make -j +``` + +For more details, refer to the CMake documentation: https://cmake.org/cmake/help/latest/ + +Build instructions for make +--------------------------- + +**Note:** The build instructions in this section require the make tool and Python to be installed, which are +part of usual Linux and macOS environments. See below for installation instruction for Python and GnuWin32 +on Windows. + +Open a command prompt on your system and change into the root directory of this project. + +To use the default system compiler simply call: +```bash +make all +``` +For MSYS2 and MinGW: Open an MSYS MinGW 64-Bit terminal and change into the root directory of this project. + +Call: +```bash +make all toolset=gcc +``` + + +Tool Installation on Windows +---------------------------- +Download CMake: http://www.cmake.org/ and install it. + +Python and GnuWin32 are not mandatory, but they simplify the build process for the user. + +python: https://www.python.org/downloads/release/python-371/ + +gnuwin32: https://sourceforge.net/projects/getgnuwin32/files/getgnuwin32/0.6.30/GetGnuWin32-0.6.3.exe/download + +To use MinGW, install MSYS2: http://repo.msys2.org/distrib/msys2-x86_64-latest.exe + +Installation instructions: https://www.msys2.org/ + +Install the needed toolchains: +```bash +pacman -S --needed base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain git subversion mingw-w64-i686-cmake mingw-w64-x86_64-cmake +``` + diff --git a/README.txt b/README.txt deleted file mode 100644 index 8c8f02715a0dac363cb2721636ae51c789eb3184..0000000000000000000000000000000000000000 --- a/README.txt +++ /dev/null @@ -1,65 +0,0 @@ -NextSoftware/VVCSoftware_VTM build howto: - -The software uses cmake to create the needed build files. -Download cmake: http://www.cmake.org/ and install it. - -=================== Windows only ======================= -Python and gnuwin32 are not mandatory, but they simplifiy the build process for the user. -python: https://www.python.org/downloads/release/python-371/ -gnuwin32: https://sourceforge.net/projects/getgnuwin32/files/getgnuwin32/0.6.30/GetGnuWin32-0.6.3.exe/download - -To use MinGW, install MSYS2: -http://repo.msys2.org/distrib/msys2-x86_64-latest.exe - -Installation instructions: -https://www.msys2.org/ - -and install the needed toolchains. -pacman -S --needed base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain git subversion mingw-w64-i686-cmake mingw-w64-x86_64-cmake -======================================================== - -========= Build instructions for plain cmake =========== -Open a command prompt on your system and change into the root directory -of this project (location of README.txt). - -Create a build directory in the root directory: -mkdir build - -After that use one of the following cmake commands. Feel free to change the -commands to satisfy your needs. - -Windows sample for Visual Studio 2015 64 Bit: -cd build -cmake .. -G "Visual Studio 14 2015 Win64" - -Linux Release Makefile sample: -cd build -cmake .. -DCMAKE_BUILD_TYPE=Release - -Linux Debug Makefile sample: -cd build -cmake .. -DCMAKE_BUILD_TYPE=Debug - -MACOSX Xcode sample: -cd build -cmake .. -G "Xcode" -======================================================== - -============= Build instructions for make ============== -remark: -If you installed python and gnuwin32 on Windows operating systems, -you will be able to use make. - -Open a command prompt on your system and change into the root directory -of this project (location of README.txt). - -to use the default system compiler simply call: -make all - -Using MSYS2 and MinGW: -Open an MSYS MinGW 64-Bit terminal and change into the root directory -of this project (location of README.txt). - -Call: -make all toolset=gcc -======================================================== diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index 814bf20d9368cd7c9a6675e9840f2ec1ae4c2e13..c758b49907e00fbea3c9d07cab18b6637904f63e 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -87,7 +87,6 @@ TemporalSubsampleRatio : 8 #============ NEXT ==================== # General -LargeCTU : 1 # Large CTU CTUSize : 128 LCTUFast : 1 QuadtreeTULog2MaxSize : 6 @@ -99,25 +98,31 @@ MinQTNonISlice : 8 MaxBTDepth : 3 MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 -MTT : 1 MTS : 1 MTSIntraMaxCand : 3 MTSInterMaxCand : 4 +SBT : 1 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 LMChroma : 1 # use CCLM only DepQuant : 1 -IMV : 2 +IMV : 1 ALF : 1 IBC : 0 # turned off in CTC +AllowDisFracMMVD : 1 +AffineAmvr : 0 +LumaReshapeEnable : 1 # luma reshaping. 0: disable 1:enable # Fast tools PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 132d9db5c55967284a1d2ee5497da6c44ee39ed5..9673ad33a33e36952002e4ac6fab81aed4f4f8b3 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -103,7 +103,6 @@ CrQpOffset : 1 #============ NEXT ==================== # General -LargeCTU : 1 # Large CTU CTUSize : 128 LCTUFast : 1 QuadtreeTULog2MaxSize : 6 @@ -115,26 +114,32 @@ MinQTNonISlice : 8 MaxBTDepth : 3 MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 -MTT : 1 MTS : 1 MTSIntraMaxCand : 3 MTSInterMaxCand : 4 +SBT : 1 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 LMChroma : 1 # use CCLM only DepQuant : 1 -IMV : 2 +IMV : 1 ALF : 1 MHIntra : 1 IBC : 0 # turned off in CTC +AllowDisFracMMVD : 1 +AffineAmvr : 0 +LumaReshapeEnable : 1 # luma reshaping. 0: disable 1:enable # Fast tools PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 7d8350f9257c2d87be841e0083792ada75bc11b3..81bcc515518a7547262b08e271397e46fccde8ae 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -103,7 +103,6 @@ CrQpOffset : 1 #============ NEXT ==================== # General -LargeCTU : 1 # Large CTU CTUSize : 128 LCTUFast : 1 QuadtreeTULog2MaxSize : 6 @@ -115,29 +114,35 @@ MinQTNonISlice : 8 MaxBTDepth : 3 MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 -MTT : 1 MTS : 1 MTSIntraMaxCand : 3 MTSInterMaxCand : 4 +SBT : 1 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 LMChroma : 1 # use CCLM only DepQuant : 1 -IMV : 2 +IMV : 1 ALF : 1 GBi : 1 GBiFast : 1 MHIntra : 1 Triangle : 1 IBC : 0 # turned off in CTC +AllowDisFracMMVD : 1 +AffineAmvr : 0 +LumaReshapeEnable : 1 # luma reshaping. 0: disable 1:enable # Fast tools PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index f3404e3f2b958461236f98e56e0387d315808658..b15a43887296c87133f8a27371943a48d8aaeea7 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -117,7 +117,6 @@ CrQpOffset : 1 #============ NEXT ==================== # General -LargeCTU : 1 # Large CTU CTUSize : 128 LCTUFast : 1 QuadtreeTULog2MaxSize : 6 @@ -129,17 +128,17 @@ MinQTNonISlice : 8 MaxBTDepth : 3 MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 -MTT : 1 MTS : 1 MTSIntraMaxCand : 3 MTSInterMaxCand : 4 +SBT : 1 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 LMChroma : 1 # use CCLM only DepQuant : 1 -IMV : 2 +IMV : 1 ALF : 1 GBi : 1 GBiFast : 1 @@ -147,12 +146,19 @@ BIO : 1 MHIntra : 1 Triangle : 1 IBC : 0 # turned off in CTC +AllowDisFracMMVD : 1 +AffineAmvr : 1 +LumaReshapeEnable : 1 # luma reshaping. 0: disable 1:enable +DMVR : 1 # Fast tools PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 1 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/per-class/classF.cfg b/cfg/per-class/classF.cfg new file mode 100644 index 0000000000000000000000000000000000000000..52ae3dfa2c608bae4325b0c19695db04bd0ce589 --- /dev/null +++ b/cfg/per-class/classF.cfg @@ -0,0 +1,3 @@ +IBC : 1 +HashME : 1 + diff --git a/doc/Makefile b/doc/Makefile index 084c4f3fdd34c793dea857b04f054dae1638cf10..c1f5a58b96c11088f7c284b98d9ab58f46b1444d 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,8 +6,13 @@ LATEX:=$(shell which xelatex || which pdflatex || which latex) BIBTOOL:=$(shell which bibtool || echo \\\# skipping bibtool ) BIBTOOL_DB=~/mpeg/doc/bib/jctvc.bib +LATEXFLAGS:="-shell-escape" + all: $(DOCNUM).pdf +clean: + rm -fr _minted-software-manual software-manual.bbl software-manual.blg software-manual.lot software-manual.out software-manual.log software-manual.toc software-manual.aux software-manual.pdf + %.aux: %.tex $(LATEX) $(LATEXFLAGS) $< diff --git a/doc/figures/YUView.png b/doc/figures/YUView.png new file mode 100644 index 0000000000000000000000000000000000000000..0b6b81f0954adc8df0fa95e4b10f78c337e2667c Binary files /dev/null and b/doc/figures/YUView.png differ diff --git a/doc/gop-structure-example.pdf b/doc/figures/gop-structure-example.pdf similarity index 100% rename from doc/gop-structure-example.pdf rename to doc/figures/gop-structure-example.pdf diff --git a/doc/figures/raceHorsesShot2MotionVectors.png b/doc/figures/raceHorsesShot2MotionVectors.png new file mode 100644 index 0000000000000000000000000000000000000000..4a35a3928103d6ac5f052bbd5fdacb2ed283b084 Binary files /dev/null and b/doc/figures/raceHorsesShot2MotionVectors.png differ diff --git a/doc/figures/raceHorsesShot3SkipFlag.png b/doc/figures/raceHorsesShot3SkipFlag.png new file mode 100644 index 0000000000000000000000000000000000000000..b4b50ee752d19b94ad1620c5174521e528850785 Binary files /dev/null and b/doc/figures/raceHorsesShot3SkipFlag.png differ diff --git a/doc/jvetdoc.cls b/doc/jvetdoc.cls new file mode 100644 index 0000000000000000000000000000000000000000..bdc22890e30fb89bfc9ac4a60b0b17d920c2af7b --- /dev/null +++ b/doc/jvetdoc.cls @@ -0,0 +1,148 @@ +%% +%% jvetdoc: Copyright (c) 2011 BBC Research & Development +%% All rights reserved. +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% Neither the names of the BBC, ITU, ISO, IEC nor the names of its +%% contributors may be used to endorse or promote products derived from +%% this software without specific prior written permission. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{jvetdoc}[2019/01/31 JVET document class] + +\LoadClassWithOptions{article} + +% typeset using Times New Roman +\RequirePackage{ifxetex} +\ifxetex + % use the correct fonts when using XeTeX + \RequirePackage{fontspec} + \defaultfontfeatures{Mapping=tex-text} + \setmainfont{Times New Roman} +\else + \RequirePackage{times} +\fi + +% expand the margins +\RequirePackage{geometry} +\geometry{tmargin=1.6cm,lmargin=1in,rmargin=2.5cm,bmargin=1in,nohead} + +% require graphicx for loading the logos in the header +\RequirePackage{graphicx} + +% don't number the abstract +\renewenvironment{abstract}{\section*{Abstract}}{} + +% format the date in iso style +\RequirePackage{datetime} +\renewcommand{\dateseparator}{-} +\newdateformat{JVET@yyyymmdddate}{% + \THEYEAR\dateseparator\twodigit{\THEMONTH}\dateseparator\twodigit{\THEDAY}} + +% all pages only have a footer +\RequirePackage{fancyhdr} +\pagestyle{fancy} +\renewcommand{\headrulewidth}{0pt} +\fancyhead{} +\cfoot{\thepage} +\rfoot{Date saved: \JVET@yyyymmdddate\today} + +% macros for document metadata +\RequirePackage[normalem]{ulem} +\def\@jvetdocnum{\uline{xxx}} +\def\@jvetdocstatus{\uline{TODO: Add \texttt{\textbackslash{}jvetdocstatus}}} +\def\@jvetdocpurpose{\uline{TODO: Add \texttt{\textbackslash{}jvetdocpurpose}}} +\def\@jvetdocsource{\uline{TODO: Add \texttt{\textbackslash{}jvetdocsource}}} +\def\@jvetmeeting{\uline{TODO: Add \texttt{\textbackslash{}jvetmeeting}}} +\newcommand{\jvetdocnum}[1]{\def\@jvetdocnum{\mbox{#1}}} +\newcommand{\jvetdocstatus}[1]{\def\@jvetdocstatus{\mbox{#1}}} +\newcommand{\jvetdocpurpose}[1]{\def\@jvetdocpurpose{\mbox{#1}}} +\newcommand{\jvetdocsource}[1]{\def\@jvetdocsource{\mbox{#1}}} +\newcommand{\jvetmeeting}[1]{\def\@jvetmeeting{\mbox{#1}}} + +% affiliation block in the author list +\newenvironment{affiliation}{% + \begin{tabular}[t]{@{}>{\renewcommand{\\}{, }}l@{}}% +}{% + \end{tabular}% +} + +\RequirePackage{array} + +\RequirePackage{ifthen} +\newcounter{jvet@author@column} +\newcommand{\@jvet@switch@author@column}{% + \ifthenelse{\value{jvet@author@column} = 1}{% + % do nothing + }{% + \addtocounter{jvet@author@column}{1}% + & + }% +} + +\newcommand*{\email}[1]{\@jvet@switch@author@column\textit{#1}} +\newcommand*{\tel}[1]{\@jvet@switch@author@column\textrm{#1}} + +% Make a title at the top of the current page. +\renewcommand\maketitle{% + % none of the title is put in the header (it is too difficult to + % make the page match the word style in this case) + \vspace*{-1.7cm} + \begin{raggedright} + \rule{0pt}{0.74cm}% strut incase images aren't loaded + \IfFileExists{logos/itu}{\includegraphics[height=0.74cm]{logos/itu}}{} + \IfFileExists{logos/iso}{\includegraphics[height=0.74cm]{logos/iso}}{} + \IfFileExists{logos/iec}{\includegraphics[height=0.74cm]{logos/iec}}{} + \\ + \textbf{Joint Video Experts Team (JVET)}\\[0ex] + \textbf{of ITU-T SG16 WP3 and ISO/IEC JTC1/SC29/WG11} + \hfill Document: JVET-\@jvetdocnum\\[0ex] + \@jvetmeeting + + \vspace{0.5\baselineskip} + + \newcommand{\@strutb}{\rule{0pt}{2.5ex}} + \begin{tabular}{lp{0.78\textwidth}} + \@strutb \it Title: & \@title \\ + \@strutb \it Status: & \@jvetdocstatus \\ + \@strutb \it Purpose: & \@jvetdocpurpose \\ + \@strutb \it Author(s): & % + \setcounter{jvet@author@column}{0} + \let\@and\\ + \renewcommand{\and}{\@and\setcounter{jvet@author@column}{0}} + \newcommand{\@NLtoPAR}{\renewcommand{\\}{\par}} + \begin{tabular}[t]{@{}>{\@NLtoPAR}p{3in}|>{\@NLtoPAR}p{2in}@{}}% + \@author + \end{tabular}\\ + \@strutb \it Source: & \@jvetdocsource \\ + \end{tabular} + \end{raggedright} + + % draw a short horizontal line to delimit the title from body + {\center\rule{0.35\textwidth}{1pt}\\} +} + +% +\RequirePackage{parskip} +\RequirePackage[compact]{titlesec} +%\titlespacing{\section}{0pt}{*0}{*0} +%\titlespacing{\subsection}{0pt}{*0}{*0} +%\titlespacing{\subsubsection}{0pt}{*0}{*0} + +\titlespacing*{\section} +{0pt}{5ex}{2ex} +\titlespacing*{\subsection} +{0pt}{5ex}{2ex} +\titlespacing*{\subsection} +{0pt}{5ex}{2ex} diff --git a/doc/mainpage.h b/doc/mainpage.h index 4a55ec87e5cc1595a4ecaae6d5fa5e40e18d7d0d..efe90264a414e5bca1df89df715511d12fd8c854 100644 --- a/doc/mainpage.h +++ b/doc/mainpage.h @@ -7,8 +7,8 @@ * * \section Introduction * - * This is the doxygen generated documentation of the HEVC HM reference software. - * + * This is the doxygen generated documentation of the HEVC HM reference software. + * * For detailed information see the sub-pages of this site. * * For information on the <b>subversion repositories</b> and the <b>software manual</b> see @@ -22,7 +22,7 @@ * The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are - * granted under this license. + * granted under this license. * * Copyright (c) 2010-2019, ITU/ISO/IEC * All rights reserved. diff --git a/doc/software-manual.pdf b/doc/software-manual.pdf index 0b4925cf32a94097c096cdc47707a5dbbebe3637..34b144cc8b9a980a393cc3c1a4a8bba40a247126 100644 Binary files a/doc/software-manual.pdf and b/doc/software-manual.pdf differ diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 0cd31316c6225c0c1924a52b909b8e5b26588341..e816dbe34f6722ddf22932558b173a04cfbcabca 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1,4 +1,4 @@ -\documentclass[a4paper,11pt]{jctvcdoc} +\documentclass[a4paper,11pt]{jvetdoc} \usepackage{geometry}[2010/02/12] @@ -22,6 +22,18 @@ \usepackage{algorithm2e} \usepackage{amsmath} +\urlstyle{same} + +% code highlighting +\usepackage{minted,xcolor} +\definecolor{bggray}{gray}{0.95} +\setminted{ +bgcolor=bggray, +xleftmargin=3ex, +breaklines=true, +fontsize=\footnotesize} + + \usepackage[strings]{underscore} \usepackage{csquotes} \MakeOuterQuote{"} @@ -72,7 +84,7 @@ } \newenvironment{OptionTableNoShorthand}[2]{% - \footnotesize + \scriptsize \def\arraystretch{1.8} \clearOptions \begin{longtable}{l<{\makecell[tl]{\optOption}}% @@ -105,7 +117,7 @@ } \newenvironment{SEIListTable}[1]{% - \footnotesize + \scriptsize \def\arraystretch{1.8} \clearOptions \begin{longtable}{c<{\makecell[tl]{\optOption}}% @@ -138,7 +150,7 @@ } \newenvironment{MacroTable}[1]{% - \footnotesize + \scriptsize \def\arraystretch{1.3} \clearOptions \begin{longtable}{lcp{0.5\textwidth}} @@ -166,7 +178,7 @@ \end{longtable} } -\title{HM Software Manual} +\title{VTM Software Manual} \author{% Frank Bossen \email{frank@bossentech.com} @@ -174,36 +186,37 @@ David Flynn \email{dflynn@blackberry.com} \and - Karl Sharman + Xiang Li + \email{xlxiangli@tencent.com} + \and + Karl Sharman \email{karl.sharman@eu.sony.com} \and Karsten S\"uhring \email{karsten.suehring@hhi.fraunhofer.de} } -\jctvcmeeting{} -\jctvcdocnum{Software Manual} -\jctvcdocstatus{Software AHG working document} -\jctvcdocpurpose{Information} -\jctvcdocsource{AHG chairs} +\jvetmeeting{} +\jvetdocnum{Software Manual} +\jvetdocstatus{Software AHG working document} +\jvetdocpurpose{Information} +\jvetdocsource{AHG chairs} \begin{document} \maketitle \begin{abstract} -This document is a user manual describing usage of reference software -for the HEVC project. It applies to version 16.13 -of the software. +This document is a user manual describing usage of the VTM reference software +for the VVC project. It applies to version 4.0 of the software. \end{abstract} \tableofcontents \listoftables - \section{General Information} Reference software is being made available to provide a reference -implementation of the HEVC standard being developed by the Joint -Collaborative Team on Video Coding (JCT-VC) regrouping experts from +implementation of the HEVC standard being developed by the Joint +Video Experts Team (JVET) regrouping experts from ITU-T SG 16 and ISO/IEC SC29 WG11. One of the main goals of the reference software is to provide a basis upon which to conduct experiments in order to determine which coding tools provide desired @@ -211,61 +224,165 @@ coding performance. It is not meant to be a particularly efficient implementation of anything, and one may notice its apparent unsuitability for a particular use. It should not be construed to be a reflection of how complex a production-quality implementation of a -future HEVC standard would be. +future VVC standard would be. This document aims to provide guidance on the usage of the reference software. It is widely suspected to be incomplete and suggestions for improvements are welcome. Such suggestions and general inquiries may be -sent to the general JCT-VC email reflector on -\url{jct-vc@lists.rwth-aachen.de} (registration required). +sent to the general JVET email reflector on +\url{https://lists.rwth-aachen.de/postorius/lists/jvet.lists.rwth-aachen.de/} +(registration required). \subsection*{Bug reporting} -Bugs should be reported on the issue tracker set up at -\url{http://hevc.kw.bbc.co.uk/trac/} +Bugs should be reported on the issue tracker set up at: + +\url{https://jvet.hhi.fraunhofer.de/trac/vvc/} \section{Installation and compilation} -The software may be retrieved from one of the following SVN servers -(mirrored): -\begin{itemize} -\item \url{https://hevc.hhi.fraunhofer.de/svn/svn_HEVCSoftware/} -\item \url{svn://hevc.kw.bbc.co.uk/svn/jctvc-hm/} -\end{itemize} +The software may be retrieved from the GitLab server located at: -Table~\ref{tab:project-files} enumerates various project files that are -provided for development environments. +\url{https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM} + +Table~\ref{tab:project-files} lists the compiler environments and versions +for which building the software is tested. + +Note that the software makes use of C++11 language features, which may not +be available in older compilers. \begin{table}[ht] -\footnotesize -\caption{Available project files} +\caption{Supported compilers} \label{tab:project-files} \centering \begin{tabular}{ll} \hline - \thead{Environment} & - \thead{Location of project file} \\ -% Environment & Location of project file \\ + \thead{Compiler environment} & + \thead{Versions} \\ \hline -MS Visual Studio 2008 (VC9) & build/HM_vc9.sln \\ -MS Visual Studio 2010 (VC10) & build/HM_vc2010.sln \\ -MS Visual Studio 2012 (VC11) & build/HM_vc2012.sln \\ -MS Visual Studio 2013 (VC12) & build/HM_vc2013.sln \\ -Xcode & HM.xcodeproj \\ -Eclipse & .project .cproject \\ -make/gcc (e.g. Linux) & build/linux/makefile \\ +MS Visual Studio & 2015 and 2017 \\ +GCC & 5.4 and 7.3 \\ +Xcode/clang & latest \\ \hline \end{tabular} \end{table} -For encoding large picture sizes (like UHDTV) it is strongly advised to build 64-bit -binaries and to use a 64-bit OS. This will allow the software to use more than 2GB of RAM. +By default the software is built as 64-bit binaries to be used on a 64-bit OS. +This allows the software to use more than 2GB of RAM. + +The software uses CMake to create platform-specific build files. + +\subsection {Build instructions for plain CMake (suggested)} + +\textbf{Note:} A working CMake installation is required for building the software. + +CMake generates configuration files for the compiler environment/development +environment on each platform. The following is a list of examples for Windows +(MS Visual Studio), macOS (Xcode) and Linux (make). + +Open a command prompt on your system and change into the root directory +of this project. + +Create a build directory in the root directory: +\begin{minted}{bash} +mkdir build +\end{minted} +Use one of the following CMake commands, based on your platform. Feel free to change the +commands to satisfy your needs. + +\textbf{Windows Visual Studio 2015 64 Bit:} +\begin{minted}{bash} +cd build +cmake .. -G "Visual Studio 14 2015 Win64" +\end{minted} +Then open the generated solution file in MS Visual Studio. + +\textbf{macOS Xcode:} +\begin{minted}{bash} +cd build +cmake .. -G "Xcode" +\end{minted} +Then open the generated work space in Xcode. + +\textbf{Linux} + +For generating Linux Release Makefile: +\begin{minted}{bash} +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +\end{minted} +For generating Linux Debug Makefile: +\begin{minted}{bash} +cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug +\end{minted} +Then type +\begin{minted}{bash} +make -j +\end{minted} +to build the software. + +For more details, refer to the CMake documentation: \url{https://cmake.org/cmake/help/latest/} + +\subsection {Build instructions for make} + +\textbf{Note:} +The build instructions in this section require the make tool and Python +to be installed, which are part of usual Linux and macOS environments. +See section \ref{windowsinstall} for installation instruction for Python +and GnuWin32 on Windows. + +Open a command prompt on your system and change into the root directory +of this project. + +To use the default system compiler simply call: +\begin{minted}{bash} +make all +\end{minted} +For MSYS2 and MinGW: +Open an MSYS MinGW 64-Bit terminal and change into the root directory +of this project. + +Call: +\begin{minted}{bash} +make all toolset=gcc +\end{minted} + +\subsection{Tool Installation on Windows} +\label{windowsinstall} + +Download CMake: \url{http://www.cmake.org/} and install it. + +Python and GnuWin32 are not mandatory, but they simplify the build process for the user. + +\begin{table}[ht] +\footnotesize +\centering +\begin{tabular}{ll} +\hline +Python & \url{https://www.python.org/downloads/release/python-371/} \\ +GnuWin32 & \url{https://sourceforge.net/projects/getgnuwin32/files/getgnuwin32/0.6.30/GetGnuWin32-0.6.3.exe/download} \\ +\hline +\end{tabular} +\end{table} + +To use MinGW, install MSYS2: +\url{http://repo.msys2.org/distrib/msys2-x86_64-latest.exe} + +Installation instructions: +\url{https://www.msys2.org/} + +Install the needed toolchains: +\begin{minted}{bash} +pacman -S --needed base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain git subversion mingw-w64-i686-cmake mingw-w64-x86_64-cmake +\end{minted} %%%% %%%% %%%% \section{Using the encoder} -\begin{verbatim} + +\begin{minted}{bash} TAppEncoder [--help] [-c config.cfg] [--parameter=value] -\end{verbatim} +\end{minted} \begin{table}[ht] \footnotesize @@ -417,7 +534,7 @@ its list of reference pictures is \verb|-1 1|. \caption{A GOP structure} \label{fig:gop-example} \centering -\includegraphics[width=0.7\textwidth]{gop-structure-example} +\includegraphics[width=0.7\textwidth]{figures/gop-structure-example} \end{figure} Inter RPS prediction may be used for Frame2, Frame3 and Frame4, hence @@ -1914,6 +2031,63 @@ RCInitialCpbFullness should be smaller than or equal to 1. \\ \end{OptionTableNoShorthand} + + +%% +%% Encoder debug parameters +%% +\begin{OptionTableNoShorthand}{Encoder debug parameters}{tab:encoder-debugging} + +\Option{DebugBitstream/DecodeBitstream1} & +%\ShortOption{\None} & +\Default{} & +Specifies the first bit stream to be read until a pre-defined switch point is encountered. +\\ + +\Option{DecodeBitstream2} & +%\ShortOption{\None} & +\Default{} & +Specifies the second bit stream, to be read after the first random access point after a QP switch point (specified using SwitchPOC and SwitchQP). +\\ + +\Option{DebugPOC} & +%\ShortOption{\None} & +\Default{-1} & +Specifies a POC, at which a bit stream specified using DebugBitstream or DecodeBitstream1 is no longer read, but rather normal encoding is started. +\\ + +\Option{DebugCTU} & +%\ShortOption{\None} & +\Default{-1} & +When the POC is encountered at which normal encoding is to be resumed, if set, this option specifies that CTUs up to the specified CTU(in raster scan addressing order are to be read from the specified bit stream, after which normal encoding is started the specified CTU. +\\ + +\Option{SwitchPOC} & +%\ShortOption{\None} & +\Default{-1} & +Specifies a POC, at which the specified bit stream is no longer read, but rather normal encoding is started. +\\ + +\Option{SwitchDQP} & +%\ShortOption{\None} & +\Default{0} & +Specifies a QP offset to be applied when normal encoding is started as specified by SwitchPOC. +\\ + +\Option{FastForwardToPOC} & +%\ShortOption{\None} & +\Default{0} & +When encoding a bit streams, all frames that are not references including transitive references to the specified POC are skipped. +\\ +\Option{StopAfterFFtoPOC} & +%\ShortOption{\None} & +\Default{false} & +If enabled, causes the encoder to not encode any frame after the frame specified by FastForwardToPOC option, in encoding order. +\\ +\end{OptionTableNoShorthand} + + + %% %% VUI parameters %% @@ -2879,9 +3053,9 @@ Numerous constants that guard individual adoptions are defined within \clearpage \section{Using the decoder} \subsection{General} -\begin{verbatim} +\begin{minted}{bash} TAppDecoder -b str.bin -o dec.yuv [options] -\end{verbatim} +\end{minted} \begin{OptionTableNoShorthand}{Decoder options}{tab:decoder-options} \Option{(--help)} & @@ -3032,7 +3206,7 @@ way, which in turn can be loaded into a suitable YUV player for overlay of the reconstructed YUV sequence, or can be used for statistical analysis at a selectable scope (e.g. block/picture/sequence level). An example implementation for such visualization is available with the open-source YUView player -(https://github.com/IENT/YUView). +(\url{https://github.com/IENT/YUView}). \subsection{Usage} @@ -3070,7 +3244,7 @@ Specifies which traces should be saved, and for which POCs. \end{OptionTableNoShorthand} Concrete examples of calls for generating a block statistics file are: -\begin{verbatim} +\begin{minted}{bash} bin/DecoderAppStatic -b str/BasketballDrive_1920x1080_QP37.vvc \ --TraceFile="stats/BasketballDrive_1920x1080_QP37_coded.vtmbmsstats" \ --TraceRule="D_BLOCK_STATISTICS_CODED:poc>=0" @@ -3078,7 +3252,7 @@ bin/DecoderAppStatic -b str/BasketballDrive_1920x1080_QP37.vvc \ bin/DecoderAppStatic -b str/BasketballDrive_1920x1080_QP37.vvc \ --TraceFile="stats/BasketballDrive_1920x1080_QP37_all.vtmbmsstats" \ --TraceRule="D_BLOCK_STATISTICS_ALL:poc>=0" -\end{verbatim} +\end{minted} \subsection{Block statistics file formats} @@ -3187,16 +3361,16 @@ In order to add further block statistics, do the following: \begin{description} \item[source/Lib/CommonLib/dtrace_blockstatistics.h] Add your statistic to the BlockStatistic enum: -\begin{verbatim} +\begin{minted}{c++} enum class BlockStatistic { // general PredMode, PartSize, Depth, -\end{verbatim} +\end{minted} Further, add your statistic to the map blockstatistic2description: -\begin{verbatim} +\begin{minted}{c++} static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType, std::string>> blockstatistic2description = @@ -3211,7 +3385,7 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType, std::string> {"MVL0", BlockStatisticType::Vector, "Scale: 4"}}, YOURS -\end{verbatim} +\end{minted} \item[source/Lib/CommonLib/dtrace_blockstatistics.cpp] All code for @@ -3219,28 +3393,28 @@ static const std::map<BlockStatistic, getAndStoreBlockStatistics. This function is called once for each CTU, after it has been en/decoded. The following macros have been defined to facilitate writing of block statistics: -\begin{verbatim} +\begin{minted}{c++} DTRACE_BLOCK_SCALAR(ctx,channel,cs_cu_pu,stat_type,val) DTRACE_BLOCK_SCALAR_CHROMA(ctx,channel,cs_cu_pu,stat_type,val) DTRACE_BLOCK_VECTOR(ctx,channel,cu_pu,stat_type,v_x,v_y) DTRACE_BLOCK_AFFINETF(ctx,channel,pu,stat_type,v_x0,v_y0,v_x1,v_y1,v_x2,v_y2) -\end{verbatim} +\end{minted} An example: -\begin{verbatim} +\begin{minted}{c++} DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::PredMode), cu.predMode); -\end{verbatim} +\end{minted} \item[Block statistics for debugging] The statistics can also be used to write out other data, not just syntax elements. Add your statistics to dtrace_blockstatistics.h. Where it should be used the following headers have to be included: -\begin{verbatim} +\begin{minted}{c++} #include "dtrace_next.h" #include "dtrace_blockstatistics.h" -\end{verbatim} +\end{minted} \end{description} \end{document} diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 6afd8db7333f1376da1346246b9cd70f6ae5befa..26753f9411d84dc9fa783fe02ec8c699d18b9206 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -215,20 +215,14 @@ void EncApp::xInitLibCfg() m_cEncLib.setMinQTSizes ( m_uiMinQT ); m_cEncLib.setMaxBTDepth ( m_uiMaxBTDepth, m_uiMaxBTDepthI, m_uiMaxBTDepthIChroma ); m_cEncLib.setDualITree ( m_dualTree ); - m_cEncLib.setLargeCTU ( m_LargeCTU ); m_cEncLib.setSubPuMvpMode ( m_SubPuMvpMode ); m_cEncLib.setAffine ( m_Affine ); m_cEncLib.setAffineType ( m_AffineType ); m_cEncLib.setBIO (m_BIO); - m_cEncLib.setDisableMotionCompression ( m_DisableMotionCompression ); - m_cEncLib.setMTTMode ( m_MTT ); m_cEncLib.setUseLMChroma ( m_LMChroma ); #if JVET_M0142_CCLM_COLLOCATED_CHROMA m_cEncLib.setCclmCollocatedChromaFlag ( m_cclmCollocatedChromaFlag ); #endif -#if ENABLE_WPP_PARALLELISM - m_cEncLib.setUseAltDQPCoding ( m_AltDQPCoding ); -#endif #if JVET_M0464_UNI_MTS m_cEncLib.setIntraMTS ( m_MTS & 1 ); m_cEncLib.setIntraMTSMaxCand ( m_MTSIntraMaxCand ); @@ -239,6 +233,12 @@ void EncApp::xInitLibCfg() m_cEncLib.setFastIntraEMT ( m_FastEMT & m_EMT & 1 ); m_cEncLib.setInterEMT ( ( m_EMT >> 1 ) & 1 ); m_cEncLib.setFastInterEMT ( ( m_FastEMT >> 1 ) & ( m_EMT >> 1 ) & 1 ); +#endif +#if JVET_M0303_IMPLICIT_MTS + m_cEncLib.setImplicitMTS ( m_MTSImplicit ); +#endif +#if JVET_M0140_SBT + m_cEncLib.setUseSBT ( m_SBT ); #endif m_cEncLib.setUseCompositeRef ( m_compositeRefEnabled ); m_cEncLib.setUseGBi ( m_GBi ); @@ -254,10 +254,25 @@ void EncApp::xInitLibCfg() m_cEncLib.setLadfIntervalLowerBound(m_LadfIntervalLowerBound[k], k); } } -#endif +#endif m_cEncLib.setUseMHIntra ( m_MHIntra ); m_cEncLib.setUseTriangle ( m_Triangle ); +#if JVET_M0253_HASH_ME + m_cEncLib.setUseHashME ( m_HashME ); +#endif +#if JVET_M0255_FRACMMVD_SWITCH + m_cEncLib.setAllowDisFracMMVD ( m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + m_cEncLib.setUseAffineAmvr ( m_AffineAmvr ); +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_cEncLib.setUseAffineAmvrEncOpt ( m_AffineAmvrEncOpt ); +#endif +#if JVET_M0147_DMVR + m_cEncLib.setDMVR ( m_DMVR ); +#endif m_cEncLib.setIBCMode ( m_IBCMode ); m_cEncLib.setIBCLocalSearchRangeX ( m_IBCLocalSearchRangeX ); m_cEncLib.setIBCLocalSearchRangeY ( m_IBCLocalSearchRangeY ); @@ -534,6 +549,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setForceDecodeBitstream1 ( m_forceDecodeBitstream1 ); m_cEncLib.setStopAfterFFtoPOC ( m_stopAfterFFtoPOC ); m_cEncLib.setBs2ModPOCAndType ( m_bs2ModPOCAndType ); +#if JVET_M0055_DEBUG_CTU + m_cEncLib.setDebugCTU ( m_debugCTU ); +#endif #if ENABLE_SPLIT_PARALLELISM m_cEncLib.setNumSplitThreads ( m_numSplitThreads ); m_cEncLib.setForceSingleSplitThread ( m_forceSplitSequential ); @@ -545,6 +563,12 @@ void EncApp::xInitLibCfg() #endif m_cEncLib.setUseALF ( m_alf ); +#if JVET_M0427_INLOOP_RESHAPER + m_cEncLib.setReshaper ( m_lumaReshapeEnable ); + m_cEncLib.setReshapeSignalType ( m_reshapeSignalType ); + m_cEncLib.setReshapeIntraCMD ( m_intraCMD ); + m_cEncLib.setReshapeCW ( m_reshapeCW ); +#endif } void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 10241f5caae994d3e4c68d692541232a9ccedee5..c3c44085eabd364146d58f33b8c248b232570210 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -799,7 +799,6 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("InterlacedSource", m_interlacedSourceFlag, false, "Indicate that source is interlaced") ("NonPackedSource", m_nonPackedConstraintFlag, false, "Indicate that source does not contain frame packing") ("FrameOnly", m_frameOnlyConstraintFlag, false, "Indicate that the bitstream contains only frames") - ("MTT", m_MTT, 0u, "Multi type tree type (0: off, 1:QTBT + triple split) [default: 0]") ("CTUSize", m_uiCTUSize, 128u, "CTUSize (specifies the CTU size if QTBT is on) [default: 128]") ("EnablePartitionConstraintsOverride", m_SplitConsOverrideEnabledFlag, true, "Enable partition constraints override") ("MinQTISlice", m_uiMinQT[0], 8u, "MinQTISlice") @@ -811,20 +810,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("MaxBTDepthISliceL", m_uiMaxBTDepthI, 3u, "MaxBTDepthISliceL") ("MaxBTDepthISliceC", m_uiMaxBTDepthIChroma, 3u, "MaxBTDepthISliceC") ("DualITree", m_dualTree, false, "Use separate QTBT trees for intra slice luma and chroma channel types") - ("LargeCTU", m_LargeCTU, false, "Enable large CTU (0:off, 1:on) [default: off]") ("SubPuMvp", m_SubPuMvpMode, 0, "Enable Sub-PU temporal motion vector prediction (0:off, 1:ATMVP, 2:STMVP, 3:ATMVP+STMVP) [default: off]") ("Affine", m_Affine, false, "Enable affine prediction (0:off, 1:on) [default: off]") ("AffineType", m_AffineType, true, "Enable affine type prediction (0:off, 1:on) [default: on]" ) ("BIO", m_BIO, false, "Enable bi-directional optical flow") - ("DisableMotCompression", m_DisableMotionCompression, false, "Disable motion data compression for all modes") - ("IMV", m_ImvMode, 2, "Adaptive MV precision Mode (IMV)\n" - "\t0: disabled IMV\n" - "\t1: IMV default (Full-Pel)\n" - "\t2: IMV Full-Pel and 4-PEL\n") + ("IMV", m_ImvMode, 1, "Adaptive MV precision Mode (IMV)\n" + "\t0: disabled\n" + "\t1: enabled (Full-Pel and 4-PEL)\n") ("IMV4PelFast", m_Imv4PelFast, 1, "Fast 4-Pel Adaptive MV precision Mode 0:disabled, 1:enabled) [default: 1]") -#if ENABLE_WPP_PARALLELISM - ("AltDQPCoding", m_AltDQPCoding, false, "Improved predictive delta-QP coding (0:off, 1:on) [default: off]") -#endif ("LMChroma", m_LMChroma, 1, " LMChroma prediction " "\t0: Disable LMChroma\n" "\t1: Enable LMChroma\n") @@ -852,6 +845,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) "\t1: Enable fast methods only for Intra EMT\n" "\t2: Enable fast methods only for Inter EMT\n" "\t3: Enable fast methods for both Intra & Inter EMT\n") +#endif +#if JVET_M0303_IMPLICIT_MTS + ("MTSImplicit", m_MTSImplicit, 0, "Enable implicit MTS (when explicit MTS is off)\n") +#endif +#if JVET_M0140_SBT + ( "SBT", m_SBT, false, "Enable Sub-Block Transform for inter blocks\n" ) #endif ("CompositeLTReference", m_compositeRefEnabled, false, "Enable Composite Long Term Reference Frame") ("GBi", m_GBi, false, "Enable Generalized Bi-prediction(GBi)") @@ -864,7 +863,22 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif ("MHIntra", m_MHIntra, false, "Enable MHIntra mode") ("Triangle", m_Triangle, false, "Enable triangular shape motion vector prediction (0:off, 1:on)") +#if JVET_M0253_HASH_ME + ("HashME", m_HashME, false, "Enable hash motion estimation (0:off, 1:on)") +#endif +#if JVET_M0255_FRACMMVD_SWITCH + ("AllowDisFracMMVD", m_allowDisFracMMVD, false, "Disable fractional MVD in MMVD mode adaptively") +#endif +#if JVET_M0246_AFFINE_AMVR + ("AffineAmvr", m_AffineAmvr, false, "Eanble AMVR for affine inter mode") +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + ("AffineAmvrEncOpt", m_AffineAmvrEncOpt, false, "Enable encoder optimization of affine AMVR") +#endif +#if JVET_M0147_DMVR + ("DMVR", m_DMVR, false, "Decoder-side Motion Vector Refinement") +#endif ( "IBC", m_IBCMode, 0u, "IBCMode (0x1:enabled, 0x0:disabled) [default: disabled]") ( "IBCLocalSearchRangeX", m_IBCLocalSearchRangeX, 128u, "Search range of IBC local search in x direction") ( "IBCLocalSearchRangeY", m_IBCLocalSearchRangeY, 128u, "Search range of IBC local search in y direction") @@ -877,7 +891,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("WrapAroundOffset", m_wrapAroundOffset, 0u, "Offset in luma samples used for computing the horizontal wrap-around position") // ADD_NEW_TOOL : (encoder app) add parsing parameters here - +#if JVET_M0427_INLOOP_RESHAPER + ("LumaReshapeEnable", m_lumaReshapeEnable, false, "Enable Reshaping for Luma Channel") + ("ReshapeSignalType", m_reshapeSignalType, 0u, "Input signal type: 0: SDR, 1:PQ, 2:HLG") + ("IntraCMD", m_intraCMD, 0u, "IntraChroma MD: 0: none, 1:fixed to default wPSNR weight") +#endif ("LCTUFast", m_useFastLCTU, false, "Fast methods for large CTU") ("FastMrg", m_useFastMrg, false, "Fast methods for inter merge") ("PBIntraFast", m_usePbIntraFast, false, "Fast assertion if the intra mode is probable") @@ -1287,6 +1305,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("ForceSingleSplitThread", m_forceSplitSequential, false, "Force single thread execution even if taking the parallelized path") ("NumWppThreads", m_numWppThreads, 1, "Number of threads used to run WPP-style parallelization") ("NumWppExtraLines", m_numWppExtraLines, 0, "Number of additional wpp lines to switch when threads are blocked") +#if JVET_M0055_DEBUG_CTU + ("DebugCTU", m_debugCTU, -1, "If DebugBitstream is present, load frames up to this POC from this bitstream. Starting with DebugPOC-frame at CTUline containin debug CTU.") +#endif #if ENABLE_WPP_PARALLELISM ("EnsureWppBitEqual", m_ensureWppBitEqual, true, "Ensure the results are equal to results with WPP-style parallelism, even if WPP is off") #else @@ -1310,13 +1331,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) po::ErrorReporter err; const list<const char*>& argv_unhandled = po::scanArgv(opts, argc, (const char**) argv, err); - if (m_compositeRefEnabled) + if (m_compositeRefEnabled) { - for (int i = 0; i < m_iGOPSize; i++) + for (int i = 0; i < m_iGOPSize; i++) { m_GOPList[i].m_POC *= 2; m_GOPList[i].m_deltaRPS *= 2; - for (int j = 0; j < m_GOPList[i].m_numRefPics; j++) + for (int j = 0; j < m_GOPList[i].m_numRefPics; j++) { m_GOPList[i].m_referencePics[j] *= 2; } @@ -1831,6 +1852,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if JVET_M0427_INLOOP_RESHAPER + m_reshapeCW.binCW.resize(3); + m_reshapeCW.rspFps = m_iFrameRate; + m_reshapeCW.rspIntraPeriod = m_iIntraPeriod; + m_reshapeCW.rspPicSize = m_iSourceWidth*m_iSourceHeight; + m_reshapeCW.rspFpsToIp = std::max(16, 16 * (int)(round((double)m_iFrameRate /16.0))); + m_reshapeCW.rspBaseQP = m_iQP; +#endif #if ENABLE_TRACING g_trace_ctx = tracing_init(sTracingFile, sTracingRule); if( bTracingChannelsList && g_trace_ctx ) @@ -1861,9 +1890,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } #else #if QP_SWITCHING_FOR_PARALLEL - if( m_LargeCTU && ( m_iQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) ) + if( ( m_iQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) ) #else - if( m_LargeCTU && ( ( int ) m_fQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) ) + if( ( ( int ) m_fQP < 38 ) && ( m_iGOPSize > 4 ) && m_bUsePerceptQPA && !m_bUseAdaptiveQP && ( m_iSourceHeight <= 1280 ) && ( m_iSourceWidth <= 2048 ) ) #endif { msg( WARNING, "*************************************************************************\n" ); @@ -1940,11 +1969,11 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_numWppThreads > 1, "WPP-style parallelization only supported with NEXT profile" ); #endif xConfirmPara( m_LMChroma, "LMChroma only allowed with NEXT profile" ); - xConfirmPara( m_LargeCTU, "Large CTU is only allowed with NEXT profile" ); - xConfirmPara( m_DisableMotionCompression, "Disable motion data compression only allowed with NEXT profile" ); - xConfirmPara( m_MTT, "Multi type tree is only allowed with NEXT profile" ); xConfirmPara( m_ImvMode, "IMV is only allowed with NEXT profile" ); xConfirmPara(m_IBCMode, "IBC Mode only allowed with NEXT profile"); +#if JVET_M0253_HASH_ME + xConfirmPara( m_HashME, "Hash motion estimation only allowed with NEXT profile" ); +#endif xConfirmPara( m_useFastLCTU, "Fast large CTU can only be applied when encoding with NEXT profile" ); #if JVET_M0464_UNI_MTS xConfirmPara( m_MTS, "MTS only allowed with NEXT profile" ); @@ -1958,13 +1987,13 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_GBi, "GBi is only allowed with NEXT profile" ); xConfirmPara( m_GBiFast, "GBiFast is only allowed with NEXT profile" ); xConfirmPara( m_Triangle, "Triangle is only allowed with NEXT profile" ); +#if JVET_M0147_DMVR + xConfirmPara(m_DMVR, "DMVR only allowed with NEXT profile"); +#endif // ADD_NEW_TOOL : (parameter check) add a check for next tools here } else { -#if ENABLE_WPP_PARALLELISM - xConfirmPara( !m_AltDQPCoding && ( m_numWppThreads + m_numWppExtraLines ) > 1, "Wavefront parallel encoding only supported with AltDQPCoding" ); -#endif if( m_depQuantEnabledFlag ) { xConfirmPara( !m_useRDOQ || !m_useRDOQTS, "RDOQ and RDOQTS must be equal to 1 if dependent quantization is enabled" ); @@ -2021,8 +2050,8 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_useAMaxBT && !m_SplitConsOverrideEnabledFlag, "AMaxBt can only be used with PartitionConstriantsOverride enabled" ); - - + + xConfirmPara(m_bitstreamFileName.empty(), "A bitstream file name must be specified (BitstreamFile)"); const uint32_t maxBitDepth=(m_chromaFormatIDC==CHROMA_400) ? m_internalBitDepth[CHANNEL_TYPE_LUMA] : std::max(m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA]); xConfirmPara(m_bitDepthConstraint<maxBitDepth, "The internalBitDepth must not be greater than the bitDepthConstraint value"); @@ -2224,6 +2253,30 @@ bool EncAppCfg::xCheckParameter() #if SHARP_LUMA_DELTA_QP xConfirmPara( m_lumaLevelToDeltaQPMapping.mode && m_uiDeltaQpRD > 0, "Luma-level-based Delta QP cannot be used together with slice level multiple-QP optimization\n" ); #endif +#if JVET_M0427_INLOOP_RESHAPER + if (m_lumaLevelToDeltaQPMapping.mode && m_lumaReshapeEnable) + { + msg(WARNING, "For HDR-PQ, reshaper should be used mutual-exclusively with Luma-level-based Delta QP. If use luma DQP, turn reshaper off.\n"); + m_lumaReshapeEnable = false; + } + if (!m_lumaReshapeEnable) + { + m_reshapeSignalType = RESHAPE_SIGNAL_NULL; + m_intraCMD = 0; + } + if (m_lumaReshapeEnable && m_reshapeSignalType == RESHAPE_SIGNAL_PQ) + { + m_intraCMD = 1; + } + else if (m_lumaReshapeEnable && m_reshapeSignalType == RESHAPE_SIGNAL_SDR) + { + m_intraCMD = 0; + } + else + { + m_lumaReshapeEnable = false; + } +#endif xConfirmPara( m_cbQpOffset < -12, "Min. Chroma Cb QP Offset is -12" ); xConfirmPara( m_cbQpOffset > 12, "Max. Chroma Cb QP Offset is 12" ); @@ -2262,13 +2315,6 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_quadtreeTULog2MinSize < 2, "QuadtreeTULog2MinSize must be 2 or greater." ); - if( !m_LargeCTU ) - { - xConfirmPara( m_uiMaxCUHeight > 64, "CTU bigger than 64 only allowed with large CTU." ); - xConfirmPara( m_uiMaxCUWidth > 64, "CTU bigger than 64 only allowed with large CTU." ); - xConfirmPara( m_uiCTUSize > 64, "CTU bigger than 64 only allowed with large CTU." ); - } - if( m_profile == Profile::NEXT ) { xConfirmPara( m_quadtreeTULog2MaxSize > 7, "QuadtreeTULog2MaxSize must be 7 or smaller." ); @@ -2301,9 +2347,15 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_MTS < 0 || m_MTS > 3, "MTS must be greater than 0 smaller than 4" ); xConfirmPara( m_MTSIntraMaxCand < 0 || m_MTSIntraMaxCand > 5, "m_MTSIntraMaxCand must be greater than 0 and smaller than 6" ); xConfirmPara( m_MTSInterMaxCand < 0 || m_MTSInterMaxCand > 5, "m_MTSInterMaxCand must be greater than 0 and smaller than 6" ); +#if JVET_M0303_IMPLICIT_MTS + xConfirmPara( m_MTS != 0 && m_MTSImplicit != 0, "Both explicit and implicit MTS cannot be enabled at the same time" ); +#endif #else xConfirmPara( m_EMT < 0 || m_EMT >3, "EMT must be 0, 1, 2 or 3" ); xConfirmPara( m_FastEMT < 0 || m_FastEMT >3, "FEMT must be 0, 1, 2 or 3" ); +#if JVET_M0303_IMPLICIT_MTS + xConfirmPara( m_EMT != 0 && m_MTSImplicit != 0, "Both explicit and implicit MTS cannot be enabled at the same time" ); +#endif #endif if( m_usePCM) { @@ -2887,7 +2939,7 @@ bool EncAppCfg::xCheckParameter() #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI xConfirmPara(m_preferredTransferCharacteristics > 255, "transfer_characteristics_idc should not be greater than 255."); #endif - xConfirmPara( unsigned(m_ImvMode) > 2, "ImvMode exceeds range (0 to 2)" ); + xConfirmPara( unsigned(m_ImvMode) > 1, "ImvMode exceeds range (0 to 1)" ); xConfirmPara( m_decodeBitstreams[0] == m_bitstreamFileName, "Debug bitstream and the output bitstream cannot be equal.\n" ); xConfirmPara( m_decodeBitstreams[1] == m_bitstreamFileName, "Decode2 bitstream and the output bitstream cannot be equal.\n" ); xConfirmPara(unsigned(m_LMChroma) > 1, "LMMode exceeds range (0 to 1)"); @@ -3127,14 +3179,8 @@ void EncAppCfg::xPrintParameter() } msg(VERBOSE, "SubPuMvp:%d+%d ", m_SubPuMvpMode & 1, (m_SubPuMvpMode & 2) == 2); msg( VERBOSE, "DualITree:%d ", m_dualTree ); - msg( VERBOSE, "LargeCTU:%d ", m_LargeCTU ); msg( VERBOSE, "IMV:%d ", m_ImvMode ); msg( VERBOSE, "BIO:%d ", m_BIO ); - msg( VERBOSE, "DisMDC:%d ", m_DisableMotionCompression ); - msg( VERBOSE, "MTT:%d ", m_MTT ); -#if ENABLE_WPP_PARALLELISM - msg( VERBOSE, "AltDQPCoding:%d ", m_AltDQPCoding ); -#endif msg( VERBOSE, "LMChroma:%d ", m_LMChroma ); #if JVET_M0142_CCLM_COLLOCATED_CHROMA if( m_LMChroma && m_chromaFormatIDC == CHROMA_420 ) @@ -3146,6 +3192,9 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "MTS: %1d(intra) %1d(inter) ", m_MTS & 1, ( m_MTS >> 1 ) & 1 ); #else msg( VERBOSE, "EMT: %1d(intra) %1d(inter) ", m_EMT & 1, ( m_EMT >> 1 ) & 1 ); +#endif +#if JVET_M0140_SBT + msg( VERBOSE, "SBT:%d ", m_SBT ); #endif msg( VERBOSE, "CompositeLTReference:%d ", m_compositeRefEnabled); msg( VERBOSE, "GBi:%d ", m_GBi ); @@ -3155,23 +3204,43 @@ void EncAppCfg::xPrintParameter() #endif msg(VERBOSE, "MHIntra:%d ", m_MHIntra); msg( VERBOSE, "Triangle:%d ", m_Triangle ); +#if JVET_M0255_FRACMMVD_SWITCH + msg( VERBOSE, "AllowDisFracMMVD:%d ", m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + msg( VERBOSE, "AffineAmvr:%d ", m_AffineAmvr ); +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_AffineAmvrEncOpt = m_AffineAmvr ? m_AffineAmvrEncOpt : false; + msg( VERBOSE, "AffineAmvrEncOpt:%d ", m_AffineAmvrEncOpt ); +#endif +#if JVET_M0147_DMVR + msg(VERBOSE, "DMVR:%d ", m_DMVR); +#endif } msg(VERBOSE, "IBC:%d ", m_IBCMode); +#if JVET_M0253_HASH_ME + msg( VERBOSE, "HashME:%d ", m_HashME ); +#endif msg( VERBOSE, "WrapAround:%d ", m_wrapAround); if( m_wrapAround ) { msg( VERBOSE, "WrapAroundOffset:%d ", m_wrapAroundOffset ); } // ADD_NEW_TOOL (add some output indicating the usage of tools) - +#if JVET_M0427_INLOOP_RESHAPER + msg(VERBOSE, "Reshape:%d ", m_lumaReshapeEnable); + if (m_lumaReshapeEnable) + { + msg(VERBOSE, "(Sigal:%s ", m_reshapeSignalType==0? "SDR" : "HDR-PQ"); + msg(VERBOSE, ") "); + } +#endif msg( VERBOSE, "\nFAST TOOL CFG: " ); - if( m_LargeCTU ) - { - msg( VERBOSE, "LCTUFast:%d ", m_useFastLCTU ); - } + msg( VERBOSE, "LCTUFast:%d ", m_useFastLCTU ); msg( VERBOSE, "FastMrg:%d ", m_useFastMrg ); msg( VERBOSE, "PBIntraFast:%d ", m_usePbIntraFast ); - if( m_ImvMode == 2 ) msg( VERBOSE, "IMV4PelFast:%d ", m_Imv4PelFast ); + if( m_ImvMode ) msg( VERBOSE, "IMV4PelFast:%d ", m_Imv4PelFast ); #if JVET_M0464_UNI_MTS if( m_MTS ) msg( VERBOSE, "MTSMaxCand: %1d(intra) %1d(inter) ", m_MTSIntraMaxCand, m_MTSInterMaxCand ); #else diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 8b67d948decc874a2639cc402a27ee0d900cf67b..45895dc47bbd603185c179c09503a9bdb18003c6 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -202,16 +202,10 @@ protected: unsigned m_uiMaxBTDepthI; unsigned m_uiMaxBTDepthIChroma; bool m_dualTree; - bool m_LargeCTU; int m_SubPuMvpMode; bool m_Affine; bool m_AffineType; bool m_BIO; - bool m_DisableMotionCompression; - unsigned m_MTT; -#if ENABLE_WPP_PARALLELISM - bool m_AltDQPCoding; -#endif int m_LMChroma; #if JVET_M0142_CCLM_COLLOCATED_CHROMA bool m_cclmCollocatedChromaFlag; @@ -224,6 +218,12 @@ protected: int m_EMT; ///< XZ: Enhanced Multiple Transform int m_FastEMT; ///< XZ: Fast Methods of Enhanced Multiple Transform #endif +#if JVET_M0303_IMPLICIT_MTS + int m_MTSImplicit; +#endif +#if JVET_M0140_SBT + bool m_SBT; ///< Sub-Block Transform for inter blocks +#endif bool m_compositeRefEnabled; bool m_GBi; @@ -237,7 +237,21 @@ protected: bool m_MHIntra; bool m_Triangle; - +#if JVET_M0253_HASH_ME + bool m_HashME; +#endif +#if JVET_M0255_FRACMMVD_SWITCH + bool m_allowDisFracMMVD; +#endif +#if JVET_M0246_AFFINE_AMVR + bool m_AffineAmvr; +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + bool m_AffineAmvrEncOpt; +#endif +#if JVET_M0147_DMVR + bool m_DMVR; +#endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; @@ -246,12 +260,17 @@ protected: unsigned m_IBCHashSearchMaxCand; unsigned m_IBCHashSearchRange4SmallBlk; unsigned m_IBCFastMethod; - + bool m_wrapAround; unsigned m_wrapAroundOffset; // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + bool m_lumaReshapeEnable; + uint32_t m_reshapeSignalType; + uint32_t m_intraCMD; + ReshapeCW m_reshapeCW; +#endif unsigned m_uiMaxCUWidth; ///< max. CU width in pixel unsigned m_uiMaxCUHeight; ///< max. CU height in pixel unsigned m_uiMaxCUDepth; ///< max. CU depth (as specified by command line) @@ -524,6 +543,9 @@ protected: int m_verbosity; std::string m_decodeBitstreams[2]; ///< filename for decode bitstreams. +#if JVET_M0055_DEBUG_CTU + int m_debugCTU; +#endif int m_switchPOC; ///< dbg poc. int m_switchDQP; ///< switch DQP. int m_fastForwardToPOC; ///< get to encoding the specified POC as soon as possible by skipping temporal layers irrelevant for the specified POC diff --git a/source/App/Parcat/parcat.cpp b/source/App/Parcat/parcat.cpp index 81872abd5fb67b1bcdce84a68959119640944178..e6443eaf190ba9614243af216fa32a4572162f77 100644 --- a/source/App/Parcat/parcat.cpp +++ b/source/App/Parcat/parcat.cpp @@ -314,11 +314,11 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int int byte_offset2 = offset / 8; int hi_bits2 = offset % 8; uint16_t data2 = (nalu[byte_offset2] << 8) | nalu[byte_offset2 + 1]; - int low_bits2 = 16 - hi_bits2 - 1; + int low_bits2 = 16 - hi_bits2 - 1; if(((data2 >> low_bits2) % 2)) - offset += 1; // PPSId=0 + offset += 1; // PPSId=0 else - offset += 3; // PPSId=1 + offset += 3; // PPSId=1 offset += 1; // slice_type TODO: ue(v) // separate_colour_plane_flag is not supported in JEM1.0 if (nalu_type == CRA) diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index ed573e04cd87e3bd859bc1068f9e0dce791251e7..b234f00997f747b2d3e886b2b86c9055a6180ab0 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -135,7 +135,7 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel int numFilters = isLuma( channel ) ? alfSliceParam.numLumaFilters : 1; short* coeff = isLuma( channel ) ? alfSliceParam.lumaCoeff : alfSliceParam.chromaCoeff; - if( alfSliceParam.coeffDeltaPredModeFlag && isLuma( channel ) ) + if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) ) { for( int i = 1; i < numFilters; i++ ) { @@ -167,7 +167,7 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel memcpy( m_coeffFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF, coeff + filterIdx * MAX_NUM_ALF_LUMA_COEFF, sizeof( int16_t ) * numCoeff ); } - if( bRedo && alfSliceParam.coeffDeltaPredModeFlag ) + if( bRedo && alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) { for( int i = numFilters - 1; i > 0; i-- ) { diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp index 07ffa9a94ab29b9ce80e49aae1e75bbeb025c6c5..84f83324ea8b668a3d6c0dfd8bcc0225a98baa2b 100644 --- a/source/Lib/CommonLib/Buffer.cpp +++ b/source/Lib/CommonLib/Buffer.cpp @@ -91,18 +91,30 @@ void addBIOAvgCore(const Pel* src0, int src0Stride, const Pel* src1, int src1Str } } +#if JVET_M0063_BDOF_FIX +void gradFilterCore(Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, const int bitDepth) +#else void gradFilterCore(Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY) +#endif { Pel* srcTmp = pSrc + srcStride + 1; Pel* gradXTmp = gradX + gradStride + 1; Pel* gradYTmp = gradY + gradStride + 1; +#if JVET_M0063_BDOF_FIX + int shift1 = std::max<int>(2, (IF_INTERNAL_PREC - bitDepth)); +#endif for (int y = 0; y < (height - 2 * BIO_EXTEND_SIZE); y++) { for (int x = 0; x < (width - 2 * BIO_EXTEND_SIZE); x++) { +#if JVET_M0063_BDOF_FIX + gradYTmp[x] = (srcTmp[x + srcStride] - srcTmp[x - srcStride]) >> shift1; + gradXTmp[x] = (srcTmp[x + 1] - srcTmp[x - 1]) >> shift1; +#else gradYTmp[x] = (srcTmp[x + srcStride] - srcTmp[x - srcStride]) >> 4; gradXTmp[x] = (srcTmp[x + 1] - srcTmp[x - 1]) >> 4; +#endif } gradXTmp += gradStride; gradYTmp += gradStride; @@ -130,15 +142,29 @@ void gradFilterCore(Pel* pSrc, int srcStride, int width, int height, int gradStr ::memcpy(gradYTmp + (height - 2 * BIO_EXTEND_SIZE)*gradStride, gradYTmp + (height - 2 * BIO_EXTEND_SIZE - 1)*gradStride, sizeof(Pel)*(width)); } +#if JVET_M0063_BDOF_FIX +void calcBIOParCore(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, const int bitDepth) +#else void calcBIOParCore(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG) +#endif { +#if JVET_M0063_BDOF_FIX + int shift4 = std::min<int>(8, (bitDepth - 4)); + int shift5 = std::min<int>(5, (bitDepth - 7)); +#endif for (int y = 0; y < heightG; y++) { for (int x = 0; x < widthG; x++) { +#if JVET_M0063_BDOF_FIX + int temp = (srcY0Temp[x] >> shift4) - (srcY1Temp[x] >> shift4); + int tempX = (gradX0[x] + gradX1[x]) >> shift5; + int tempY = (gradY0[x] + gradY1[x]) >> shift5; +#else int temp = (srcY0Temp[x] >> 6) - (srcY1Temp[x] >> 6); int tempX = (gradX0[x] + gradX1[x]) >> 3; int tempY = (gradY0[x] + gradY1[x]) >> 3; +#endif dotProductTemp1[x] = tempX * tempX; dotProductTemp2[x] = tempX * tempY; dotProductTemp3[x] = -tempX * temp; @@ -273,6 +299,10 @@ PelBufferOps::PelBufferOps() calcBIOPar = calcBIOParCore; calcBlkGradient = calcBlkGradientCore; +#if JVET_M0147_DMVR + copyBuffer = copyBufferCore; + padding = paddingCore; +#endif #if ENABLE_SIMD_OPT_GBI removeWeightHighFreq8 = removeWeightHighFreq; removeWeightHighFreq4 = removeWeightHighFreq; @@ -287,6 +317,42 @@ PelBufferOps g_pelBufOP = PelBufferOps(); #endif #endif +#if JVET_M0147_DMVR +void copyBufferCore(Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height) +{ + int numBytes = width * sizeof(Pel); + for (int i = 0; i < height; i++) + { + memcpy(dst + i * dstStride, src + i * srcStride, numBytes); + } +} + +void paddingCore(Pel *ptr, int stride, int width, int height, int padSize) +{ + /*left and right padding*/ + Pel *ptrTemp1 = ptr; + Pel *ptrTemp2 = ptr + (width - 1); + int offset = 0; + for (int i = 0; i < height; i++) + { + offset = stride * i; + for (int j = 1; j <= padSize; j++) + { + *(ptrTemp1 - j + offset) = *(ptrTemp1 + offset); + *(ptrTemp2 + j + offset) = *(ptrTemp2 + offset); + } + } + /*Top and Bottom padding*/ + int numBytes = (width + padSize + padSize) * sizeof(Pel); + ptrTemp1 = (ptr - padSize); + ptrTemp2 = (ptr + (stride * (height - 1)) - padSize); + for (int i = 1; i <= padSize; i++) + { + memcpy(ptrTemp1 - (i * stride), (ptrTemp1), numBytes); + memcpy(ptrTemp2 + (i * stride), (ptrTemp2), numBytes); + } +} +#endif template<> void AreaBuf<Pel>::addWeightedAvg(const AreaBuf<const Pel> &other1, const AreaBuf<const Pel> &other2, const ClpRng& clpRng, const int8_t gbiIdx) { @@ -317,6 +383,80 @@ void AreaBuf<Pel>::addWeightedAvg(const AreaBuf<const Pel> &other1, const AreaBu #undef ADD_AVG_INC } +#if JVET_M0427_INLOOP_RESHAPER +template<> +void AreaBuf<Pel>::rspSignal(std::vector<Pel>& pLUT) +{ + Pel* dst = buf; + Pel* src = buf; +#if !JVET_M0102_INTRA_SUBPARTITIONS + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { +#endif + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + dst[x] = pLUT[src[x]]; + } + dst += stride; + src += stride; + } +#if !JVET_M0102_INTRA_SUBPARTITIONS + } +#endif +} + +template<> +void AreaBuf<Pel>::scaleSignal(const int scale, const bool dir, const ClpRng& clpRng) +{ + Pel* dst = buf; + Pel* src = buf; + int sign, absval; + int maxAbsclipBD = (1<<clpRng.bd) - 1; + + if (dir) // forward + { + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + sign = src[x] >= 0 ? 1 : -1; + absval = sign * src[x]; + dst[x] = (Pel)Clip3(-maxAbsclipBD, maxAbsclipBD, sign * (((absval << CSCALE_FP_PREC) + (scale >> 1)) / scale)); + } + dst += stride; + src += stride; + } + } + } + else // inverse + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + sign = src[x] >= 0 ? 1 : -1; + absval = sign * src[x]; + dst[x] = sign * ((absval * scale + (1 << (CSCALE_FP_PREC - 1))) >> CSCALE_FP_PREC); + } + dst += stride; + src += stride; + } + } +} +#endif + template<> void AreaBuf<Pel>::addAvg( const AreaBuf<const Pel> &other1, const AreaBuf<const Pel> &other2, const ClpRng& clpRng) { diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index 116f5c69fac4469eb69e6ec8ba755d133060ecdd..21584dde076f5c2056803e680d6bd1d285ac65a4 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -69,9 +69,18 @@ struct PelBufferOps void ( *linTf4 ) ( const Pel* src0, int src0Stride, Pel *dst, int dstStride, int width, int height, int scale, int shift, int offset, const ClpRng& clpRng, bool bClip ); void ( *linTf8 ) ( const Pel* src0, int src0Stride, Pel *dst, int dstStride, int width, int height, int scale, int shift, int offset, const ClpRng& clpRng, bool bClip ); void(*addBIOAvg4) (const Pel* src0, int src0Stride, const Pel* src1, int src1Stride, Pel *dst, int dstStride, const Pel *gradX0, const Pel *gradX1, const Pel *gradY0, const Pel*gradY1, int gradStride, int width, int height, int tmpx, int tmpy, int shift, int offset, const ClpRng& clpRng); +#if JVET_M0063_BDOF_FIX + void(*bioGradFilter) (Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, const int bitDepth); + void(*calcBIOPar) (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, const int bitDepth); +#else void(*bioGradFilter) (Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY); void(*calcBIOPar) (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG); +#endif void(*calcBlkGradient)(int sx, int sy, int *arraysGx2, int *arraysGxGy, int *arraysGxdI, int *arraysGy2, int *arraysGydI, int &sGx2, int &sGy2, int &sGxGy, int &sGxdI, int &sGydI, int width, int height, int unitSize); +#if JVET_M0147_DMVR + void(*copyBuffer)(Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height); + void(*padding)(Pel *dst, int stride, int width, int height, int padSize); +#endif #if ENABLE_SIMD_OPT_GBI void ( *removeWeightHighFreq8) ( Pel* src0, int src0Stride, const Pel* src1, int src1Stride, int width, int height, int shift, int gbiWeight); void ( *removeWeightHighFreq4) ( Pel* src0, int src0Stride, const Pel* src1, int src1Stride, int width, int height, int shift, int gbiWeight); @@ -85,6 +94,12 @@ extern PelBufferOps g_pelBufOP; #endif #endif + +#if JVET_M0147_DMVR +void paddingCore(Pel *ptr, int stride, int width, int height, int padSize); +void copyBufferCore(Pel *src, int srcStride, Pel *Dst, int dstStride, int width, int height); +#endif + template<typename T> struct AreaBuf : public Size { @@ -118,7 +133,6 @@ struct AreaBuf : public Size void removeHighFreq ( const AreaBuf<T>& other, const bool bClip, const ClpRng& clpRng); void updateHistogram ( std::vector<int32_t>& hist ) const; - T mean () const; T meanDiff ( const AreaBuf<const T> &other ) const; void subtract ( const T val ); @@ -128,6 +142,12 @@ struct AreaBuf : public Size void toLast ( const ClpRng& clpRng ); +#if JVET_M0427_INLOOP_RESHAPER + void rspSignal ( std::vector<Pel>& pLUT ); + void scaleSignal ( const int scale, const bool dir , const ClpRng& clpRng); +#endif + T computeAvg ( ) const; + T& at( const int &x, const int &y ) { return buf[y * stride + x]; } const T& at( const int &x, const int &y ) const { return buf[y * stride + x]; } @@ -548,26 +568,6 @@ void AreaBuf<T>::extendBorderPel( unsigned margin ) } } -template<typename T> -T AreaBuf<T>::mean() const -{ - int64_t sum = 0; - - CHECK (area() == 0, "size of area is zero"); - - const T* src = buf; - -#define MEAN_INC src += stride -#define MEAN_OP(ADDR) sum += src[ADDR] - - SIZE_AWARE_PER_EL_OP(MEAN_OP, MEAN_INC); - -#undef MEAN_INC -#undef MEAN_OP - - return T ((sum + (area() >> 1)) / area()); -} - template<typename T> T AreaBuf<T>::meanDiff( const AreaBuf<const T> &other ) const { @@ -631,6 +631,33 @@ void AreaBuf<T>::transposedFrom( const AreaBuf<const T> &other ) } } +template<typename T> +T AreaBuf <T> ::computeAvg() const +{ +#if !JVET_M0102_INTRA_SUBPARTITIONS + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { +#endif + const T* src = buf; +#if ENABLE_QPA + int64_t acc = 0; // for picture-wise use in getGlaringColorQPOffset() and applyQPAdaptationChroma() +#else + int32_t acc = 0; +#endif +#define AVG_INC src += stride +#define AVG_OP(ADDR) acc += src[ADDR] + SIZE_AWARE_PER_EL_OP(AVG_OP, AVG_INC); +#undef AVG_INC +#undef AVG_OP + return T ((acc + (area() >> 1)) / area()); +#if !JVET_M0102_INTRA_SUBPARTITIONS + } +#endif +} #ifndef DONT_UNDEF_SIZE_AWARE_PER_EL_OP #undef SIZE_AWARE_PER_EL_OP diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h index 748138fdf7a5339d69a21cab167088f17ac5e40c..b35013ca264fc26fa1d29d526bea4048c2ebd919 100644 --- a/source/Lib/CommonLib/CodingStatistics.h +++ b/source/Lib/CommonLib/CodingStatistics.h @@ -68,13 +68,21 @@ enum CodingStatisticsType STATS__CABAC_BITS__MVD_EP, STATS__CABAC_BITS__AFFINE_FLAG, STATS__CABAC_BITS__AFFINE_TYPE, +#if JVET_M0102_INTRA_SUBPARTITIONS + STATS__CABAC_BITS__ISP_MODE_FLAG, + STATS__CABAC_BITS__ISP_SPLIT_FLAG, +#endif STATS__CABAC_BITS__TRANSFORM_SUBDIV_FLAG, STATS__CABAC_BITS__QT_ROOT_CBF, STATS__CABAC_BITS__DELTA_QP_EP, STATS__CABAC_BITS__CHROMA_QP_ADJUSTMENT, STATS__CABAC_BITS__QT_CBF, STATS__CABAC_BITS__CROSS_COMPONENT_PREDICTION, +#if JVET_M0464_UNI_MTS + STATS__CABAC_BITS__MTS_FLAGS, +#else STATS__CABAC_BITS__TRANSFORM_SKIP_FLAGS, +#endif STATS__CABAC_BITS__LAST_SIG_X_Y, STATS__CABAC_BITS__SIG_COEFF_GROUP_FLAG, STATS__CABAC_BITS__SIG_COEFF_MAP_FLAG, @@ -99,18 +107,23 @@ enum CodingStatisticsType STATS__CABAC_BITS__INVALID, STATS__CABAC_BITS__IMV_FLAG, STATS__CABAC_BITS__GBI_IDX, +#if !JVET_M0464_UNI_MTS STATS__CABAC_BITS__EMT_CU_FLAG, STATS__CABAC_BITS__EMT_TU_INDEX, +#endif +#if JVET_M0140_SBT + STATS__CABAC_BITS__SBT_MODE, +#endif STATS__CABAC_BITS__MH_INTRA_FLAG, STATS__CABAC_BITS__TRIANGLE_FLAG, STATS__CABAC_BITS__TRIANGLE_INDEX, STATS__CABAC_BITS__MULTI_REF_LINE, - STATS__TOOL_TOTAL_FRAME,// This is a special case and is not included in the report. - STATS__TOOL_AFF, - STATS__TOOL_EMT, #if JVET_M0444_SMVD STATS__CABAC_BITS__SYMMVD_FLAG, #endif + STATS__TOOL_TOTAL_FRAME,// This is a special case and is not included in the report. + STATS__TOOL_AFF, + STATS__TOOL_EMT, STATS__TOOL_TOTAL, STATS__NUM_STATS }; @@ -150,13 +163,21 @@ static inline const char* getName(CodingStatisticsType name) "CABAC_BITS__MVD_EP", "CABAC_BITS__AFFINE_FLAG", "CABAC_BITS__AFFINE_TYPE", +#if JVET_M0102_INTRA_SUBPARTITIONS + "CABAC_BITS__ISP_MODE_FLAG", + "CABAC_BITS__ISP_SPLIT_FLAG", +#endif "CABAC_BITS__TRANSFORM_SUBDIV_FLAG", "CABAC_BITS__QT_ROOT_CBF", "CABAC_BITS__DELTA_QP_EP", "CABAC_BITS__CHROMA_QP_ADJUSTMENT", "CABAC_BITS__QT_CBF", "CABAC_BITS__CROSS_COMPONENT_PREDICTION", +#if JVET_M0464_UNI_MTS + "CABAC_BITS__MTS_FLAGS", +#else "CABAC_BITS__TRANSFORM_SKIP_FLAGS", +#endif "CABAC_BITS__LAST_SIG_X_Y", "CABAC_BITS__SIG_COEFF_GROUP_FLAG", "CABAC_BITS__SIG_COEFF_MAP_FLAG", @@ -181,8 +202,13 @@ static inline const char* getName(CodingStatisticsType name) "CABAC_BITS__INVALID", "CABAC_BITS__IMV_FLAG", "CABAC_BITS__GBI_IDX", +#if !JVET_M0464_UNI_MTS "CABAC_BITS__EMT_CU_FLAG", "CABAC_BITS__EMT_TU_INDX", +#endif +#if JVET_M0140_SBT + "CABAC_BITS__SBT_MODE", +#endif "CABAC_BITS__MH_INTRA_FLAG", "CABAC_BITS__TRIANGLE_FLAG", "CABAC_BITS__TRIANGLE_INDEX", diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 8d5013fcc154824f7131c04f8dc76f23b3576441..f52f4205834c8bfafe0841b22e45451cb4462b16 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -62,6 +62,9 @@ CodingStructure::CodingStructure(CUCache& cuCache, PUCache& puCache, TUCache& tu : area () , picture ( nullptr ) , parent ( nullptr ) +#if JVET_M0246_AFFINE_AMVR + , bestCS ( nullptr ) +#endif , m_isTuEnc ( false ) , m_cuCache ( cuCache ) , m_puCache ( puCache ) @@ -256,7 +259,11 @@ const PredictionUnit * CodingStructure::getPU( const Position &pos, const Channe } } +#if JVET_M0102_INTRA_SUBPARTITIONS +TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType effChType, const int subTuIdx ) +#else TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType effChType ) +#endif { const CompArea &_blk = area.blocks[effChType]; @@ -269,13 +276,45 @@ TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType ef { const unsigned idx = m_tuIdx[effChType][rsAddr( pos, _blk.pos(), _blk.width, unitScale[effChType] )]; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( idx != 0 ) + { + unsigned extraIdx = 0; + if( isLuma( effChType ) ) + { + const TransformUnit& tu = *tus[idx - 1]; + + if( tu.cu->ispMode ) // Intra SubPartitions mode + { + //we obtain the offset to index the corresponding sub-partition + if( subTuIdx != -1 ) + { + extraIdx = subTuIdx; + } + else + { + while( pos != tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].pos() ) + { + extraIdx++; + } + } + } + } + return tus[idx - 1 + extraIdx]; + } +#else if( idx != 0 ) return tus[ idx - 1 ]; +#endif else if( m_isTuEnc ) return parent->getTU( pos, effChType ); else return nullptr; } } +#if JVET_M0102_INTRA_SUBPARTITIONS +const TransformUnit * CodingStructure::getTU( const Position &pos, const ChannelType effChType, const int subTuIdx ) const +#else const TransformUnit * CodingStructure::getTU( const Position &pos, const ChannelType effChType ) const +#endif { const CompArea &_blk = area.blocks[effChType]; @@ -287,8 +326,34 @@ const TransformUnit * CodingStructure::getTU( const Position &pos, const Channel else { const unsigned idx = m_tuIdx[effChType][rsAddr( pos, _blk.pos(), _blk.width, unitScale[effChType] )]; - +#if JVET_M0102_INTRA_SUBPARTITIONS + if( idx != 0 ) + { + unsigned extraIdx = 0; + if( isLuma( effChType ) ) + { + const TransformUnit& tu = *tus[idx - 1]; + if( tu.cu->ispMode ) // Intra SubPartitions mode + { + //we obtain the offset to index the corresponding sub-partition + if( subTuIdx != -1 ) + { + extraIdx = subTuIdx; + } + else + { + while( pos != tus[idx - 1 + extraIdx]->blocks[effChType].pos() ) + { + extraIdx++; + } + } + } + } + return tus[idx - 1 + extraIdx]; + } +#else if( idx != 0 ) return tus[idx - 1]; +#endif else if( m_isTuEnc ) return parent->getTU( pos, effChType ); else return nullptr; } @@ -415,6 +480,9 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c tu->UnitArea::operator=( unit ); tu->initData(); tu->next = nullptr; +#if JVET_M0102_INTRA_SUBPARTITIONS + tu->prev = nullptr; +#endif tu->cs = this; tu->cu = m_isTuEnc ? cus[0] : getCU( unit.blocks[chType].pos(), chType ); tu->chType = chType; @@ -430,6 +498,9 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c if( prevTU && prevTU->cu == tu->cu ) { prevTU->next = tu; +#if JVET_M0102_INTRA_SUBPARTITIONS + tu->prev = prevTU; +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM CHECK( prevTU->cacheId != tu->cacheId, "Inconsintent cacheId between previous and current TU" ); @@ -467,11 +538,25 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c const CompArea &_selfBlk = area.blocks[i]; const CompArea &_blk = tu-> blocks[i]; +#if JVET_M0102_INTRA_SUBPARTITIONS + bool isIspTu = tu->cu != nullptr && tu->cu->ispMode && isLuma( _blk.compID ); + + bool isFirstIspTu = false; + if( isIspTu ) + { + isFirstIspTu = CU::isISPFirst( *tu->cu, _blk, getFirstComponentOfChannel( ChannelType( i ) ) ); + } + if( !isIspTu || isFirstIspTu ) +#endif { const UnitScale& scale = unitScale[_blk.compID]; const Area scaledSelf = scale.scale( _selfBlk ); +#if JVET_M0102_INTRA_SUBPARTITIONS + const Area scaledBlk = isIspTu ? scale.scale( tu->cu->blocks[i] ) : scale.scale( _blk ); +#else const Area scaledBlk = scale.scale( _blk ); +#endif unsigned *idxPtr = m_tuIdx[i] + rsAddr( scaledBlk.pos(), scaledSelf.pos(), scaledSelf.width ); CHECK( *idxPtr, "Overwriting a pre-existing value, should be '0'!" ); AreaBuf<uint32_t>( idxPtr, scaledSelf.width, scaledBlk.size() ).fill( idx ); @@ -746,7 +831,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C if( cpyResi ) picture->getResiBuf( clippedArea ).copyFrom( subResiBuf ); if( cpyReco ) picture->getRecoBuf( clippedArea ).copyFrom( subRecoBuf ); +#if JVET_M0483_IBC + if (!subStruct.m_isTuEnc && ((!slice->isIntra() || slice->getSPS()->getIBCFlag()) && subStruct.chType != CHANNEL_TYPE_CHROMA)) +#else if (!subStruct.m_isTuEnc && (!slice->isIntra() && subStruct.chType != CHANNEL_TYPE_CHROMA)) +#endif { // copy motion buffer MotionBuf ownMB = getMotionBuf ( clippedArea ); @@ -926,7 +1015,11 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel pu = *ppu; } +#if JVET_M0483_IBC + if (!other.slice->isIntra() || other.slice->getSPS()->getIBCFlag()) +#else if( !other.slice->isIntra() ) +#endif { // copy motion buffer MotionBuf ownMB = getMotionBuf(); @@ -966,6 +1059,28 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel // copy data to picture picture->getRecoBuf( area ).copyFrom( recoBuf ); +#if JVET_M0427_INLOOP_RESHAPER + if (other.pcv->isEncoder) + { + CPelUnitBuf predBuf = other.getPredBuf(area); + if (parent) + { + getPredBuf(area).copyFrom(predBuf); + } + picture->getPredBuf(area).copyFrom(predBuf); + } +#endif +#if JVET_M0055_DEBUG_CTU + + // required for DebugCTU + int numCh = ::getNumberValidChannels( area.chromaFormat ); + for( int i = 0; i < numCh; i++ ) + { + const size_t _area = unitScale[i].scaleArea( area.blocks[i].area() ); + + memcpy( m_isDecomp[i], other.m_isDecomp[i], sizeof( *m_isDecomp[0] ) * _area ); + } +#endif } } @@ -981,7 +1096,11 @@ void CodingStructure::initStructData( const int &QP, const bool &_isLosses, cons isLossless = _isLosses; } +#if JVET_M0483_IBC + if (!skipMotBuf && (!parent || ((!slice->isIntra() || slice->getSPS()->getIBCFlag()) && !m_isTuEnc))) +#else if( !skipMotBuf && ( !parent || ( ( slice->getSliceType() != I_SLICE ) && !m_isTuEnc ) ) ) +#endif { getMotionBuf() .memset( 0 ); } @@ -989,6 +1108,9 @@ void CodingStructure::initStructData( const int &QP, const bool &_isLosses, cons fracBits = 0; dist = 0; cost = MAX_DOUBLE; +#if JVET_M0102_INTRA_SUBPARTITIONS + lumaCost = MAX_DOUBLE; +#endif interHad = std::numeric_limits<Distortion>::max(); } @@ -1004,7 +1126,7 @@ void CodingStructure::clearTUs() memset( m_tuIdx [i], 0, sizeof( *m_tuIdx [0] ) * _area ); } - numCh = getNumberValidComponents( area.chromaFormat ); + numCh = getNumberValidComponents( area.chromaFormat ); for( int i = 0; i < numCh; i++ ) { m_offsets[i] = 0; diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 3727cc1fd33e8af22c8d7a44362b79ba00a14524..f28500a798c9a02ea29c2f58e19501540d80f94a 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -53,6 +53,9 @@ enum PictureType { PIC_RECONSTRUCTION = 0, PIC_ORIGINAL, +#if JVET_M0427_INLOOP_RESHAPER + PIC_TRUE_ORIGINAL, +#endif PIC_PREDICTION, PIC_RESIDUAL, PIC_ORG_RESI, @@ -79,7 +82,9 @@ public: Picture *picture; CodingStructure *parent; - +#if JVET_M0246_AFFINE_AMVR + CodingStructure *bestCS; +#endif Slice *slice; UnitScale unitScale[MAX_NUM_COMPONENT]; @@ -124,11 +129,19 @@ public: const CodingUnit *getCU(const Position &pos, const ChannelType _chType) const; const PredictionUnit *getPU(const Position &pos, const ChannelType _chType) const; +#if JVET_M0102_INTRA_SUBPARTITIONS + const TransformUnit *getTU(const Position &pos, const ChannelType _chType, const int subTuIdx = -1) const; +#else const TransformUnit *getTU(const Position &pos, const ChannelType _chType) const; +#endif CodingUnit *getCU(const Position &pos, const ChannelType _chType); PredictionUnit *getPU(const Position &pos, const ChannelType _chType); +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit *getTU(const Position &pos, const ChannelType _chType, const int subTuIdx = -1); +#else TransformUnit *getTU(const Position &pos, const ChannelType _chType); +#endif const CodingUnit *getCU(const ChannelType &_chType) const { return getCU(area.blocks[_chType].pos(), _chType); } const PredictionUnit *getPU(const ChannelType &_chType) const { return getPU(area.blocks[_chType].pos(), _chType); } @@ -166,6 +179,9 @@ public: static_vector<double, NUM_ENC_FEATURES> features; double cost; +#if JVET_M0102_INTRA_SUBPARTITIONS + double lumaCost; +#endif uint64_t fracBits; Distortion dist; Distortion interHad; diff --git a/source/Lib/CommonLib/Common.h b/source/Lib/CommonLib/Common.h index 24746baad3be0895fd1ae962155c4fdbc17bccc4..81c92278b2bd60a59c558424bcdbedf0f1defb5b 100644 --- a/source/Lib/CommonLib/Common.h +++ b/source/Lib/CommonLib/Common.h @@ -72,6 +72,9 @@ struct Size bool operator!=(const Size &other) const { return (width != other.width) || (height != other.height); } bool operator==(const Size &other) const { return (width == other.width) && (height == other.height); } uint32_t area() const { return (uint32_t) width * (uint32_t) height; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo(const Size newSize) { width = newSize.width; height = newSize.height; } +#endif }; struct Area : public Position, public Size diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 27d76437a551bb84a7d284e129c8d27423cb3d9c..6d09dc35f650e11d42a96fe0daf219da1381a6e5 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -53,9 +53,10 @@ #include "TypeDef.h" #include "version.h" +// MS Visual Studio before 2014 does not support required C++11 features #ifdef _MSC_VER -#if _MSC_VER <= 1500 -inline int64_t abs (int64_t x) { return _abs64(x); }; +#if _MSC_VER < 1900 +#error "MS Visual Studio version not supported. Please upgrade to Visual Studio 2015 or higher (or use other compilers)" #endif #endif @@ -66,7 +67,14 @@ inline int64_t abs (int64_t x) { return _abs64(x); }; // Platform information // ==================================================================================================================== -#ifdef __GNUC__ +#ifdef __clang__ +#define NVM_COMPILEDBY "[clang %d.%d.%d]", __clang_major__, __clang_minor__, __clang_patchlevel__ +#ifdef __IA64__ +#define NVM_ONARCH "[on 64-bit] " +#else +#define NVM_ONARCH "[on 32-bit] " +#endif +#elif __GNUC__ #define NVM_COMPILEDBY "[GCC %d.%d.%d]", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ #ifdef __IA64__ #define NVM_ONARCH "[on 64-bit] " @@ -117,7 +125,7 @@ static const double AFFINE_ME_LIST_MVP_TH = 1.0; // ==================================================================================================================== // Common constants // ==================================================================================================================== - +static const uint64_t MAX_UINT64 = 0xFFFFFFFFFFFFFFFFU; static const uint32_t MAX_UINT = 0xFFFFFFFFU; ///< max. value of unsigned 32-bit integer static const int MAX_INT = 2147483647; ///< max. value of signed 32-bit integer static const uint8_t MAX_UCHAR = 255; @@ -162,9 +170,11 @@ static const int MAXIMUM_INTRA_FILTERED_HEIGHT = 16; static const int MAX_CPB_CNT = 32; ///< Upper bound of (cpb_cnt_minus1 + 1) static const int MAX_NUM_LAYER_IDS = 64; - +#if JVET_M0470 +static const int COEF_REMAIN_BIN_REDUCTION = 5; ///< indicates the level at which the VLC transitions from Golomb-Rice to TU+EG(k) +#else static const int COEF_REMAIN_BIN_REDUCTION = 3; ///< indicates the level at which the VLC transitions from Golomb-Rice to TU+EG(k) - +#endif static const int CU_DQP_TU_CMAX = 5; ///< max number bins for truncated unary static const int CU_DQP_EG_k = 0; ///< expgolomb order @@ -316,7 +326,7 @@ static const int BIO_TEMP_BUFFER_SIZE = (MAX_CU_SIZE static const int GBI_NUM = 5; ///< the number of weight options static const int GBI_DEFAULT = ((uint8_t)(GBI_NUM >> 1)); ///< Default weighting index representing for w=0.5 static const int GBI_SIZE_CONSTRAINT = 256; ///< disabling GBi if cu size is smaller than 256 -static const int MAX_NUM_HMVP_CANDS = 6; ///< maximum number of HMVP candidates to be stored and used in merge list +static const int MAX_NUM_HMVP_CANDS = 5; ///< maximum number of HMVP candidates to be stored and used in merge list static const int MAX_NUM_HMVP_AVMPCANDS = 4; ///< maximum number of HMVP candidates to be used in AMVP list #if W0038_DB_OPT @@ -330,6 +340,14 @@ static const uint32_t LUMA_LEVEL_TO_DQP_LUT_MAXSIZE = 1024; ///< #if !JVET_M0464_UNI_MTS static const int NUM_EMT_CU_FLAG_CTX = 6; ///< number of context models for EMT CU-level flag #endif +#if JVET_M0147_DMVR +static const int DMVR_SUBCU_WIDTH = 16; +static const int DMVR_SUBCU_HEIGHT = 16; +static const int DMVR_SUBCU_WIDTH_LOG2 = 4; +static const int DMVR_SUBCU_HEIGHT_LOG2 = 4; +static const int MAX_NUM_SUBCU_DMVR = ((MAX_CU_SIZE * MAX_CU_SIZE) >> (DMVR_SUBCU_WIDTH_LOG2 + DMVR_SUBCU_HEIGHT_LOG2)); +static const int DMVR_NUM_ITERATION = 2; +#endif //QTBT high level parameters //for I slice luma CTB configuration para. @@ -365,7 +383,7 @@ static const int FAST_SKIP_DEPTH = 2; static const double PBINTRA_RATIO = 1.1; static const int NUM_MRG_SATD_CAND = 4; static const double MRG_FAST_RATIO = 1.25; -static const int NUM_AFF_MRG_SATD_CAND = 1; +static const int NUM_AFF_MRG_SATD_CAND = 2; static const double AMAXBT_TH32 = 15.0; static const double AMAXBT_TH64 = 30.0; @@ -396,13 +414,31 @@ static const int TRIANGLE_MAX_NUM_CANDS = 40; static const int TRIANGLE_MAX_NUM_SATD_CANDS = 3; static const int TRIANGLE_MIN_SIZE = 8 * 8; +#if JVET_M0140_SBT +static const int SBT_MAX_SIZE = 64; ///< maximum CU size for using SBT +static const int SBT_NUM_SL = 10; ///< maximum number of historical PU decision saved for a CU +static const int SBT_NUM_RDO = 2; ///< maximum number of SBT mode tried for a PU +#endif + static const int IBC_MAX_CAND_SIZE = 16; // max block size for ibc search static const int IBC_NUM_CANDIDATES = 64; ///< Maximum number of candidates to store/test static const int CHROMA_REFINEMENT_CANDIDATES = 8; /// 8 candidates BV to choose from static const int IBC_FAST_METHOD_NOINTRA_IBCCBF0 = 0x01; static const int IBC_FAST_METHOD_BUFFERBV = 0X02; static const int IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE = 0X04; - +#if JVET_M0512_MOTION_BUFFER_COMPRESSION +static constexpr int MV_EXPONENT_BITCOUNT = 4; +static constexpr int MV_MANTISSA_BITCOUNT = 6; +static constexpr int MV_MANTISSA_UPPER_LIMIT = ((1 << (MV_MANTISSA_BITCOUNT - 1)) - 1); +static constexpr int MV_MANTISSA_LIMIT = (1 << (MV_MANTISSA_BITCOUNT - 1)); +static constexpr int MV_EXPONENT_MASK = ((1 << MV_EXPONENT_BITCOUNT) - 1); +#endif +#if JVET_M0427_INLOOP_RESHAPER +static const int PIC_ANALYZE_CW_BINS = 32; +static const int PIC_CODE_CW_BINS = 16; +static const int FP_PREC = 14; +static const int CSCALE_FP_PREC = 11; +#endif // ==================================================================================================================== // Macro functions // ==================================================================================================================== diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index d52ea51e00383a3719d16ecc733dd3f968afda60..b90718f94d61afd495af74edd8faa6ea59070b9e 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -50,11 +50,21 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp , m_chType (toChannelType(m_compID)) , m_width (tu.block(m_compID).width) , m_height (tu.block(m_compID).height) +#if JVET_M0102_INTRA_SUBPARTITIONS + , m_log2CGWidth ( g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][0] ) + , m_log2CGHeight ( g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][1] ) +#else , m_log2CGWidth ((m_width & 3) || (m_height & 3) ? 1 : 2) , m_log2CGHeight ((m_width & 3) || (m_height & 3) ? 1 : 2) +#endif , m_log2CGSize (m_log2CGWidth + m_log2CGHeight) - , m_widthInGroups (m_width >> m_log2CGWidth) - , m_heightInGroups (m_height >> m_log2CGHeight) +#if JVET_M0257 + , m_widthInGroups(std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, m_width) >> m_log2CGWidth) + , m_heightInGroups(std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, m_height) >> m_log2CGHeight) +#else + , m_widthInGroups(m_width >> m_log2CGWidth) + , m_heightInGroups(m_height >> m_log2CGHeight) +#endif , m_log2BlockWidth (g_aucLog2[m_width]) , m_log2BlockHeight (g_aucLog2[m_height]) , m_log2BlockSize ((m_log2BlockWidth + m_log2BlockHeight)>>1) @@ -69,14 +79,22 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp #else , m_scanType (SCAN_DIAG) #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + , m_scan (g_scanOrder [m_chType][SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )]) + , m_scanCG (g_scanOrder [m_chType][SCAN_UNGROUPED ][m_scanType][gp_sizeIdxInfo->idxFrom(m_widthInGroups)][gp_sizeIdxInfo->idxFrom(m_heightInGroups)]) +#else , m_scan (g_scanOrder [SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )]) - , m_scanPosX (g_scanOrderPosXY[SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][0]) - , m_scanPosY (g_scanOrderPosXY[SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][1]) , m_scanCG (g_scanOrder[SCAN_UNGROUPED ][m_scanType][gp_sizeIdxInfo->idxFrom(m_widthInGroups)][gp_sizeIdxInfo->idxFrom(m_heightInGroups)]) +#endif , m_CtxSetLastX (Ctx::LastX[m_chType]) , m_CtxSetLastY (Ctx::LastY[m_chType]) - , m_maxLastPosX (g_uiGroupIdx[m_width - 1]) - , m_maxLastPosY (g_uiGroupIdx[m_height - 1]) +#if JVET_M0257 + , m_maxLastPosX(g_uiGroupIdx[std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, m_width) - 1]) + , m_maxLastPosY(g_uiGroupIdx[std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, m_height) - 1]) +#else + , m_maxLastPosX(g_uiGroupIdx[m_width - 1]) + , m_maxLastPosY(g_uiGroupIdx[m_height - 1]) +#endif , m_lastOffsetX (0) , m_lastOffsetY (0) , m_lastShiftX (0) @@ -137,7 +155,7 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp void CoeffCodingContext::initSubblock( int SubsetId, bool sigGroupFlag ) { m_subSetId = SubsetId; - m_subSetPos = m_scanCG[ m_subSetId ]; + m_subSetPos = m_scanCG[m_subSetId].idx; m_subSetPosY = m_subSetPos / m_widthInGroups; m_subSetPosX = m_subSetPos - ( m_subSetPosY * m_widthInGroups ); m_minSubPos = m_subSetId << m_log2CGSize; @@ -262,8 +280,8 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u ////////////////////////// // CTX is h/v bt (0-3) ////////////////////////// - ctxHorBt = ( partitioner.currBtDepth >= 2 ? 1 : 0 ); - ctxVerBt = ( partitioner.currBtDepth >= 2 ? 3 : 2 ); + ctxHorBt = ( partitioner.currMtDepth <= 1 ? 1 : 0 ); + ctxVerBt = ( partitioner.currMtDepth <= 1 ? 3 : 2 ); } #else unsigned DeriveCtx::CtxCUsplit( const CodingStructure& cs, Partitioner& partitioner ) @@ -304,8 +322,17 @@ unsigned DeriveCtx::CtxCUsplit( const CodingStructure& cs, Partitioner& partitio } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf, const int ispIdx ) +{ + if( ispIdx && isLuma( compID ) ) + { + return 2 + (int)prevCbCbf; + } +#else unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ) { +#endif if( compID == COMPONENT_Cr ) { return ( prevCbCbf ? 1 : 0 ); @@ -322,11 +349,7 @@ unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, unsigned DeriveCtx::CtxInterDir( const PredictionUnit& pu ) { - if( pu.cs->sps->getSpsNext().getUseLargeCTU() ) - { - return Clip3( 0, 3, 7 - ( ( g_aucLog2[pu.lumaSize().width] + g_aucLog2[pu.lumaSize().height] + 1 ) >> 1 ) ); // VG-ASYMM DONE - } - return pu.cu->qtDepth; + return Clip3( 0, 3, 7 - ( ( g_aucLog2[pu.lumaSize().width] + g_aucLog2[pu.lumaSize().height] + 1 ) >> 1 ) ); // VG-ASYMM DONE } unsigned DeriveCtx::CtxAffineFlag( const CodingUnit& cu ) @@ -451,6 +474,20 @@ unsigned DeriveCtx::CtxPredModeFlag( const CodingUnit& cu ) } #endif +#if JVET_M0483_IBC +unsigned DeriveCtx::CtxIBCFlag(const CodingUnit& cu) +{ + const CodingStructure *cs = cu.cs; + unsigned ctxId = 0; + const CodingUnit *cuLeft = cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L); + ctxId += (cuLeft && CU::isIBC(*cuLeft)) ? 1 : 0; + + const CodingUnit *cuAbove = cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L); + ctxId += (cuAbove && CU::isIBC(*cuAbove)) ? 1 : 0; + return ctxId; +} +#endif + void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) { CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" ); @@ -470,17 +507,28 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) pu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID; pu.mvpNum [REF_PIC_LIST_0] = NOT_VALID; pu.mvpNum [REF_PIC_LIST_1] = NOT_VALID; +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + { + pu.bv = pu.mv[REF_PIC_LIST_0]; + pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution + } +#else if (interDirNeighbours[candIdx] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mvFieldNeighbours[candIdx << 1].refIdx)->getPOC() == pu.cs->slice->getPOC()) { pu.cu->ibc = true; pu.bv = pu.mv[REF_PIC_LIST_0]; pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution } +#endif pu.cu->GBiIdx = ( interDirNeighbours[candIdx] == 3 ) ? GBiIdx[candIdx] : GBI_DEFAULT; #if JVET_M0068_M0171_MMVD_CLEANUP PU::restrictBiPredMergeCandsOne(pu); #endif +#if JVET_M0823_MMVD_ENCOPT + pu.mmvdEncOptMode = 0; +#endif } void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) { @@ -501,8 +549,15 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) tempIdx = tempIdx - fPosBaseIdx * (MMVD_MAX_REFINE_NUM); fPosStep = tempIdx / 4; fPosPosition = tempIdx - fPosStep * (4); - +#if JVET_M0255_FRACMMVD_SWITCH + int offset = refMvdCands[fPosStep]; + if ( pu.cu->slice->getDisFracMMVD() ) + { + offset <<= 2; + } +#else const int offset = refMvdCands[fPosStep]; +#endif const int refList0 = mmvdBaseMv[fPosBaseIdx][0].refIdx; const int refList1 = mmvdBaseMv[fPosBaseIdx][1].refIdx; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 4f2c0d90327606deffffdf26773083927762a763..5e6b2db73a4ee36c8b5738c6055c26ca065df37d 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -70,6 +70,10 @@ public: int cgPosX () const { return m_subSetPosX; } unsigned width () const { return m_width; } unsigned height () const { return m_height; } +#if JVET_M0297_32PT_MTS_ZERO_OUT + unsigned log2CGWidth () const { return m_log2CGWidth; } + unsigned log2CGHeight () const { return m_log2CGHeight; } +#endif unsigned log2CGSize () const { return m_log2CGSize; } unsigned log2BlockWidth () const { return m_log2BlockWidth; } unsigned log2BlockHeight () const { return m_log2BlockHeight; } @@ -82,7 +86,7 @@ public: int maxSubPos () const { return m_maxSubPos; } bool isLast () const { return ( ( m_scanPosLast >> m_log2CGSize ) == m_subSetId ); } bool isNotFirst () const { return ( m_subSetId != 0 ); } - bool isSigGroup ( int scanPosCG ) const { return m_sigCoeffGroupFlag[ m_scanCG[ scanPosCG ] ]; } + bool isSigGroup(int scanPosCG) const { return m_sigCoeffGroupFlag[m_scanCG[scanPosCG].idx]; } bool isSigGroup () const { return m_sigCoeffGroupFlag[ m_subSetPos ]; } #if HEVC_USE_SIGN_HIDING bool signHiding () const { return m_signHiding; } @@ -90,9 +94,9 @@ public: int posLast ) const { return ( m_signHiding && ( posLast - posFirst >= SBH_THRESHOLD ) ); } #endif CoeffScanType scanType () const { return m_scanType; } - unsigned blockPos ( int scanPos ) const { return m_scan[ scanPos ]; } - unsigned posX ( int scanPos ) const { return m_scanPosX[ scanPos ]; } - unsigned posY ( int scanPos ) const { return m_scanPosY[ scanPos ]; } + unsigned blockPos(int scanPos) const { return m_scan[scanPos].idx; } + unsigned posX(int scanPos) const { return m_scan[scanPos].x; } + unsigned posY(int scanPos) const { return m_scan[scanPos].y; } unsigned maxLastPosX () const { return m_maxLastPosX; } unsigned maxLastPosY () const { return m_maxLastPosY; } unsigned lastXCtxId ( unsigned posLastX ) const { return m_CtxSetLastX( m_lastOffsetX + ( posLastX >> m_lastShiftX ) ); } @@ -101,8 +105,8 @@ public: unsigned sigCtxIdAbs( int scanPos, const TCoeff* coeff, const int state ) { - const uint32_t posY = m_scanPosY[ scanPos ]; - const uint32_t posX = m_scanPosX[ scanPos ]; + const uint32_t posY = m_scan[scanPos].y; + const uint32_t posX = m_scan[scanPos].x; const TCoeff* pData = coeff + posX + posY * m_width; const int diag = posX + posY; int numPos = 0; @@ -160,8 +164,8 @@ public: unsigned templateAbsSum( int scanPos, const TCoeff* coeff ) { - const uint32_t posY = m_scanPosY[scanPos]; - const uint32_t posX = m_scanPosX[scanPos]; + const uint32_t posY = m_scan[scanPos].y; + const uint32_t posX = m_scan[scanPos].x; const TCoeff* pData = coeff + posX + posY * m_width; int sum = 0; if (posX < m_width - 1) @@ -213,10 +217,8 @@ private: const bool m_extendedPrecision; const int m_maxLog2TrDynamicRange; CoeffScanType m_scanType; - const unsigned* m_scan; - const unsigned* m_scanPosX; - const unsigned* m_scanPosY; - const unsigned* m_scanCG; + const ScanElement * m_scan; + const ScanElement * m_scanCG; const CtxSet m_CtxSetLastX; const CtxSet m_CtxSetLastY; const unsigned m_maxLastPosX; @@ -308,7 +310,11 @@ void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, uns unsigned CtxCUsplit ( const CodingStructure& cs, Partitioner& partitioner ); unsigned CtxBTsplit ( const CodingStructure& cs, Partitioner& partitioner ); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf = false, const int ispIdx = 0 ); +#else unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ); +#endif unsigned CtxInterDir ( const PredictionUnit& pu ); unsigned CtxSkipFlag ( const CodingUnit& cu ); unsigned CtxIMVFlag ( const CodingUnit& cu ); @@ -317,6 +323,9 @@ unsigned CtxTriangleFlag( const CodingUnit& cu ); #if JVET_M0502_PRED_MODE_CTX unsigned CtxPredModeFlag( const CodingUnit& cu ); #endif +#if JVET_M0483_IBC +unsigned CtxIBCFlag(const CodingUnit& cu); +#endif } #endif // __CONTEXTMODELLING__ diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index cbc516d354ffa006e10826ec03b36f8bb78fb434..566a85793a3ac598ed6de281b603288309d75662 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -350,12 +350,12 @@ std::vector<std::vector<uint8_t>> ContextSetCfg::sm_InitTables( NUMBER_OF_SLICE_ const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0421_SPLIT_SIG - // |-------- do split ctx -------------------| - { 93, 124, 141, 123, 125, 141, 139, 126, 157, }, - { 108, 139, 156, 138, 140, 141, 139, 141, 143, }, - { 153, 154, 172, 153, 140, 156, 154, 127, 159, }, + // |-------- do split ctx -------------------| + { 122, 124, 141, 108, 125, 156, 138, 126, 143, }, + { 93, 139, 171, 124, 125, 141, 139, 141, 158, }, + { 138, 154, 172, 124, 140, 142, 154, 127, 175, }, #if JVET_M0453_CABAC_ENGINE - { DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, }, + { 9, 13, 8, 8, 13, 12, 5, 10, 12, }, #endif #else #if JVET_M0453_CABAC_ENGINE @@ -374,31 +374,31 @@ const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet #if JVET_M0421_SPLIT_SIG const CtxSet ContextSetCfg::SplitQtFlag = ContextSetCfg::addCtxSet ({ - { 153, 126, 142, 137, 109, 155, }, - { 153, 126, 157, 122, 138, 140, }, - { 153, 125, 127, 137, 153, 155, }, + { 138, 140, 142, 136, 138, 140, }, + { 139, 126, 142, 107, 138, 125, }, + { 139, 125, 127, 136, 153, 126, }, #if JVET_M0453_CABAC_ENGINE - { DWS, DWS, DWS, DWS, DWS, DWS, }, + { 0, 8, 8, 12, 12, 8, }, #endif }); const CtxSet ContextSetCfg::SplitHvFlag = ContextSetCfg::addCtxSet ({ - { 154, 168, 155, 153, 155, }, - { 154, 168, 170, 153, 170, }, - { 154, 153, 140, 153, 154, }, + { 154, 168, 155, 139, 155, }, + { 169, 168, 170, 153, 170, }, + { 154, 168, 140, 153, 169, }, #if JVET_M0453_CABAC_ENGINE - { DWS, DWS, DWS, DWS, DWS, }, + { 10, 9, 9, 8, 8, }, #endif }); const CtxSet ContextSetCfg::Split12Flag = ContextSetCfg::addCtxSet ({ - { 140, 154, 140, 154, }, - { 155, 169, 140, 154, }, - { 155, 154, 155, 154, }, + { 154, 140, 154, 140, }, + { 169, 155, 154, 140, }, + { 154, 170, 154, 170, }, #if JVET_M0453_CABAC_ENGINE - { DWS, DWS, DWS, DWS, }, + { 12, 12, 12, 12, }, #endif }); #else @@ -421,10 +421,10 @@ const CtxSet ContextSetCfg::BTSplitFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::SkipFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 197, 214, 230,}, - { 197, 184, 200,}, - { CNU, CNU, CNU,}, - { 5, 8, 8,}, + { 197, 214, 216, }, + { 197, 198, 185, }, + { 40, 138, 154, }, + { 5, 8, 8, }, #else { 183, 185, 186, }, { 168, 199, 200, }, @@ -435,10 +435,10 @@ const CtxSet ContextSetCfg::SkipFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MergeFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 125,}, - { 110,}, - { CNU,}, - { 5,}, + { 111, }, + { 111, }, + { 153, }, + { 5, }, #else { 125, }, { 110, }, @@ -449,10 +449,10 @@ const CtxSet ContextSetCfg::MergeFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MergeIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE + { 138, }, + { 154, }, { 153, }, - { 154,}, - { CNU, }, - { 8,}, + { 8, }, #else { 167, }, { 138, }, @@ -463,10 +463,10 @@ const CtxSet ContextSetCfg::MergeIdx = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MmvdFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 135,}, - { 122,}, - { CNU,}, - { 9,}, + { 120, }, + { 122, }, + { CNU, }, + { 8, }, #else { 136, }, { 167, }, @@ -480,7 +480,7 @@ const CtxSet ContextSetCfg::MmvdMergeIdx = ContextSetCfg::addCtxSet { 154, }, { 154, }, { CNU, }, - { 10,}, + { 10, }, #else { 154, }, { 154, }, @@ -491,10 +491,10 @@ const CtxSet ContextSetCfg::MmvdMergeIdx = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MmvdStepMvpIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 228, }, - { 245,}, + { 213, }, + { 244, }, { CNU, }, - { 1,}, + { 1, }, #else { 213, }, { 169, }, @@ -520,10 +520,10 @@ const CtxSet ContextSetCfg::PredMode = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE #if JVET_M0502_PRED_MODE_CTX - { 193, 193, }, - { 151, 151, }, + { 192, 168, }, + { 165, 139, }, { CNU, CNU, }, - { 1, 1, }, + { 5, 2, }, #else { 193,}, { 151,}, @@ -546,10 +546,10 @@ const CtxSet ContextSetCfg::PredMode = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MultiRefLineIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 90, 212, CNU,}, - { 118, 212, CNU,}, - { 134, 184, CNU,}, - { 8, 8, DWS,}, + { 90, 212, CNU, }, + { 118, 212, CNU, }, + { 119, 169, CNU, }, + { 8, 8, DWS, }, #else { 151, 183, CNU, }, { 165, 183, CNU, }, @@ -557,43 +557,31 @@ const CtxSet ContextSetCfg::MultiRefLineIdx = ContextSetCfg::addCtxSet #endif }); -const CtxSet ContextSetCfg::IPredMode[] = -{ - ContextSetCfg::addCtxSet - ({ +const CtxSet ContextSetCfg::IntraLumaMpmFlag = ContextSetCfg::addCtxSet +({ #if JVET_M0453_CABAC_ENGINE - { 169,}, - { 169,}, - { 156,}, - { 1,}, + { 154, }, + { 154, }, + { 170, }, + { 6, }, #else { 183, }, { 154, }, { 156, }, #endif - }), - ContextSetCfg::addCtxSet - ({ -#if JVET_M0453_CABAC_ENGINE - { CNU, 137, 139, 140, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU,}, - { CNU, 138, 139, 169, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU,}, - { CNU, 154, 139, 154, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU,}, - { DWS, 5, 8, 9, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, }, -#else - { CNU, 152, 139, 154, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, - { CNU, 138, 139, 169, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, - { CNU, 109, 139, 154, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, -#endif - }), -}; +}); -const CtxSet ContextSetCfg::PdpcFlag = ContextSetCfg::addCtxSet +const CtxSet ContextSetCfg::IntraChromaPredMode = ContextSetCfg::addCtxSet ({ - { 107,}, - { 107,}, - { 139,}, #if JVET_M0453_CABAC_ENGINE - { DWS, } + { 137, 139, 140,}, + { 138, 139, 169,}, + { 154, 139, 154,}, + { 5, 8, 9,}, +#else + { 152, 139, 154,}, + { 138, 139, 169,}, + { 109, 139, 154,}, #endif }); @@ -610,10 +598,10 @@ const CtxSet ContextSetCfg::DeltaQP = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::InterDir = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 126, 125, 110, 79, 208,}, - { 126, 111, 110, 79, 224,}, - { CNU, CNU, CNU, CNU, CNU,}, - { 0, 1, 4, 5, 0,}, + { 111, 125, 110, 94, 192, }, + { 126, 111, 110, 94, 208, }, + { CNU, CNU, CNU, CNU, CNU, }, + { 0, 0, 4, 5, 0, }, #else { 111, 110, 95, 78, 193, }, { 126, 111, 95, 93, 194, }, @@ -624,10 +612,10 @@ const CtxSet ContextSetCfg::InterDir = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::RefPic = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 110, 139,}, - { 108, 168,}, - { CNU, CNU,}, - { 4, 5,}, + { 125, 139, }, + { 138, 168, }, + { CNU, CNU, }, + { 4, 5, }, #else { 139, 139, }, { 138, 168, }, @@ -638,10 +626,10 @@ const CtxSet ContextSetCfg::RefPic = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::AffineFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 194, 169, 156,}, - { 180, 182, 155,}, - { CNU, CNU, CNU,}, - { 8, 5, 4,}, + { 179, 169, 171, }, + { 180, 168, 155, }, + { CNU, CNU, CNU, }, + { 8, 5, 4, }, #else { 196, 184, 171, }, { 181, 169, 185, }, @@ -653,9 +641,9 @@ const CtxSet ContextSetCfg::AffineType = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE { 138, }, - { 138, }, + { 153, }, { CNU, }, - { 4,}, + { 4, }, #else { 123, }, { 138, }, @@ -666,25 +654,38 @@ const CtxSet ContextSetCfg::AffineType = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::AffMergeIdx = ContextSetCfg::addCtxSet ( { #if JVET_M0453_CABAC_ENGINE +#if JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX + { 109, }, + { 95, }, + { CNU, }, + { 0, }, +#else { 109, 168, 168, 153, CNU,}, { 95, 154, 139, 153, CNU,}, { CNU, CNU, CNU, CNU, CNU,}, { 0, 5, 9, 8, DWS,}, +#endif +#else +#if JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX + { 123, }, + { 109, }, + { CNU, }, #else { 123, 154, 154, 168, CNU, }, { 109, 154, 139, 168, CNU, }, { CNU, CNU, CNU, CNU, CNU, }, #endif +#endif } ); const CtxSet ContextSetCfg::GBiIdx = ContextSetCfg::addCtxSet ({ // 4 ctx for 1st bin; 1 ctx for each of rest bins #if JVET_M0453_CABAC_ENGINE - { 228, CNU, CNU, CNU, 154, 170, 143,}, - { 242, CNU, CNU, CNU, 154, 185, 175,}, - { CNU, CNU, CNU, CNU, CNU, CNU, CNU,}, - { 4, DWS, DWS, DWS, 4, 0, 0,}, + { 228, CNU, CNU, CNU, 125, 155, 175, }, + { 242, CNU, CNU, CNU, 154, 170, 237, }, + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, + { 4, DWS, DWS, DWS, 4, 0, 0, }, #else { 199, CNU, CNU, CNU, 124, 169, 127, }, { 154, CNU, CNU, CNU, 124, 185, 143, }, @@ -696,9 +697,9 @@ const CtxSet ContextSetCfg::Mvd = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE { 169, 183, }, - { 155, 154,}, - { CNU, CNU, }, - { 9, 5,}, + { 155, 154, }, + { 141, 156, }, + { 9, 5, }, #else { 169, 183, }, { 155, 198, }, @@ -706,23 +707,13 @@ const CtxSet ContextSetCfg::Mvd = ContextSetCfg::addCtxSet #endif }); -const CtxSet ContextSetCfg::TransSubdivFlag = ContextSetCfg::addCtxSet -({ - { 224, 167, 122, 122, 122}, - { 124, 138, 94, 94, 94}, - { 153, 138, 138, 138, 138}, -#if JVET_M0453_CABAC_ENGINE - { DWS, DWS, DWS, DWS, DWS, } -#endif -}); - const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 94,}, - { 94,}, - { CNU,}, - { 4,}, + { 109, }, + { 95, }, + { 110, }, + { 4, }, #else { 94, }, { 95, }, @@ -732,6 +723,24 @@ const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::QtCbf[] = { +#if JVET_M0102_INTRA_SUBPARTITIONS +#if JVET_M0453_CABAC_ENGINE + ContextSetCfg::addCtxSet + ({ + { 141, 127, 139, 140, }, + { 142, 127, 139, 140, }, + { CNU, 111, 124, 111, }, + { 1, 5, 9, 8, }, + }), +#else + ContextSetCfg::addCtxSet + ({ + { 140, 141, CNU, CNU}, + { 155, 127, CNU, CNU}, + { CNU, 126, CNU, CNU}, + }), +#endif +#else ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE @@ -745,13 +754,14 @@ const CtxSet ContextSetCfg::QtCbf[] = { CNU, 126, }, #endif }), +#endif ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 178, 154, CNU, CNU, CNU,}, - { 164, 154, CNU, CNU, CNU,}, - { 109, CNU, CNU, CNU, CNU,}, - { 5, 4, DWS, DWS, DWS, }, + { 163, 154, CNU, CNU, CNU, }, + { 164, 154, CNU, CNU, CNU, }, + { 109, CNU, CNU, CNU, CNU, }, + { 5, 8, DWS, DWS, DWS, }, #else { 149, 168, CNU, CNU, CNU, }, { 164, 154, CNU, CNU, CNU, }, @@ -761,10 +771,10 @@ const CtxSet ContextSetCfg::QtCbf[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 162, 154,}, - { 192, 154,}, - { 151, 155,}, - { 5, 4, }, + { 161, 154, }, + { 192, 154, }, + { 151, 155, }, + { 5, 5, }, #else { 192, 153, }, { 178, 139, }, @@ -778,10 +788,10 @@ const CtxSet ContextSetCfg::SigCoeffGroup[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 120, 185,}, - { 106, 171,}, - { 107, 159,}, - { 8, 5, }, + { 105, 155, }, + { 106, 156, }, + { 107, 158, }, + { 8, 5, }, #else { 106, 170, }, { 121, 141, }, @@ -791,10 +801,10 @@ const CtxSet ContextSetCfg::SigCoeffGroup[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 91, 141,}, - { 90, 156,}, - { 76, 127,}, - { 8, 8, }, + { 91, 155, }, + { 90, 141, }, + { 76, 127, }, + { 5, 8, }, #else { 91, 140, }, { 105, 155, }, @@ -803,18 +813,18 @@ const CtxSet ContextSetCfg::SigCoeffGroup[] = }), ContextSetCfg::addCtxSet ({ - { 122, 143, }, - { 78, 111, }, - { 135, 155, }, + { CNU, CNU, }, + { CNU, CNU, }, + { CNU, CNU, }, #if JVET_M0453_CABAC_ENGINE { DWS, DWS, } #endif }), ContextSetCfg::addCtxSet ({ - { 91, 141, }, - { 60, 140, }, - { 104, 139, }, + { CNU, CNU, }, + { CNU, CNU, }, + { CNU, CNU, }, #if JVET_M0453_CABAC_ENGINE { DWS, DWS, } #endif @@ -826,10 +836,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 104, 137, 152, 182, 168, 169, 161, 167, 182, 168, 183, 170, 208, 213, 183, 183, 169, 185,}, - { 133, 152, 167, 168, 183, 140, 163, 182, 168, 183, 169, 170, 166, 213, 183, 169, 184, 156,}, - { 104, 138, 153, 139, 125, 111, 134, 139, 139, 140, 155, 127, 137, 185, 169, 185, 156, 143,}, - { 12, 9, 9, 9, 9, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, }, + { 88, 166, 152, 182, 168, 154, 0, 167, 182, 168, 183, 155, 193, 213, 183, 183, 169, 185, }, + { 132, 152, 167, 168, 183, 140, 177, 182, 168, 154, 169, 155, 180, 213, 183, 169, 184, 156, }, + { 89, 138, 153, 139, 154, 140, 134, 139, 139, 140, 140, 141, 137, 170, 169, 170, 141, 157, }, + { 12, 9, 9, 9, 9, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9, }, #else { 105, 152, 167, 153, 168, 169, 104, 167, 182, 183, 183, 170, 209, 213, 183, 183, 169, 185, }, { 119, 152, 167, 168, 183, 140, 134, 182, 168, 183, 169, 185, 166, 228, 183, 198, 184, 156, }, @@ -839,10 +849,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 133, 167, 153, 168, 154, 155, 151, 199, 183, 199, 199, 157,}, - { 104, 138, 153, 139, 154, 155, 181, 229, 169, 229, 170, 157,}, - { 74, 153, 168, 169, 140, 141, 152, 215, 155, 172, 171, 143,}, - { 9, 9, 12, 9, 9, 13, 8, 5, 8, 8, 8, 9, }, + { 72, 167, 153, 168, 154, 155, 180, 199, 183, 199, 199, 186, }, + { 133, 138, 153, 139, 154, 140, 181, 229, 169, 229, 170, 157, }, + { 43, 153, 168, 169, 154, 155, 152, 215, 155, 201, 171, 143, }, + { 9, 9, 12, 9, 13, 13, 5, 5, 8, 8, 8, 9, }, #else { 148, 167, 153, 168, 154, 140, 166, 199, 183, 199, 199, 172, }, { 134, 168, 168, 169, 169, 170, 196, 244, 184, 244, 200, 172, }, @@ -852,10 +862,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 152, 127, 187, 201, 172, 173, 197, 248, 188, 232, 188, 205, 182, 223, 223, 223, 223, 223,}, - { 123, 142, 172, 172, 172, 218, 138, 248, 248, 248, 248, 223, 139, 223, 223, 223, 223, 223,}, - { 93, 157, 143, 158, 203, 190, 123, 223, 175, 253, 253, 223, 124, 223, 223, 223, 223, 223,}, - { 9, 12, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, }, + { 152, 156, 201, 186, 186, 187, 182, 248, 188, 232, 188, 205, 182, 223, 223, 223, 223, 223, }, + { 123, 142, 157, 172, 172, 218, 138, 249, 248, 248, 219, 223, 139, 223, 223, 223, 223, 223, }, + { 93, 142, 157, 143, 188, 175, 138, 238, 205, 238, 253, 237, 139, 223, 223, 223, 223, 253, }, + { 9, 12, 8, 8, 8, 8, 8, 8, 8, 8, 8, 5, 8, 0, 0, 0, 0, 0, }, #else { 152, 127, 173, 201, 187, 173, 197, 203, 188, 217, 188, 189, 182, 223, 223, 223, 223, 223, }, { 123, 142, 202, 172, 172, 203, 138, 188, 233, 203, 203, 191, 139, 223, 223, 223, 223, 223, }, @@ -865,10 +875,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 182, 171, 143, 158, 172, 189, 183, 223, 223, 223, 223, 223,}, - { 168, 156, 173, 201, 172, 204, 169, 223, 223, 223, 223, 223,}, - { 152, 173, 157, 187, 189, 252, 170, 223, 223, 223, 223, 223,}, - { 8, 9, 12, 8, 8, 8, 4, 0, 0, 0, 0, 0, }, + { 182, 171, 143, 158, 172, 189, 183, 223, 223, 223, 223, 223, }, + { 168, 156, 173, 216, 172, 219, 169, 223, 223, 223, 223, 223, }, + { 152, 173, 157, 187, 204, 253, 170, 223, 223, 223, 223, 223, }, + { 8, 9, 12, 8, 8, 8, 4, 0, 2, 2, 2, 2, }, #else { 182, 171, 143, 158, 172, 202, 168, 223, 223, 223, 223, 223, }, { 168, 156, 173, 201, 157, 203, 198, 223, 223, 223, 223, 223, }, @@ -878,10 +888,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 123, 158, 223, 175, 217, 205, 212, 223, 223, 220, 205, 223, 208, 223, 223, 223, 223, 223,}, - { 123, 174, 223, 189, 203, 221, 138, 223, 223, 223, 190, 223, 196, 223, 223, 223, 223, 223,}, - { 107, 159, 223, 191, 205, 253, 63, 223, 223, 223, 223, 223, 14, 223, 223, 223, 223, 223,}, - { 8, 8, 4, 8, 8, 8, 8, 0, 0, 4, 8, 8, 4, 0, 0, 0, 0, 0, }, + { 123, 173, 223, 191, 232, 251, 212, 223, 223, 236, 206, 223, 192, 223, 223, 223, 223, 223, }, + { 123, 175, 223, 175, 218, 223, 138, 223, 223, 223, 222, 223, 196, 223, 223, 223, 223, 223, }, + { 107, 174, 223, 238, 251, 223, 63, 223, 223, 238, 223, 238, 12, 223, 223, 223, 223, 223, }, + { 8, 8, 4, 8, 8, 8, 8, 0, 0, 4, 8, 5, 4, 2, 2, 2, 2, 1, }, #else { 137, 142, 190, 188, 202, 189, 241, 191, 191, 189, 189, 190, 195, 223, 223, 223, 223, 223, }, { 123, 187, 191, 173, 173, 248, 138, 191, 191, 191, 203, 191, 196, 223, 223, 223, 223, 223, }, @@ -891,10 +901,10 @@ const CtxSet ContextSetCfg::SigFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 167, 201, 223, 233, 189, 223, 181, 223, 223, 223, 223, 223,}, - { 167, 171, 223, 174, 233, 223, 152, 223, 223, 223, 223, 223,}, - { 166, 219, 223, 235, 233, 252, 123, 223, 223, 223, 223, 223,}, - { 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, }, + { 167, 201, 223, 248, 219, 223, 181, 223, 223, 223, 223, 223, }, + { 167, 171, 223, 175, 248, 223, 152, 223, 223, 223, 223, 223, }, + { 166, 234, 223, 236, 248, 223, 108, 223, 223, 223, 223, 223, }, + { 8, 8, 5, 8, 8, 8, 5, 1, 2, 2, 2, 2, }, #else { 167, 200, 175, 188, 174, 175, 196, 223, 223, 223, 223, 223, }, { 167, 156, 237, 158, 188, 205, 182, 223, 223, 223, 223, 223, }, @@ -909,10 +919,10 @@ const CtxSet ContextSetCfg::ParFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 121, 119, 121, 137, 138, 153, 90, 122, 167, 153, 168, 121, 152, 153, 168, 139, 151, 153, 139, 168, 154,}, - { 121, 119, 136, 152, 138, 153, 119, 122, 138, 153, 139, 121, 138, 153, 168, 139, 137, 153, 168, 139, 139,}, - { 121, 135, 137, 152, 138, 153, 91, 137, 138, 153, 139, 151, 138, 153, 139, 139, 138, 168, 139, 154, 139,}, - { 8, 9, 12, 13, 13, 13, 10, 13, 13, 13, 13, 10, 13, 13, 13, 13, 10, 10, 13, 13, 13, }, + { 121, 105, 136, 152, 138, 183, 90, 122, 167, 153, 168, 135, 152, 153, 168, 139, 151, 153, 139, 168, 154, }, + { 121, 119, 136, 137, 138, 153, 104, 122, 138, 153, 139, 106, 138, 153, 168, 139, 137, 153, 168, 139, 139, }, + { 121, 135, 137, 152, 138, 153, 91, 137, 138, 153, 139, 151, 138, 153, 139, 139, 138, 168, 139, 154, 139, }, + { 8, 9, 12, 13, 13, 13, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 13, 13, 13, 13, }, #else { 91, 104, 136, 152, 153, 153, 105, 137, 167, 153, 168, 121, 167, 153, 168, 139, 151, 153, 139, 168, 154, }, { 106, 134, 151, 152, 138, 168, 120, 137, 138, 153, 139, 136, 138, 153, 168, 139, 137, 153, 168, 139, 139, }, @@ -922,10 +932,10 @@ const CtxSet ContextSetCfg::ParFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 136, 120, 152, 138, 138, 153, 136, 168, 154, 168, 139,}, - { 135, 120, 137, 138, 138, 153, 136, 153, 168, 139, 154,}, - { 136, 135, 152, 153, 138, 153, 136, 168, 154, 139, 154,}, - { 8, 10, 12, 12, 13, 13, 10, 10, 10, 12, 13, }, + { 151, 120, 152, 138, 153, 153, 136, 168, 154, 168, 154, }, + { 135, 120, 137, 138, 138, 153, 136, 153, 168, 139, 154, }, + { 136, 135, 152, 153, 138, 153, 136, 168, 154, 139, 154, }, + { 8, 10, 12, 12, 13, 13, 10, 10, 13, 13, 13, }, #else { 135, 135, 152, 138, 153, 124, 151, 168, 169, 153, 139, }, { 120, 150, 152, 153, 153, 153, 166, 168, 168, 139, 154, }, @@ -939,10 +949,10 @@ const CtxSet ContextSetCfg::GtxFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 60, 0, 102, 119, 150, 137, 42, 44, 120, 136, 123, 86, 119, 151, 152, 153, 104, 136, 138, 153, 125,}, - { 44, 0, 41, 119, 135, 137, 0, 88, 135, 151, 138, 116, 105, 122, 167, 153, 119, 107, 123, 153, 154,}, - { 75, 86, 148, 150, 151, 138, 43, 75, 77, 137, 109, 58, 106, 108, 109, 124, 121, 138, 139, 154, 140,}, - { 4, 5, 9, 9, 9, 6, 5, 9, 8, 9, 9, 9, 9, 8, 8, 8, 9, 8, 8, 8, 8, }, + { 31, 73, 118, 75, 152, 109, 42, 44, 105, 107, 109, 0, 119, 136, 152, 124, 118, 136, 138, 153, 140, }, + { 14, 116, 86, 119, 106, 152, 0, 72, 120, 151, 138, 116, 90, 107, 152, 153, 104, 107, 123, 153, 154, }, + { 90, 72, 119, 135, 137, 138, 43, 60, 106, 137, 109, 58, 106, 108, 109, 124, 121, 138, 139, 154, 155, }, + { 4, 1, 8, 8, 4, 2, 5, 9, 9, 8, 9, 9, 9, 9, 8, 9, 9, 8, 9, 8, 8, }, #else { 30, 0, 102, 104, 106, 152, 57, 44, 120, 136, 123, 87, 134, 151, 152, 153, 89, 121, 152, 153, 125, }, { 88, 0, 102, 149, 150, 152, 101, 103, 150, 151, 138, 102, 105, 122, 167, 153, 90, 107, 123, 153, 154, }, @@ -952,10 +962,10 @@ const CtxSet ContextSetCfg::GtxFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 119, 11, 105, 107, 107, 108, 104, 122, 124, 140, 140,}, - { 117, 101, 90, 106, 92, 78, 88, 136, 138, 154, 125,}, - { 194, 56, 105, 122, 122, 123, 118, 106, 153, 154, 140,}, - { 2, 5, 8, 8, 8, 8, 6, 9, 8, 8, 9, }, + { 119, 101, 134, 151, 107, 123, 118, 122, 124, 140, 155, }, + { 117, 0, 90, 106, 92, 93, 147, 136, 138, 154, 140, }, + { 194, 40, 120, 122, 122, 138, 103, 121, 153, 154, 155, }, + { 2, 5, 8, 8, 8, 6, 6, 8, 8, 8, 7, }, #else { 102, 101, 90, 107, 122, 93, 118, 121, 153, 125, 140, }, { 0, 0, 105, 151, 107, 93, 103, 136, 138, 154, 125, }, @@ -965,10 +975,10 @@ const CtxSet ContextSetCfg::GtxFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 88, 147, 151, 138, 139, 140, 133, 167, 124, 154, 155, 164, 153, 154, 169, 155, 166, 183, 169, 185, 186,}, - { 101, 133, 137, 153, 139, 140, 134, 138, 139, 169, 155, 121, 153, 154, 140, 170, 152, 154, 155, 170, 186,}, - { 119, 120, 123, 153, 139, 140, 121, 153, 139, 125, 126, 152, 154, 140, 155, 141, 139, 140, 185, 171, 157,}, - { 8, 5, 10, 12, 13, 10, 9, 9, 10, 12, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, }, + { 43, 177, 181, 168, 154, 170, 133, 167, 139, 154, 155, 164, 153, 154, 169, 155, 181, 183, 169, 185, 186, }, + { 101, 133, 137, 153, 139, 140, 134, 138, 139, 154, 155, 136, 153, 154, 140, 170, 138, 154, 155, 170, 186, }, + { 134, 120, 123, 153, 139, 140, 92, 124, 154, 125, 111, 138, 154, 140, 155, 141, 154, 140, 185, 171, 143, }, + { 8, 5, 9, 9, 12, 9, 9, 10, 13, 12, 10, 9, 10, 10, 10, 10, 8, 9, 8, 8, 10, }, #else { 89, 132, 151, 138, 124, 125, 119, 152, 153, 154, 140, 135, 153, 139, 169, 155, 151, 168, 169, 170, 171, }, { 118, 101, 137, 138, 139, 140, 149, 138, 139, 154, 155, 136, 153, 154, 140, 170, 152, 139, 140, 155, 186, }, @@ -978,10 +988,10 @@ const CtxSet ContextSetCfg::GtxFlag[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 116, 164, 153, 154, 140, 140, 196, 170, 171, 157, 158,}, - { 117, 150, 153, 139, 125, 140, 167, 155, 156, 142, 173,}, - { 134, 136, 153, 154, 125, 111, 168, 170, 201, 172, 173,}, - { 6, 9, 10, 12, 12, 9, 8, 9, 8, 8, 9, }, + { 0, 178, 153, 154, 140, 140, 196, 170, 186, 157, 188, }, + { 0, 135, 153, 139, 125, 140, 182, 155, 156, 142, 159, }, + { 163, 136, 153, 154, 125, 140, 183, 170, 201, 187, 174, }, + { 6, 9, 10, 12, 12, 10, 5, 9, 8, 8, 9, }, #else { 102, 164, 138, 139, 154, 140, 181, 155, 171, 157, 143, }, { 132, 136, 153, 154, 140, 155, 167, 155, 156, 142, 173, }, @@ -995,10 +1005,10 @@ const CtxSet ContextSetCfg::LastX[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 111, 111, 110, 111, 111, 124, 111, 111, 111, 95, 126, 126, 111, 111, 169, 154, 111, 110, 110, 123, CNU, CNU, CNU, CNU, CNU,}, - { 125, 110, 109, 111, 125, 123, 111, 111, 95, 108, 126, 126, 110, 95, 183, 154, 140, 110, 124, 137, CNU, CNU, CNU, CNU, CNU,}, - { 140, 140, 124, 111, 126, 109, 111, 126, 125, 123, 126, 127, 111, 110, 93, 141, 157, 126, 125, 182, CNU, CNU, CNU, CNU, CNU,}, - { 8, 8, 5, 5, 4, 4, 5, 4, 4, 0, 5, 4, 0, 0, 0, 1, 1, 1, 0, 8, DWS, DWS, DWS, DWS, DWS, }, + { 111, 111, 110, 111, 111, 139, 111, 126, 111, 139, 126, 126, 111, 111, 169, 154, 111, 110, 110, 139, CNU, CNU, CNU, CNU, CNU, }, + { 125, 110, 109, 125, 125, 123, 111, 111, 95, 123, 126, 111, 110, 95, 169, 154, 140, 139, 139, 138, CNU, CNU, CNU, CNU, CNU, }, + { 125, 140, 124, 111, 111, 109, 111, 126, 125, 123, 111, 141, 111, 125, 79, 155, 142, 170, 140, 183, CNU, CNU, CNU, CNU, CNU, }, + { 8, 5, 5, 5, 4, 4, 5, 4, 4, 0, 5, 1, 0, 0, 0, 1, 1, 0, 0, 0, DWS, DWS, DWS, DWS, DWS, }, #else { 111, 125, 124, 111, 111, 109, 111, 111, 125, 109, 140, 126, 111, 111, 139, 140, 111, 125, 95, 138, CNU, CNU, CNU, CNU, CNU, }, { 125, 110, 109, 111, 125, 123, 111, 111, 95, 123, 140, 126, 125, 95, 169, 125, 140, 110, 124, 152, CNU, CNU, CNU, CNU, CNU, }, @@ -1008,10 +1018,10 @@ const CtxSet ContextSetCfg::LastX[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 137, 109, 62, CNU,}, - { 138, 123, 92, CNU,}, - { 138, 108, 61, CNU,}, - { 2, 4, 4, DWS, }, + { 122, 124, 63, CNU, }, + { 138, 123, 92, CNU, }, + { 138, 108, 47, CNU, }, + { 2, 1, 1, DWS, }, #else { 123, 109, 63, CNU, }, { 138, 123, 92, CNU, }, @@ -1025,10 +1035,10 @@ const CtxSet ContextSetCfg::LastY[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 125, 125, 139, 111, 111, 124, 111, 111, 110, 110, 140, 126, 110, 95, 155, 154, 111, 110, 124, 180, CNU, CNU, CNU, CNU, CNU,}, - { 110, 95, 109, 125, 110, 93, 125, 111, 124, 108, 140, 111, 95, 109, 153, 125, 126, 110, 109, 181, CNU, CNU, CNU, CNU, CNU,}, - { 110, 110, 109, 125, 111, 108, 111, 126, 95, 93, 111, 127, 111, 95, 47, 155, 158, 156, 140, 137, CNU, CNU, CNU, CNU, CNU,}, - { 8, 5, 8, 5, 5, 4, 5, 5, 4, 0, 5, 5, 1, 0, 0, 1, 4, 1, 0, 8, DWS, DWS, DWS, DWS, DWS, }, + { 125, 125, 139, 125, 111, 139, 111, 111, 110, 110, 140, 126, 125, 125, 140, 139, 111, 110, 124, 181, CNU, CNU, CNU, CNU, CNU, }, + { 95, 95, 109, 110, 110, 108, 125, 111, 124, 123, 140, 111, 110, 124, 139, 125, 126, 110, 124, 182, CNU, CNU, CNU, CNU, CNU, }, + { 110, 110, 109, 125, 111, 123, 111, 126, 95, 108, 111, 127, 111, 95, 78, 169, 157, 141, 125, 138, CNU, CNU, CNU, CNU, CNU, }, + { 8, 5, 8, 5, 5, 4, 5, 5, 4, 0, 5, 5, 1, 0, 0, 1, 4, 1, 0, 0, DWS, DWS, DWS, DWS, DWS, }, #else { 125, 110, 139, 125, 125, 109, 111, 111, 110, 109, 140, 126, 110, 110, 154, 140, 111, 125, 109, 181, CNU, CNU, CNU, CNU, CNU, }, { 110, 95, 94, 125, 110, 123, 140, 111, 95, 123, 125, 111, 110, 95, 154, 125, 111, 95, 94, 137, CNU, CNU, CNU, CNU, CNU, }, @@ -1038,10 +1048,10 @@ const CtxSet ContextSetCfg::LastY[] = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 137, 109, 122, CNU,}, - { 108, 108, 136, CNU,}, - { 123, 123, 91, CNU,}, - { 2, 5, 5, DWS, }, + { 122, 124, 123, CNU, }, + { 108, 123, 121, CNU, }, + { 123, 123, 91, CNU, }, + { 2, 2, 2, DWS, }, #else { 108, 94, 122, CNU, }, { 108, 93, 92, CNU, }, @@ -1054,10 +1064,10 @@ const CtxSet ContextSetCfg::LastY[] = const CtxSet ContextSetCfg::MVPIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 153,}, + { 153, }, { 168, }, - { CNU, }, - { 10,}, + { 168, }, + { 10, }, #else { 168, }, { 168, }, @@ -1069,10 +1079,10 @@ const CtxSet ContextSetCfg::MVPIdx = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::SmvdFlag = ContextSetCfg::addCtxSet ( { { 154, }, - { 110, }, + { 125, }, { CNU, }, #if JVET_M0453_CABAC_ENGINE - { DWS, } + { 8, }, #endif } ); #endif @@ -1080,10 +1090,10 @@ const CtxSet ContextSetCfg::SmvdFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::SaoMergeFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 63,}, - { 244,}, - { 199,}, - { 0,}, + { 47, }, + { 244, }, + { 199, }, + { 0, }, #else { 92, }, { 214, }, @@ -1094,10 +1104,10 @@ const CtxSet ContextSetCfg::SaoMergeFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::SaoTypeIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 63,}, - { 95,}, - { 110,}, - { 0,}, + { 47, }, + { 95, }, + { 95, }, + { 0, }, #else { 77, }, { 111, }, @@ -1155,10 +1165,10 @@ const CtxSet ContextSetCfg::RdpcmDir = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MTSIndex = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, - { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, - { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, - { DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, }, + { CNU, 155, 155, 140, 140, CNU, 216, 153, 153, 0, CNU, }, + { CNU, 155, 155, 140, 140, CNU, 233, 167, 153, 0, CNU, }, + { CNU, CNU, 140, 140, 140, CNU, 219, 138, 153, 0, CNU, }, + { DWS, 8, 8, 8, 8, DWS, 4, 8, 9, 3, DWS, }, #else { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, @@ -1195,6 +1205,60 @@ const CtxSet ContextSetCfg::EMTCuFlag = ContextSetCfg::addCtxSet }); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +const CtxSet ContextSetCfg::ISPMode = ContextSetCfg::addCtxSet +({ + { 152, 154, }, + { 166, 154, }, + { 152, 154, }, +#if JVET_M0453_CABAC_ENGINE + { 8, 5, }, +#endif +}); +#endif + +#if JVET_M0140_SBT +const CtxSet ContextSetCfg::SbtFlag = ContextSetCfg::addCtxSet +( { + { 168, 183, }, + { 197, 183, }, + { CNU, CNU, }, +#if JVET_M0453_CABAC_ENGINE + { 4, 8, }, +#endif +} ); + +const CtxSet ContextSetCfg::SbtQuadFlag = ContextSetCfg::addCtxSet +( { + { 168, }, + { 168, }, + { CNU, }, +#if JVET_M0453_CABAC_ENGINE + { 9, }, +#endif +} ); + +const CtxSet ContextSetCfg::SbtHorFlag = ContextSetCfg::addCtxSet +( { + { 139, 154, 139, }, + { 139, 154, 139, }, + { CNU, CNU, CNU, }, +#if JVET_M0453_CABAC_ENGINE + { 8, 5, 4, }, +#endif +} ); + +const CtxSet ContextSetCfg::SbtPosFlag = ContextSetCfg::addCtxSet +( { + { 154, }, + { 154, }, + { CNU, }, +#if JVET_M0453_CABAC_ENGINE + { 13, }, +#endif +} ); +#endif + const CtxSet ContextSetCfg::CrossCompPred = ContextSetCfg::addCtxSet ({ { 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,}, @@ -1228,15 +1292,28 @@ const CtxSet ContextSetCfg::ChromaQpAdjIdc = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::ImvFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE +#if JVET_M0246_AFFINE_AMVR + { 212, 199, 215, 180, 183, 242, }, + { 213, 229, 244, 166, 198, 244, }, + { CNU, CNU, CNU, 152, CNU, CNU, }, + { 1, 4, 4, 5, 1, 0, }, +#else { 227, 214, 230, 195,}, { 213, 229, 230, 166,}, { CNU, CNU, CNU, CNU,}, { 1, 4, 4, 5,}, +#endif +#else +#if JVET_M0246_AFFINE_AMVR + { 212, 214, 230, 182, 212, 214 }, + { 212, 214, 230, 182, 212, 214 }, + { CNU, CNU, CNU, CNU, CNU, CNU }, #else { 212, 214, 230, 182, }, { 212, 214, 230, 182, }, { CNU, CNU, CNU, CNU, }, #endif +#endif }); const CtxSet ContextSetCfg::ctbAlfFlag = @@ -1244,10 +1321,10 @@ const CtxSet ContextSetCfg::ctbAlfFlag = ContextSetCfg::addCtxSet ( { #if JVET_M0453_CABAC_ENGINE - { 154, 201, 203, 168, 247, 249, 168, 248, 235,}, - { 139, 186, 203, 168, 247, 249, 168, 247, 234,}, - { 219, 237, 253, 187, 234, 235, 216, 219, 250,}, - { 0, 0, 4, 0, 0, 0, 0, 0, 0, }, + { 154, 186, 174, 183, 233, 250, 168, 248, 250, }, + { 139, 186, 203, 183, 247, 249, 183, 232, 249, }, + { 219, 236, 238, 232, 249, 235, 246, 234, 251, }, + { 0, 0, 4, 0, 0, 1, 0, 0, 1, }, #else { 138, 141, 173, 122, 170, 203, 151, 170, 203, }, { 153, 156, 188, 137, 185, 218, 152, 185, 218, }, @@ -1259,10 +1336,10 @@ const CtxSet ContextSetCfg::ctbAlfFlag = const CtxSet ContextSetCfg::MHIntraFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 240,}, - { 197,}, - { CNU,}, - { 1,}, + { 225, }, + { 197, }, + { CNU, }, + { 1, }, #else { 226, }, { 227, }, @@ -1273,10 +1350,10 @@ const CtxSet ContextSetCfg::MHIntraFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MHIntraPredMode = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 156, CNU, CNU, CNU,}, - { 156, CNU, CNU, CNU,}, - { CNU, CNU, CNU, CNU,}, - { 9, DWS, DWS, DWS,}, + { 156, CNU, CNU, CNU, }, + { 156, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, }, + { 9, DWS, DWS, DWS, }, #else { 155, CNU, CNU, CNU, }, { 141, CNU, CNU, CNU, }, @@ -1287,10 +1364,10 @@ const CtxSet ContextSetCfg::MHIntraPredMode = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::TriangleFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 149, 137, 137,}, - { 165, 151, 137,}, - { CNU, CNU, CNU,}, - { 9, 13, 10,}, + { 149, 123, 123, }, + { 151, 152, 138, }, + { CNU, CNU, CNU, }, + { 8, 12, 9, }, #else { 165, 137, 153, }, { 106, 122, 138, }, @@ -1301,10 +1378,10 @@ const CtxSet ContextSetCfg::TriangleFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::TriangleIdx = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE - { 141,}, - { 141,}, - { CNU,}, - { 8,}, + { CNU, }, + { CNU, }, + { CNU, }, + { DWS, }, #else { 155, }, { 126, }, @@ -1313,6 +1390,22 @@ const CtxSet ContextSetCfg::TriangleIdx = ContextSetCfg::addCtxSet }); // clang-format on +#if JVET_M0483_IBC +const CtxSet ContextSetCfg::IBCFlag = ContextSetCfg::addCtxSet +({ +#if JVET_M0453_CABAC_ENGINE + { 0, 154, 141, }, + { 0, 153, 140, }, + { 132, 153, 125, }, + { 5, 5, 8, }, +#else + { 165, 137, 153, }, + { 106, 122, 138, }, + { CNU, CNU, CNU, }, +#endif +}); +#endif + const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_InitTables[0].size(); diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index fcc59f0152a14eddf03460f23822adff43834592..79bfc51f179f0abd347614993a7c6d096a82e796 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -258,8 +258,8 @@ public: static const CtxSet PartSize; static const CtxSet PredMode; static const CtxSet MultiRefLineIdx; - static const CtxSet IPredMode [2]; // [ ChannelType ] - static const CtxSet PdpcFlag; + static const CtxSet IntraLumaMpmFlag; + static const CtxSet IntraChromaPredMode; static const CtxSet DeltaQP; static const CtxSet InterDir; static const CtxSet RefPic; @@ -270,7 +270,6 @@ public: static const CtxSet AffineType; static const CtxSet AffMergeIdx; static const CtxSet Mvd; - static const CtxSet TransSubdivFlag; static const CtxSet QtRootCbf; static const CtxSet QtCbf [3]; // [ channel ] static const CtxSet SigCoeffGroup [4]; // [ ChannelType ] @@ -293,6 +292,12 @@ public: #if !JVET_M0464_UNI_MTS static const CtxSet EMTTuIndex; static const CtxSet EMTCuFlag; +#endif +#if JVET_M0140_SBT + static const CtxSet SbtFlag; + static const CtxSet SbtQuadFlag; + static const CtxSet SbtHorFlag; + static const CtxSet SbtPosFlag; #endif static const CtxSet CrossCompPred; static const CtxSet ChromaQpAdjFlag; @@ -306,6 +311,12 @@ public: static const CtxSet TriangleIdx; #if JVET_M0444_SMVD static const CtxSet SmvdFlag; +#endif +#if JVET_M0483_IBC + static const CtxSet IBCFlag; +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + static const CtxSet ISPMode; #endif static const unsigned NumberOfContexts; diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp index 820920082c726b577d39675070e5048683ce6888..e318345f2149e2d9184dd63a27153fdf0e3b2226 100644 --- a/source/Lib/CommonLib/DepQuant.cpp +++ b/source/Lib/CommonLib/DepQuant.cpp @@ -87,6 +87,10 @@ namespace DQIntern NbInfoSbb nextNbInfoSbb; int nextSbbRight; int nextSbbBelow; +#if JVET_M0297_32PT_MTS_ZERO_OUT + int posX; + int posY; +#endif }; class Rom; @@ -111,10 +115,8 @@ namespace DQIntern unsigned m_widthInSbb; unsigned m_heightInSbb; CoeffScanType m_scanType; - const unsigned* m_scanSbbId2SbbPos; - const unsigned* m_scanId2BlkPos; - const unsigned* m_scanId2PosX; - const unsigned* m_scanId2PosY; + const ScanElement *m_scanSbbId2SbbPos; + const ScanElement *m_scanId2BlkPos; const NbInfoSbb* m_scanId2NbInfoSbb; const NbInfoOut* m_scanId2NbInfoOut; ScanInfo* m_scanInfo; @@ -128,8 +130,13 @@ namespace DQIntern Rom() : m_scansInitialized(false) {} ~Rom() { xUninitScanArrays(); } void init () { xInitScanArrays(); } +#if JVET_M0102_INTRA_SUBPARTITIONS + const NbInfoSbb* getNbInfoSbb( int hd, int vd, int ch ) const { return m_scanId2NbInfoSbbArray[hd][vd][ch]; } + const NbInfoOut* getNbInfoOut( int hd, int vd, int ch ) const { return m_scanId2NbInfoOutArray[hd][vd][ch]; } +#else const NbInfoSbb* getNbInfoSbb( int hd, int vd ) const { return m_scanId2NbInfoSbbArray[hd][vd]; } const NbInfoOut* getNbInfoOut( int hd, int vd ) const { return m_scanId2NbInfoOutArray[hd][vd]; } +#endif const TUParameters* getTUPars ( const CompArea& area, const ComponentID compID ) const { return m_tuParameters[g_aucLog2[area.width]][g_aucLog2[area.height]][toChannelType(compID)]; @@ -139,8 +146,13 @@ namespace DQIntern void xUninitScanArrays (); private: bool m_scansInitialized; +#if JVET_M0102_INTRA_SUBPARTITIONS + NbInfoSbb* m_scanId2NbInfoSbbArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; + NbInfoOut* m_scanId2NbInfoOutArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; +#else NbInfoSbb* m_scanId2NbInfoSbbArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ]; NbInfoOut* m_scanId2NbInfoOutArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ]; +#endif TUParameters* m_tuParameters [ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; }; @@ -155,51 +167,84 @@ namespace DQIntern ::memset( m_tuParameters, 0, sizeof(m_tuParameters) ); uint32_t raster2id[ MAX_CU_SIZE * MAX_CU_SIZE ]; + ::memset(raster2id, 0, sizeof(raster2id)); +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { + for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) + { + for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) + { + if( (hd == 0 && vd <= 1) || (hd <= 1 && vd == 0) ) + { + continue; + } +#else for( int hd = 1; hd <= MAX_CU_DEPTH; hd++ ) { for( int vd = 1; vd <= MAX_CU_DEPTH; vd++ ) { +#endif const uint32_t blockWidth = (1 << hd); const uint32_t blockHeight = (1 << vd); - const uint32_t totalValues = blockWidth * blockHeight; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t log2CGWidth = g_log2SbbSize[ch][hd][vd][0]; + const uint32_t log2CGHeight = g_log2SbbSize[ch][hd][vd][1]; +#else const uint32_t log2CGWidth = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; const uint32_t log2CGHeight = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; +#endif const uint32_t groupWidth = 1 << log2CGWidth; const uint32_t groupHeight = 1 << log2CGHeight; const uint32_t groupSize = groupWidth * groupHeight; const CoeffScanType scanType = SCAN_DIAG; const SizeType blkWidthIdx = gp_sizeIdxInfo->idxFrom( blockWidth ); const SizeType blkHeightIdx = gp_sizeIdxInfo->idxFrom( blockHeight ); - const uint32_t* scanId2RP = g_scanOrder [SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx]; - const uint32_t* scanId2X = g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][0]; - const uint32_t* scanId2Y = g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][1]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const ScanElement * scanId2RP = g_scanOrder[ch][SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx]; + NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd][ch]; + NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd][ch]; +#else + const ScanElement * scanId2RP = g_scanOrder[SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx]; NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd]; NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd]; +#endif + // consider only non-zero-out region +#if JVET_M0257 + const uint32_t blkWidthNZOut = std::min<unsigned>( JVET_C0024_ZERO_OUT_TH, blockWidth ); + const uint32_t blkHeightNZOut= std::min<unsigned>( JVET_C0024_ZERO_OUT_TH, blockHeight ); +#else + const uint32_t blkWidthNZOut = blockWidth; + const uint32_t blkHeightNZOut= blockHeight; +#endif + const uint32_t totalValues = blkWidthNZOut * blkHeightNZOut; sId2NbSbb = new NbInfoSbb[ totalValues ]; sId2NbOut = new NbInfoOut[ totalValues ]; for( uint32_t scanId = 0; scanId < totalValues; scanId++ ) { - raster2id[ scanId2RP[ scanId ] ] = scanId; + raster2id[scanId2RP[scanId].idx] = scanId; } for( unsigned scanId = 0; scanId < totalValues; scanId++ ) { - const int posX = scanId2X [ scanId ]; - const int posY = scanId2Y [ scanId ]; - const int rpos = scanId2RP[ scanId ]; + const int posX = scanId2RP[scanId].x; + const int posY = scanId2RP[scanId].y; + const int rpos = scanId2RP[scanId].idx; { //===== inside subband neighbours ===== NbInfoSbb& nbSbb = sId2NbSbb[ scanId ]; const int begSbb = scanId - ( scanId & (groupSize-1) ); // first pos in current subblock int cpos[5]; - cpos[0] = ( posX < blockWidth -1 ? ( raster2id[rpos+1 ] - begSbb < groupSize ? raster2id[rpos+1 ] - begSbb : 0 ) : 0 ); - cpos[1] = ( posX < blockWidth -2 ? ( raster2id[rpos+2 ] - begSbb < groupSize ? raster2id[rpos+2 ] - begSbb : 0 ) : 0 ); - cpos[2] = ( posX < blockWidth -1 && posY < blockHeight-1 ? ( raster2id[rpos+1+blockWidth] - begSbb < groupSize ? raster2id[rpos+1+blockWidth] - begSbb : 0 ) : 0 ); - cpos[3] = ( posY < blockHeight-1 ? ( raster2id[rpos+ blockWidth] - begSbb < groupSize ? raster2id[rpos+ blockWidth] - begSbb : 0 ) : 0 ); - cpos[4] = ( posY < blockHeight-2 ? ( raster2id[rpos+2*blockWidth] - begSbb < groupSize ? raster2id[rpos+2*blockWidth] - begSbb : 0 ) : 0 ); + + cpos[0] = ( posX + 1 < blkWidthNZOut ? ( raster2id[rpos+1 ] < groupSize + begSbb ? raster2id[rpos+1 ] - begSbb : 0 ) : 0 ); + cpos[1] = ( posX + 2 < blkWidthNZOut ? ( raster2id[rpos+2 ] < groupSize + begSbb ? raster2id[rpos+2 ] - begSbb : 0 ) : 0 ); + cpos[2] = ( posX + 1 < blkWidthNZOut && posY + 1 < blkHeightNZOut ? ( raster2id[rpos+1+blockWidth] < groupSize + begSbb ? raster2id[rpos+1+blockWidth] - begSbb : 0 ) : 0 ); + cpos[3] = ( posY + 1 < blkHeightNZOut ? ( raster2id[rpos+ blockWidth] < groupSize + begSbb ? raster2id[rpos+ blockWidth] - begSbb : 0 ) : 0 ); + cpos[4] = ( posY + 2 < blkHeightNZOut ? ( raster2id[rpos+2*blockWidth] < groupSize + begSbb ? raster2id[rpos+2*blockWidth] - begSbb : 0 ) : 0 ); + for( nbSbb.num = 0; true; ) { int nk = -1; @@ -227,11 +272,13 @@ namespace DQIntern NbInfoOut& nbOut = sId2NbOut[ scanId ]; const int begSbb = scanId - ( scanId & (groupSize-1) ); // first pos in current subblock int cpos[5]; - cpos[0] = ( posX < blockWidth -1 ? ( raster2id[rpos+1 ] - begSbb >= groupSize ? raster2id[rpos+1 ] : 0 ) : 0 ); - cpos[1] = ( posX < blockWidth -2 ? ( raster2id[rpos+2 ] - begSbb >= groupSize ? raster2id[rpos+2 ] : 0 ) : 0 ); - cpos[2] = ( posX < blockWidth -1 && posY < blockHeight-1 ? ( raster2id[rpos+1+blockWidth] - begSbb >= groupSize ? raster2id[rpos+1+blockWidth] : 0 ) : 0 ); - cpos[3] = ( posY < blockHeight-1 ? ( raster2id[rpos+ blockWidth] - begSbb >= groupSize ? raster2id[rpos+ blockWidth] : 0 ) : 0 ); - cpos[4] = ( posY < blockHeight-2 ? ( raster2id[rpos+2*blockWidth] - begSbb >= groupSize ? raster2id[rpos+2*blockWidth] : 0 ) : 0 ); + + cpos[0] = ( posX + 1 < blkWidthNZOut ? ( raster2id[rpos+1 ] >= groupSize + begSbb ? raster2id[rpos+1 ] : 0 ) : 0 ); + cpos[1] = ( posX + 2 < blkWidthNZOut ? ( raster2id[rpos+2 ] >= groupSize + begSbb ? raster2id[rpos+2 ] : 0 ) : 0 ); + cpos[2] = ( posX + 1 < blkWidthNZOut && posY + 1 < blkHeightNZOut ? ( raster2id[rpos+1+blockWidth] >= groupSize + begSbb ? raster2id[rpos+1+blockWidth] : 0 ) : 0 ); + cpos[3] = ( posY + 1 < blkHeightNZOut ? ( raster2id[rpos+ blockWidth] >= groupSize + begSbb ? raster2id[rpos+ blockWidth] : 0 ) : 0 ); + cpos[4] = ( posY + 2 < blkHeightNZOut ? ( raster2id[rpos+2*blockWidth] >= groupSize + begSbb ? raster2id[rpos+2*blockWidth] : 0 ) : 0 ); + for( nbOut.num = 0; true; ) { int nk = -1; @@ -271,17 +318,25 @@ namespace DQIntern const int begSbb = scanId - ( scanId & (groupSize-1) ); // first pos in current subblock for( int k = 0; k < nbOut.num; k++ ) { + CHECK(begSbb > nbOut.outPos[k], "Position must be past sub block begin"); nbOut.outPos[k] -= begSbb; } nbOut.maxDist -= scanId; } +#if JVET_M0102_INTRA_SUBPARTITIONS + m_tuParameters[hd][vd][ch] = new TUParameters( *this, blockWidth, blockHeight, ChannelType(ch) ); +#else for( int chId = 0; chId < MAX_NUM_CHANNEL_TYPE; chId++ ) { m_tuParameters[hd][vd][chId] = new TUParameters( *this, blockWidth, blockHeight, ChannelType(chId) ); } +#endif } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif m_scansInitialized = true; } @@ -291,6 +346,32 @@ namespace DQIntern { return; } +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) + { + for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) + { + for( int ch = 0; ch < 2; ch++ ) + { + NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd][ch]; + NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd][ch]; + TUParameters*& tuPars = m_tuParameters [hd][vd][ch]; + if( sId2NbSbb ) + { + delete [] sId2NbSbb; + } + if( sId2NbOut ) + { + delete [] sId2NbOut; + } + if( tuPars ) + { + delete tuPars; + } + } + } + } +#else for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) { for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) @@ -315,6 +396,7 @@ namespace DQIntern } } } +#endif m_scansInitialized = false; } @@ -327,15 +409,31 @@ namespace DQIntern m_chType = chType; m_width = width; m_height = height; +#if JVET_M0257 + const uint32_t nonzeroWidth = std::min<uint32_t>(JVET_C0024_ZERO_OUT_TH, m_width); + const uint32_t nonzeroHeight = std::min<uint32_t>(JVET_C0024_ZERO_OUT_TH, m_height); + m_numCoeff = nonzeroWidth * nonzeroHeight; +#else m_numCoeff = m_width * m_height; +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + m_log2SbbWidth = g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][0]; + m_log2SbbHeight = g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][1]; +#else const bool no4x4 = ( ( m_width & 3 ) != 0 || ( m_height & 3 ) != 0 ); m_log2SbbWidth = ( no4x4 ? 1 : 2 ); m_log2SbbHeight = ( no4x4 ? 1 : 2 ); +#endif m_log2SbbSize = m_log2SbbWidth + m_log2SbbHeight; m_sbbSize = ( 1 << m_log2SbbSize ); m_sbbMask = m_sbbSize - 1; +#if JVET_M0257 + m_widthInSbb = nonzeroWidth >> m_log2SbbWidth; + m_heightInSbb = nonzeroHeight >> m_log2SbbHeight; +#else m_widthInSbb = m_width >> m_log2SbbWidth; m_heightInSbb = m_height >> m_log2SbbHeight; +#endif m_numSbb = m_widthInSbb * m_heightInSbb; #if HEVC_USE_MDCS #error "MDCS is not supported" // use different function... @@ -347,14 +445,21 @@ namespace DQIntern SizeType vsbb = gp_sizeIdxInfo->idxFrom( m_heightInSbb ); SizeType hsId = gp_sizeIdxInfo->idxFrom( m_width ); SizeType vsId = gp_sizeIdxInfo->idxFrom( m_height ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_scanSbbId2SbbPos = g_scanOrder [ chType ][ SCAN_UNGROUPED ][ m_scanType ][ hsbb ][ vsbb ]; + m_scanId2BlkPos = g_scanOrder [ chType ][ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ]; + int log2W = g_aucLog2[ m_width ]; + int log2H = g_aucLog2[ m_height ]; + m_scanId2NbInfoSbb = rom.getNbInfoSbb( log2W, log2H, chType ); + m_scanId2NbInfoOut = rom.getNbInfoOut( log2W, log2H, chType ); +#else m_scanSbbId2SbbPos = g_scanOrder [ SCAN_UNGROUPED ][ m_scanType ][ hsbb ][ vsbb ]; m_scanId2BlkPos = g_scanOrder [ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ]; - m_scanId2PosX = g_scanOrderPosXY[ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ][ 0 ]; - m_scanId2PosY = g_scanOrderPosXY[ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ][ 1 ]; int log2W = g_aucLog2[ m_width ]; int log2H = g_aucLog2[ m_height ]; m_scanId2NbInfoSbb = rom.getNbInfoSbb( log2W, log2H ); m_scanId2NbInfoOut = rom.getNbInfoOut( log2W, log2H ); +#endif m_scanInfo = new ScanInfo[ m_numCoeff ]; for( int scanIdx = 0; scanIdx < m_numCoeff; scanIdx++ ) { @@ -368,8 +473,8 @@ namespace DQIntern scanInfo.sbbSize = m_sbbSize; scanInfo.numSbb = m_numSbb; scanInfo.scanIdx = scanIdx; - scanInfo.rasterPos = m_scanId2BlkPos[ scanIdx ]; - scanInfo.sbbPos = m_scanSbbId2SbbPos[ scanIdx >> m_log2SbbSize ]; + scanInfo.rasterPos = m_scanId2BlkPos[scanIdx].idx; + scanInfo.sbbPos = m_scanSbbId2SbbPos[scanIdx >> m_log2SbbSize].idx; scanInfo.insidePos = scanIdx & m_sbbMask; scanInfo.eosbb = ( scanInfo.insidePos == 0 ); scanInfo.spt = SCAN_ISCSBB; @@ -377,10 +482,14 @@ namespace DQIntern scanInfo.spt = SCAN_SOCSBB; else if( scanInfo.eosbb && scanIdx > 0 && scanIdx < m_numCoeff - m_sbbSize ) scanInfo.spt = SCAN_EOCSBB; +#if JVET_M0297_32PT_MTS_ZERO_OUT + scanInfo.posX = m_scanId2BlkPos[scanIdx].x; + scanInfo.posY = m_scanId2BlkPos[scanIdx].y; +#endif if( scanIdx ) { const int nextScanIdx = scanIdx - 1; - const int diag = m_scanId2PosX[ nextScanIdx ] + m_scanId2PosY[ nextScanIdx ]; + const int diag = m_scanId2BlkPos[nextScanIdx].x + m_scanId2BlkPos[nextScanIdx].y; if( m_chType == CHANNEL_TYPE_LUMA ) { scanInfo.sigCtxOffsetNext = ( diag < 2 ? 12 : diag < 5 ? 6 : 0 ); @@ -395,7 +504,7 @@ namespace DQIntern scanInfo.nextNbInfoSbb = m_scanId2NbInfoSbb[ nextScanIdx ]; if( scanInfo.eosbb ) { - const int nextSbbPos = m_scanSbbId2SbbPos[ nextScanIdx >> m_log2SbbSize ]; + const int nextSbbPos = m_scanSbbId2SbbPos[nextScanIdx >> m_log2SbbSize].idx; const int nextSbbPosY = nextSbbPos / m_widthInSbb; const int nextSbbPosX = nextSbbPos - nextSbbPosY * m_widthInSbb; scanInfo.nextSbbRight = ( nextSbbPosX < m_widthInSbb - 1 ? nextSbbPos + 1 : 0 ); @@ -421,7 +530,7 @@ namespace DQIntern inline const CoeffFracBits *gtxFracBits(unsigned stateId) const { return m_gtxFracBits; } inline int32_t lastOffset(unsigned scanIdx) const { - return m_lastBitsX[m_scanId2PosX[scanIdx]] + m_lastBitsY[m_scanId2PosY[scanIdx]]; + return m_lastBitsX[m_scanId2Pos[scanIdx].x] + m_lastBitsY[m_scanId2Pos[scanIdx].y]; } private: @@ -438,8 +547,7 @@ namespace DQIntern static const unsigned sm_maxNumGtxCtx = 21; private: - const unsigned* m_scanId2PosX; - const unsigned* m_scanId2PosY; + const ScanElement * m_scanId2Pos; int32_t m_lastBitsX [ MAX_TU_SIZE ]; int32_t m_lastBitsY [ MAX_TU_SIZE ]; BinFracBits m_sigSbbFracBits [ sm_maxNumSigSbbCtx ]; @@ -449,8 +557,7 @@ namespace DQIntern void RateEstimator::initCtx( const TUParameters& tuPars, const TransformUnit& tu, const ComponentID compID, const FracBitsAccess& fracBitsAccess ) { - m_scanId2PosX = tuPars.m_scanId2PosX; - m_scanId2PosY = tuPars.m_scanId2PosY; + m_scanId2Pos = tuPars.m_scanId2BlkPos; xSetSigSbbFracBits ( fracBitsAccess, tuPars.m_chType ); xSetSigFlagBits ( fracBitsAccess, tuPars.m_chType ); xSetGtxFlagBits ( fracBitsAccess, tuPars.m_chType ); @@ -468,8 +575,44 @@ namespace DQIntern } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + BinFracBits bits; + bool prevLumaCbf = false; + bool lastCbfIsInferred = false; + bool useIntraSubPartitions = tu.cu->ispMode && isLuma(chType); + if( useIntraSubPartitions ) + { + bool rootCbfSoFar = false; + bool isLastSubPartition = CU::isISPLast(*tu.cu, tu.Y(), compID); + uint32_t nTus = tu.cu->ispMode == HOR_INTRA_SUBPARTITIONS ? tu.cu->lheight() >> g_aucLog2[tu.lheight()] : tu.cu->lwidth() >> g_aucLog2[tu.lwidth()]; + if( isLastSubPartition ) + { + TransformUnit* tuPointer = tu.cu->firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth(*tuPointer, COMPONENT_Y, tu.depth); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + prevLumaCbf = TU::getPrevTuCbfAtDepth(tu, compID, tu.depth); + } + bits = fracBitsAccess.getFracBitsArray(Ctx::QtCbf[compID](DeriveCtx::CtxQtCbf(compID, tu.depth, prevLumaCbf, true))); + } + else + { + bits = fracBitsAccess.getFracBitsArray(Ctx::QtCbf[compID](DeriveCtx::CtxQtCbf(compID, tu.depth, tu.cbf[COMPONENT_Cb]))); + } + cbfDeltaBits = lastCbfIsInferred ? 0 : int32_t(bits.intBits[1]) - int32_t(bits.intBits[0]); +#else BinFracBits bits = fracBitsAccess.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( compID, tu.depth, tu.cbf[COMPONENT_Cb] ) ) ); cbfDeltaBits = int32_t( bits.intBits[1] ) - int32_t( bits.intBits[0] ); +#endif } static const unsigned prefixCtx[] = { 0, 0, 0, 3, 6, 10, 15, 21 }; @@ -489,7 +632,11 @@ namespace DQIntern const unsigned lastShift = ( compID == COMPONENT_Y ? (log2Size+1)>>2 : Clip3<unsigned>(0,2,size>>3) ); const unsigned lastOffset = ( compID == COMPONENT_Y ? ( prefixCtx[log2Size] ) : 0 ); uint32_t sumFBits = 0; +#if JVET_M0257 + unsigned maxCtxId = g_uiGroupIdx[std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, size) - 1]; +#else unsigned maxCtxId = g_uiGroupIdx[ size - 1 ]; +#endif for( unsigned ctxId = 0; ctxId < maxCtxId; ctxId++ ) { const BinFracBits bits = fracBitsAccess.getFracBitsArray( ctxSetLast( lastOffset + ( ctxId >> lastShift ) ) ); @@ -497,7 +644,11 @@ namespace DQIntern sumFBits += bits.intBits[1]; } ctxBits [ maxCtxId ] = sumFBits + ( maxCtxId>3 ? ((maxCtxId-2)>>1)<<SCALE_BITS : 0 ) + bitOffset; +#if JVET_M0257 + for (unsigned pos = 0; pos < std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, size); pos++) +#else for( unsigned pos = 0; pos < size; pos++ ) +#endif { lastBits[ pos ] = ctxBits[ g_uiGroupIdx[ pos ] ]; } @@ -653,8 +804,13 @@ namespace DQIntern m_QShift = QUANT_SHIFT - 1 + qpPer + transformShift; m_QAdd = -( ( 3 << m_QShift ) >> 1 ); #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + Intermediate_Int invShift = IQUANT_SHIFT + 1 - qpPer - transformShift + ( TU::needsBlockSizeTrafoScale( tu, compID ) ? ADJ_DEQUANT_SHIFT : 0 ); + m_QScale = ( TU::needsSqrt2Scale( tu, compID ) ? ( g_quantScales[ qpRem ] * 181 ) >> 7 : g_quantScales[ qpRem ] ); +#else Intermediate_Int invShift = IQUANT_SHIFT + 1 - qpPer - transformShift + ( TU::needsBlockSizeTrafoScale( area ) ? ADJ_DEQUANT_SHIFT : 0 ); m_QScale = ( TU::needsSqrt2Scale( area ) ? ( g_quantScales[ qpRem ] * 181 ) >> 7 : g_quantScales[ qpRem ] ); +#endif #else Intermediate_Int invShift = IQUANT_SHIFT + 1 - qpPer - transformShift; m_QScale = g_quantScales [ qpRem ]; @@ -699,7 +855,11 @@ namespace DQIntern #else const CoeffScanType scanType = SCAN_DIAG; #endif - const unsigned* scan = g_scanOrder[ SCAN_GROUPED_4x4 ][ scanType ][ hsId ][ vsId ]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const ScanElement *scan = g_scanOrder[toChannelType(compID)][SCAN_GROUPED_4x4][scanType][hsId][vsId]; +#else + const ScanElement * scan = g_scanOrder[SCAN_GROUPED_4x4][scanType][hsId][vsId]; +#endif const TCoeff* qCoeff = tu.getCoeffs( compID ).buf; TCoeff* tCoeff = recCoeff.buf; @@ -708,7 +868,7 @@ namespace DQIntern int lastScanIdx = -1; for( int scanIdx = numCoeff - 1; scanIdx >= 0; scanIdx-- ) { - if( qCoeff[ scan[ scanIdx ] ] ) + if (qCoeff[scan[scanIdx].idx]) { lastScanIdx = scanIdx; break; @@ -737,8 +897,13 @@ namespace DQIntern #endif const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ); #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift + ( TU::needsBlockSizeTrafoScale( tu, compID ) ? ADJ_DEQUANT_SHIFT : 0 ); + Intermediate_Int invQScale = g_invQuantScales[ qpRem ] * ( TU::needsSqrt2Scale( tu, compID ) ? 181 : 1 ); +#else Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift + ( TU::needsBlockSizeTrafoScale( area ) ? ADJ_DEQUANT_SHIFT : 0 ); Intermediate_Int invQScale = g_invQuantScales[ qpRem ] * ( TU::needsSqrt2Scale( area ) ? 181 : 1 ); +#endif #else Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift; Intermediate_Int invQScale = g_invQuantScales[ qpRem ]; @@ -753,7 +918,7 @@ namespace DQIntern //----- dequant coefficients ----- for( int state = 0, scanIdx = lastScanIdx; scanIdx >= 0; scanIdx-- ) { - const unsigned rasterPos = scan [ scanIdx ]; + const unsigned rasterPos = scan[scanIdx].idx; const TCoeff& level = qCoeff[ rasterPos ]; if( level ) { @@ -840,6 +1005,15 @@ namespace DQIntern }; #define RICEMAX 32 +#if JVET_M0470 + const int32_t g_goRiceBits[4][RICEMAX] = + { + { 32768, 65536, 98304, 131072, 163840, 196608, 262144, 262144, 327680, 327680, 327680, 327680, 393216, 393216, 393216, 393216, 393216, 393216, 393216, 393216, 458752, 458752, 458752, 458752, 458752, 458752, 458752, 458752, 458752, 458752, 458752, 458752}, + { 65536, 65536, 98304, 98304, 131072, 131072, 163840, 163840, 196608, 196608, 229376, 229376, 294912, 294912, 294912, 294912, 360448, 360448, 360448, 360448, 360448, 360448, 360448, 360448, 425984, 425984, 425984, 425984, 425984, 425984, 425984, 425984}, + { 98304, 98304, 98304, 98304, 131072, 131072, 131072, 131072, 163840, 163840, 163840, 163840, 196608, 196608, 196608, 196608, 229376, 229376, 229376, 229376, 262144, 262144, 262144, 262144, 327680, 327680, 327680, 327680, 327680, 327680, 327680, 327680}, + { 131072, 131072, 131072, 131072, 131072, 131072, 131072, 131072, 163840, 163840, 163840, 163840, 163840, 163840, 163840, 163840, 196608, 196608, 196608, 196608, 196608, 196608, 196608, 196608, 229376, 229376, 229376, 229376, 229376, 229376, 229376, 229376} + }; +#else const int32_t g_goRiceBits[4][RICEMAX] = { { 32768, 65536, 98304, 131072, 163840, 196608, 229376, 294912, 294912, 360448, 360448, 360448, 360448, 425984, 425984, 425984, 425984, 425984, 425984, 425984, 425984, 491520, 491520, 491520, 491520, 491520, 491520, 491520, 491520, 491520, 491520, 491520 }, @@ -847,6 +1021,7 @@ namespace DQIntern { 98304, 98304, 98304, 98304, 131072, 131072, 131072, 131072, 163840, 163840, 163840, 163840, 196608, 196608, 196608, 196608, 229376, 229376, 229376, 229376, 262144, 262144, 262144, 262144, 294912, 294912, 294912, 294912, 360448, 360448, 360448, 360448 }, { 131072, 131072, 131072, 131072, 131072, 131072, 131072, 131072, 163840, 163840, 163840, 163840, 163840, 163840, 163840, 163840, 196608, 196608, 196608, 196608, 196608, 196608, 196608, 196608, 229376, 229376, 229376, 229376, 229376, 229376, 229376, 229376 } }; +#endif class State { @@ -981,6 +1156,16 @@ namespace DQIntern } } +#if JVET_M0297_32PT_MTS_ZERO_OUT + inline void checkRdCostSkipSbbZeroOut(Decision &decision) const + { + int64_t rdCost = m_rdCost + m_sbbFracBits.intBits[0]; + decision.rdCost = rdCost; + decision.absLevel = 0; + decision.prevId = 4 + m_stateId; + } +#endif + private: int64_t m_rdCost; uint16_t m_absLevelsAndCtxInit[24]; // 16x8bit for abs levels + 16x16bit for ctx init id @@ -1168,10 +1353,17 @@ namespace DQIntern if( decision.prevId > -2 ) { const State* prvState = 0; - if( decision.prevId >= 0 ) + if( decision.prevId >= 4 ) + { + CHECK( decision.absLevel != 0, "cannot happen" ); + prvState = skipStates + ( decision.prevId - 4 ); + m_numSigSbb = 0; + ::memset( m_absLevelsAndCtxInit, 0, 16*sizeof(uint8_t) ); + } + else if( decision.prevId >= 0 ) { - prvState = ( decision.prevId < 4 ? prevStates : skipStates - 4 ) + decision.prevId; - m_numSigSbb = prvState->m_numSigSbb + !!decision.absLevel; + prvState = prevStates + decision.prevId; + m_numSigSbb = prvState->m_numSigSbb + !!decision.absLevel; ::memcpy( m_absLevelsAndCtxInit, prvState->m_absLevelsAndCtxInit, 16*sizeof(uint8_t) ); } else @@ -1291,8 +1483,13 @@ namespace DQIntern void dequant ( const TransformUnit& tu, CoeffBuf& recCoeff, const ComponentID compID, const QpParam& cQP ) const; private: +#if JVET_M0297_32PT_MTS_ZERO_OUT + void xDecideAndUpdate ( const TCoeff absCoeff, const ScanInfo& scanInfo, bool zeroOut ); + void xDecide ( const ScanPosType spt, const TCoeff absCoeff, const int lastOffset, Decision* decisions, bool zeroOut ); +#else void xDecideAndUpdate ( const TCoeff absCoeff, const ScanInfo& scanInfo ); void xDecide ( const ScanPosType spt, const TCoeff absCoeff, const int lastOffset, Decision* decisions ); +#endif private: CommonCtx m_commonCtx; @@ -1330,10 +1527,28 @@ namespace DQIntern #undef DINIT +#if JVET_M0297_32PT_MTS_ZERO_OUT + void DepQuant::xDecide( const ScanPosType spt, const TCoeff absCoeff, const int lastOffset, Decision* decisions, bool zeroOut) +#else void DepQuant::xDecide( const ScanPosType spt, const TCoeff absCoeff, const int lastOffset, Decision* decisions) +#endif { ::memcpy( decisions, startDec, 8*sizeof(Decision) ); +#if JVET_M0297_32PT_MTS_ZERO_OUT + if( zeroOut ) + { + if( spt==SCAN_EOCSBB ) + { + m_skipStates[0].checkRdCostSkipSbbZeroOut( decisions[0] ); + m_skipStates[1].checkRdCostSkipSbbZeroOut( decisions[1] ); + m_skipStates[2].checkRdCostSkipSbbZeroOut( decisions[2] ); + m_skipStates[3].checkRdCostSkipSbbZeroOut( decisions[3] ); + } + return; + } +#endif + PQData pqData[4]; m_quant.preQuantCoeff( absCoeff, pqData ); m_prevStates[0].checkRdCosts( spt, pqData[0], pqData[2], decisions[0], decisions[2]); @@ -1351,13 +1566,21 @@ namespace DQIntern m_startState.checkRdCostStart( lastOffset, pqData[2], decisions[2] ); } +#if JVET_M0297_32PT_MTS_ZERO_OUT + void DepQuant::xDecideAndUpdate( const TCoeff absCoeff, const ScanInfo& scanInfo, bool zeroOut ) +#else void DepQuant::xDecideAndUpdate( const TCoeff absCoeff, const ScanInfo& scanInfo ) +#endif { Decision* decisions = m_trellis[ scanInfo.scanIdx ]; std::swap( m_prevStates, m_currStates ); +#if JVET_M0297_32PT_MTS_ZERO_OUT + xDecide( scanInfo.spt, absCoeff, lastOffset(scanInfo.scanIdx), decisions, zeroOut ); +#else xDecide( scanInfo.spt, absCoeff, lastOffset(scanInfo.scanIdx), decisions); +#endif if( scanInfo.scanIdx ) { @@ -1370,7 +1593,11 @@ namespace DQIntern m_currStates[3].updateStateEOS( scanInfo, m_prevStates, m_skipStates, decisions[3] ); ::memcpy( decisions+4, decisions, 4*sizeof(Decision) ); } +#if JVET_M0297_32PT_MTS_ZERO_OUT + else if( !zeroOut ) +#else else +#endif { switch( scanInfo.nextNbInfoSbb.num ) { @@ -1438,7 +1665,7 @@ namespace DQIntern const TCoeff thres = m_quant.getLastThreshold(); for( ; firstTestPos >= 0; firstTestPos-- ) { - if( abs( tCoeff[ tuPars.m_scanId2BlkPos[firstTestPos] ] ) > thres ) + if (abs(tCoeff[tuPars.m_scanId2BlkPos[firstTestPos].idx]) > thres) { break; } @@ -1457,12 +1684,38 @@ namespace DQIntern } m_startState.init(); +#if JVET_M0297_32PT_MTS_ZERO_OUT + int effWidth = tuPars.m_width, effHeight = tuPars.m_height; + bool zeroOut = false; +#if JVET_M0140_SBT +#if JVET_M0464_UNI_MTS + if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tuPars.m_height <= 32 && tuPars.m_width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tuPars.m_height <= 32 && tuPars.m_width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#else +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( tu.cu->emtFlag && !tu.transformSkip[compID] && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#endif + { + effHeight = ( tuPars.m_height == 32 ) ? 16 : tuPars.m_height; + effWidth = ( tuPars.m_width == 32 ) ? 16 : tuPars.m_width; + zeroOut = ( effHeight < tuPars.m_height || effWidth < tuPars.m_width ); + } +#endif //===== populate trellis ===== for( int scanIdx = firstTestPos; scanIdx >= 0; scanIdx-- ) { const ScanInfo& scanInfo = tuPars.m_scanInfo[ scanIdx ]; +#if JVET_M0297_32PT_MTS_ZERO_OUT + xDecideAndUpdate( abs( tCoeff[ scanInfo.rasterPos ] ), scanInfo, zeroOut && ( scanInfo.posX >= effWidth || scanInfo.posY >= effHeight ) ); +#else xDecideAndUpdate( abs( tCoeff[ scanInfo.rasterPos ] ), scanInfo ); +#endif } //===== find best path ===== @@ -1483,7 +1736,7 @@ namespace DQIntern for( ; decision.prevId >= 0; scanIdx++ ) { decision = m_trellis[ scanIdx ][ decision.prevId ]; - int32_t blkpos = tuPars.m_scanId2BlkPos[ scanIdx ]; + int32_t blkpos = tuPars.m_scanId2BlkPos[scanIdx].idx; qCoeff[ blkpos ] = ( tCoeff[ blkpos ] < 0 ? -decision.absLevel : decision.absLevel ); absSum += decision.absLevel; } diff --git a/source/Lib/CommonLib/Hash.cpp b/source/Lib/CommonLib/Hash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2301f6845b148de9e435cb6f72cbd4dbcb0fddfc --- /dev/null +++ b/source/Lib/CommonLib/Hash.cpp @@ -0,0 +1,732 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2019, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file TEncHash.cpp + \brief hash encoder class + */ +#include "CommonLib/dtrace_codingstruct.h" +#include "CommonLib/Picture.h" +#include "CommonLib/UnitTools.h" +#include "Hash.h" + + + + // ==================================================================================================================== + // Constructor / destructor / create / destroy + // ==================================================================================================================== + +int TComHash::m_blockSizeToIndex[65][65]; +TCRCCalculatorLight TComHash::m_crcCalculator1(24, 0x5D6DCB); +TCRCCalculatorLight TComHash::m_crcCalculator2(24, 0x864CFB); + +TCRCCalculatorLight::TCRCCalculatorLight(uint32_t bits, uint32_t truncPoly) +{ + m_remainder = 0; + m_bits = bits; + m_truncPoly = truncPoly; + m_finalResultMask = (1 << bits) - 1; + + xInitTable(); +} + +TCRCCalculatorLight::~TCRCCalculatorLight() +{ + +} + +void TCRCCalculatorLight::xInitTable() +{ + const uint32_t highBit = 1 << (m_bits - 1); + const uint32_t byteHighBit = 1 << (8 - 1); + + for (uint32_t value = 0; value < 256; value++) + { + uint32_t remainder = 0; + for (unsigned char mask = byteHighBit; mask != 0; mask >>= 1) + { + if (value & mask) + { + remainder ^= highBit; + } + + if (remainder & highBit) + { + remainder <<= 1; + remainder ^= m_truncPoly; + } + else + { + remainder <<= 1; + } + } + + m_table[value] = remainder; + } +} + +void TCRCCalculatorLight::processData(unsigned char* curData, uint32_t dataLength) +{ + for (uint32_t i = 0; i < dataLength; i++) + { + unsigned char index = (m_remainder >> (m_bits - 8)) ^ curData[i]; + m_remainder <<= 8; + m_remainder ^= m_table[index]; + } +} + + +TComHash::TComHash() +{ + m_lookupTable = NULL; + tableHasContent = false; +} + +TComHash::~TComHash() +{ + clearAll(); + if (m_lookupTable != NULL) + { + delete[] m_lookupTable; + m_lookupTable = NULL; + } +} + +void TComHash::create() +{ + if (m_lookupTable != NULL) + { + clearAll(); + return; + } + int maxAddr = 1 << (m_CRCBits + m_blockSizeBits); + m_lookupTable = new std::vector<BlockHash>*[maxAddr]; + memset(m_lookupTable, 0, sizeof(std::vector<BlockHash>*) * maxAddr); + tableHasContent = false; +} + +void TComHash::clearAll() +{ + tableHasContent = false; + if (m_lookupTable == NULL) + { + return; + } + int maxAddr = 1 << (m_CRCBits + m_blockSizeBits); + for (int i = 0; i < maxAddr; i++) + { + if (m_lookupTable[i] != NULL) + { + delete m_lookupTable[i]; + m_lookupTable[i] = NULL; + } + } +} + +void TComHash::addToTable(uint32_t hashValue, const BlockHash& blockHash) +{ + if (m_lookupTable[hashValue] == NULL) + { + m_lookupTable[hashValue] = new std::vector<BlockHash>; + m_lookupTable[hashValue]->push_back(blockHash); + } + else + { + m_lookupTable[hashValue]->push_back(blockHash); + } +} + +int TComHash::count(uint32_t hashValue) +{ + if (m_lookupTable[hashValue] == NULL) + { + return 0; + } + else + { + return static_cast<int>(m_lookupTable[hashValue]->size()); + } +} + +int TComHash::count(uint32_t hashValue) const +{ + if (m_lookupTable[hashValue] == NULL) + { + return 0; + } + else + { + return static_cast<int>(m_lookupTable[hashValue]->size()); + } +} + +MapIterator TComHash::getFirstIterator(uint32_t hashValue) +{ + return m_lookupTable[hashValue]->begin(); +} + +const MapIterator TComHash::getFirstIterator(uint32_t hashValue) const +{ + return m_lookupTable[hashValue]->begin(); +} + +bool TComHash::hasExactMatch(uint32_t hashValue1, uint32_t hashValue2) +{ + if (m_lookupTable[hashValue1] == NULL) + { + return false; + } + std::vector<BlockHash>::iterator it; + for (it = m_lookupTable[hashValue1]->begin(); it != m_lookupTable[hashValue1]->end(); it++) + { + if ((*it).hashValue2 == hashValue2) + { + return true; + } + } + return false; +} + +void TComHash::generateBlock2x2HashValue(const PelUnitBuf &curPicBuf, int picWidth, int picHeight, const BitDepths bitDepths, uint32_t* picBlockHash[2], bool* picBlockSameInfo[3]) +{ + const int width = 2; + const int height = 2; + int xEnd = picWidth - width + 1; + int yEnd = picHeight - height + 1; + + int length = width * 2; + bool includeChroma = false; + if ((curPicBuf).chromaFormat == CHROMA_444) + { + length *= 3; + includeChroma = true; + } + unsigned char* p = new unsigned char[length]; + + int pos = 0; + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + TComHash::getPixelsIn1DCharArrayByBlock2x2(curPicBuf, p, xPos, yPos, bitDepths, includeChroma); + picBlockSameInfo[0][pos] = isBlock2x2RowSameValue(p, includeChroma); + picBlockSameInfo[1][pos] = isBlock2x2ColSameValue(p, includeChroma); + + picBlockHash[0][pos] = TComHash::getCRCValue1(p, length * sizeof(unsigned char)); + picBlockHash[1][pos] = TComHash::getCRCValue2(p, length * sizeof(unsigned char)); + + pos++; + } + pos += width - 1; + } + + delete[] p; +} +void TComHash::generateRectangleHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]) +{ + //at present, only support 1:2(2:1) retangle hash value + CHECK(width != (height << 1) && (width << 1) != height, "Wrong") + bool isHorizontal = width == (height << 1) ? true : false; + + int xEnd = picWidth - width + 1; + int yEnd = picHeight - height + 1; + + int srcWidth = width >> 1; + int quadWidth = width >> 2; + int srcHeight = height >> 1; + int quadHeight = height >> 2; + + int length = 2 * sizeof(uint32_t); + uint32_t* p = new uint32_t[2]; + int pos = 0; + if (isHorizontal) + { + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + p[0] = srcPicBlockHash[0][pos]; + p[1] = srcPicBlockHash[0][pos + srcWidth]; + dstPicBlockHash[0][pos] = TComHash::getCRCValue1((unsigned char*)p, length); + + p[0] = srcPicBlockHash[1][pos]; + p[1] = srcPicBlockHash[1][pos + srcWidth]; + dstPicBlockHash[1][pos] = TComHash::getCRCValue2((unsigned char*)p, length); + + dstPicBlockSameInfo[0][pos] = srcPicBlockSameInfo[0][pos] && srcPicBlockSameInfo[0][pos + quadWidth] && srcPicBlockSameInfo[0][pos + srcWidth]; + dstPicBlockSameInfo[1][pos] = srcPicBlockSameInfo[1][pos] && srcPicBlockSameInfo[1][pos + srcWidth]; + pos++; + } + pos += width - 1; + } + } + else + { + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + p[0] = srcPicBlockHash[0][pos]; + p[1] = srcPicBlockHash[0][pos + srcHeight * picWidth]; + dstPicBlockHash[0][pos] = TComHash::getCRCValue1((unsigned char*)p, length); + + p[0] = srcPicBlockHash[1][pos]; + p[1] = srcPicBlockHash[1][pos + srcHeight * picWidth]; + dstPicBlockHash[1][pos] = TComHash::getCRCValue2((unsigned char*)p, length); + + dstPicBlockSameInfo[0][pos] = srcPicBlockSameInfo[0][pos] && srcPicBlockSameInfo[0][pos + srcHeight * picWidth]; + dstPicBlockSameInfo[1][pos] = srcPicBlockSameInfo[1][pos] && srcPicBlockSameInfo[1][pos + quadHeight * picWidth] && srcPicBlockSameInfo[1][pos + srcHeight * picWidth]; + + pos++; + } + pos += width - 1; + } + } + + int widthMinus1 = width - 1; + int heightMinus1 = height - 1; + pos = 0; + + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + dstPicBlockSameInfo[2][pos] = (!dstPicBlockSameInfo[0][pos] && !dstPicBlockSameInfo[1][pos]) || (((xPos & widthMinus1) == 0) && ((yPos & heightMinus1) == 0)); + pos++; + } + pos += width - 1; + } + + delete[] p; +} + +void TComHash::generateBlockHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]) +{ + int xEnd = picWidth - width + 1; + int yEnd = picHeight - height + 1; + + int srcWidth = width >> 1; + int quadWidth = width >> 2; + int srcHeight = height >> 1; + int quadHeight = height >> 2; + + int length = 4 * sizeof(uint32_t); + + uint32_t* p = new uint32_t[4]; + int pos = 0; + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + p[0] = srcPicBlockHash[0][pos]; + p[1] = srcPicBlockHash[0][pos + srcWidth]; + p[2] = srcPicBlockHash[0][pos + srcHeight * picWidth]; + p[3] = srcPicBlockHash[0][pos + srcHeight * picWidth + srcWidth]; + dstPicBlockHash[0][pos] = TComHash::getCRCValue1((unsigned char*)p, length); + + p[0] = srcPicBlockHash[1][pos]; + p[1] = srcPicBlockHash[1][pos + srcWidth]; + p[2] = srcPicBlockHash[1][pos + srcHeight * picWidth]; + p[3] = srcPicBlockHash[1][pos + srcHeight * picWidth + srcWidth]; + dstPicBlockHash[1][pos] = TComHash::getCRCValue2((unsigned char*)p, length); + + dstPicBlockSameInfo[0][pos] = srcPicBlockSameInfo[0][pos] && srcPicBlockSameInfo[0][pos + quadWidth] && srcPicBlockSameInfo[0][pos + srcWidth] + && srcPicBlockSameInfo[0][pos + srcHeight * picWidth] && srcPicBlockSameInfo[0][pos + srcHeight * picWidth + quadWidth] && srcPicBlockSameInfo[0][pos + srcHeight * picWidth + srcWidth]; + + dstPicBlockSameInfo[1][pos] = srcPicBlockSameInfo[1][pos] && srcPicBlockSameInfo[1][pos + srcWidth] && srcPicBlockSameInfo[1][pos + quadHeight * picWidth] + && srcPicBlockSameInfo[1][pos + quadHeight * picWidth + srcWidth] && srcPicBlockSameInfo[1][pos + srcHeight * picWidth] && srcPicBlockSameInfo[1][pos + srcHeight * picWidth + srcWidth]; + + pos++; + } + pos += width - 1; + } + + if (width >= 4) + { + int widthMinus1 = width - 1; + int heightMinus1 = height - 1; + pos = 0; + + for (int yPos = 0; yPos < yEnd; yPos++) + { + for (int xPos = 0; xPos < xEnd; xPos++) + { + dstPicBlockSameInfo[2][pos] = (!dstPicBlockSameInfo[0][pos] && !dstPicBlockSameInfo[1][pos]) || (((xPos & widthMinus1) == 0) && ((yPos & heightMinus1) == 0)); + pos++; + } + pos += width - 1; + } + } + + delete[] p; + +} + +void TComHash::addToHashMapByRowWithPrecalData(uint32_t* picHash[2], bool* picIsSame, int picWidth, int picHeight, int width, int height) +{ + int xEnd = picWidth - width + 1; + int yEnd = picHeight - height + 1; + + bool* srcIsAdded = picIsSame; + uint32_t* srcHash[2] = { picHash[0], picHash[1] }; + + int addValue = m_blockSizeToIndex[width][height]; + CHECK(addValue < 0, "Wrong") + addValue <<= m_CRCBits; + int crcMask = 1 << m_CRCBits; + crcMask -= 1; + + for (int xPos = 0; xPos < xEnd; xPos++) + { + for (int yPos = 0; yPos < yEnd; yPos++) + { + int pos = yPos * picWidth + xPos; + //valid data + if (srcIsAdded[pos]) + { + BlockHash blockHash; + blockHash.x = xPos; + blockHash.y = yPos; + + uint32_t hashValue1 = (srcHash[0][pos] & crcMask) + addValue; + blockHash.hashValue2 = srcHash[1][pos]; + + addToTable(hashValue1, blockHash); + } + } + } +} + +void TComHash::getPixelsIn1DCharArrayByBlock2x2(const PelUnitBuf &curPicBuf, unsigned char* pixelsIn1D, int xStart, int yStart, const BitDepths& bitDepths, bool includeAllComponent) +{ + ChromaFormat fmt = (curPicBuf).chromaFormat; + if (fmt != CHROMA_444) + { + includeAllComponent = false; + } + + if (bitDepths.recon[CHANNEL_TYPE_LUMA] == 8 && bitDepths.recon[CHANNEL_TYPE_CHROMA] == 8) + { + Pel* curPel[3]; + int stride[3]; + for (int id = 0; id < 3; id++) + { + ComponentID compID = ComponentID(id); + stride[id] = (curPicBuf).get(compID).stride; + curPel[id] = (curPicBuf).get(compID).buf; + curPel[id] += (yStart >> getComponentScaleY(compID, fmt)) * stride[id] + (xStart >> getComponentScaleX(compID, fmt)); + } + + int index = 0; + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[0][j]); + if (includeAllComponent) + { + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[1][j]); + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[2][j]); + } + } + curPel[0] += stride[0]; + if (includeAllComponent) + { + curPel[1] += stride[1]; + curPel[2] += stride[2]; + } + } + } + else + { + int shift = bitDepths.recon[CHANNEL_TYPE_LUMA] - 8; + int shiftc = bitDepths.recon[CHANNEL_TYPE_CHROMA] - 8; + Pel* curPel[3]; + int stride[3]; + for (int id = 0; id < 3; id++) + { + ComponentID compID = ComponentID(id); + stride[id] = (curPicBuf).get(compID).stride; + curPel[id] = (curPicBuf).get(compID).buf; + curPel[id] += (yStart >> getComponentScaleY(compID, fmt)) * stride[id] + (xStart >> getComponentScaleX(compID, fmt)); + } + + int index = 0; + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[0][j] >> shift); + if (includeAllComponent) + { + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[1][j] >> shiftc); + pixelsIn1D[index++] = static_cast<unsigned char>(curPel[2][j] >> shiftc); + } + } + curPel[0] += stride[0]; + if (includeAllComponent) + { + curPel[1] += stride[1]; + curPel[2] += stride[2]; + } + } + } +} + +bool TComHash::isBlock2x2RowSameValue(unsigned char* p, bool includeAllComponent) +{ + if (includeAllComponent) + { + if (p[0] != p[3] || p[6] != p[9]) + { + return false; + } + if (p[1] != p[4] || p[7] != p[10]) + { + return false; + } + if (p[2] != p[5] || p[8] != p[11]) + { + return false; + } + } + else + { + if (p[0] != p[1] || p[2] != p[3]) + { + return false; + } + } + + return true; +} + +bool TComHash::isBlock2x2ColSameValue(unsigned char* p, bool includeAllComponent) +{ + if (includeAllComponent) + { + if (p[0] != p[6] || p[3] != p[9]) + { + return false; + } + if (p[1] != p[7] || p[4] != p[10]) + { + return false; + } + if (p[2] != p[8] || p[5] != p[11]) + { + return false; + } + } + else + { + if ((p[0] != p[2]) || (p[1] != p[3])) + { + return false; + } + } + + return true; +} + +bool TComHash::getBlockHashValue(const PelUnitBuf &curPicBuf, int width, int height, int xStart, int yStart, const BitDepths bitDepths, uint32_t& hashValue1, uint32_t& hashValue2) +{ + int addValue = m_blockSizeToIndex[width][height]; + + CHECK(addValue < 0, "Wrong") + addValue <<= m_CRCBits; + int crcMask = 1 << m_CRCBits; + crcMask -= 1; + int length = 4; + bool includeChroma = false; + if ((curPicBuf).chromaFormat == CHROMA_444) + { + length *= 3; + includeChroma = true; + } + + unsigned char* p = new unsigned char[length]; + uint32_t* toHash = new uint32_t[4]; + + int block2x2Num = (width*height) >> 2; + + uint32_t* hashValueBuffer[2][2]; + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + hashValueBuffer[i][j] = new uint32_t[block2x2Num]; + } + } + + //2x2 subblock hash values in current CU + int subBlockInWidth = (width >> 1); + int subBlockInHeight = (height >> 1); + for (int yPos = 0; yPos < height; yPos += 2) + { + for (int xPos = 0; xPos < width; xPos += 2) + { + int pos = (yPos >> 1)*subBlockInWidth + (xPos >> 1); + TComHash::getPixelsIn1DCharArrayByBlock2x2(curPicBuf, p, xStart + xPos, yStart + yPos, bitDepths, includeChroma); + + hashValueBuffer[0][0][pos] = TComHash::getCRCValue1(p, length * sizeof(unsigned char)); + hashValueBuffer[1][0][pos] = TComHash::getCRCValue2(p, length * sizeof(unsigned char)); + } + } + + int srcSubBlockInWidth = subBlockInWidth; + subBlockInWidth >>= 1; + subBlockInHeight >>= 1; + length = 4 * sizeof(uint32_t); + + int srcIdx = 1; + int dstIdx = 0; + + //4x4 subblock hash values to current block hash values + int minSize = std::min(height, width); + for (int subWidth = 4; subWidth <= minSize; subWidth *= 2) + { + srcIdx = 1 - srcIdx; + dstIdx = 1 - dstIdx; + + int dstPos = 0; + for (int yPos = 0; yPos < subBlockInHeight; yPos++) + { + for (int xPos = 0; xPos < subBlockInWidth; xPos++) + { + int srcPos = (yPos << 1)*srcSubBlockInWidth + (xPos << 1); + + toHash[0] = hashValueBuffer[0][srcIdx][srcPos]; + toHash[1] = hashValueBuffer[0][srcIdx][srcPos + 1]; + toHash[2] = hashValueBuffer[0][srcIdx][srcPos + srcSubBlockInWidth]; + toHash[3] = hashValueBuffer[0][srcIdx][srcPos + srcSubBlockInWidth + 1]; + + hashValueBuffer[0][dstIdx][dstPos] = TComHash::getCRCValue1((unsigned char*)toHash, length); + + toHash[0] = hashValueBuffer[1][srcIdx][srcPos]; + toHash[1] = hashValueBuffer[1][srcIdx][srcPos + 1]; + toHash[2] = hashValueBuffer[1][srcIdx][srcPos + srcSubBlockInWidth]; + toHash[3] = hashValueBuffer[1][srcIdx][srcPos + srcSubBlockInWidth + 1]; + hashValueBuffer[1][dstIdx][dstPos] = TComHash::getCRCValue2((unsigned char*)toHash, length); + + dstPos++; + } + } + + srcSubBlockInWidth = subBlockInWidth; + subBlockInWidth >>= 1; + subBlockInHeight >>= 1; + } + + if (width != height)//currently support 1:2 or 2:1 block size + { + CHECK(width != (height << 1) && (width << 1) != height, "Wrong") + bool isHorizontal = width == (height << 1) ? true : false; + length = 2 * sizeof(uint32_t); + srcIdx = 1 - srcIdx; + dstIdx = 1 - dstIdx; + if (isHorizontal) + { + toHash[0] = hashValueBuffer[0][srcIdx][0]; + toHash[1] = hashValueBuffer[0][srcIdx][1]; + + hashValueBuffer[0][dstIdx][0] = TComHash::getCRCValue1((unsigned char*)toHash, length); + + toHash[0] = hashValueBuffer[1][srcIdx][0]; + toHash[1] = hashValueBuffer[1][srcIdx][1]; + hashValueBuffer[1][dstIdx][0] = TComHash::getCRCValue2((unsigned char*)toHash, length); + } + else + { + CHECK(srcSubBlockInWidth != 1, "Wrong") + toHash[0] = hashValueBuffer[0][srcIdx][0]; + toHash[1] = hashValueBuffer[0][srcIdx][srcSubBlockInWidth]; + + hashValueBuffer[0][dstIdx][0] = TComHash::getCRCValue1((unsigned char*)toHash, length); + + toHash[0] = hashValueBuffer[1][srcIdx][0]; + toHash[1] = hashValueBuffer[1][srcIdx][srcSubBlockInWidth]; + hashValueBuffer[1][dstIdx][0] = TComHash::getCRCValue2((unsigned char*)toHash, length); + } + } + + hashValue1 = (hashValueBuffer[0][dstIdx][0] & crcMask) + addValue; + hashValue2 = hashValueBuffer[1][dstIdx][0]; + + delete[] toHash; + + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + delete[] hashValueBuffer[i][j]; + } + } + + delete[] p; + + return true; +} + +void TComHash::initBlockSizeToIndex() +{ + for (int i = 0; i < 65; i++) + { + for (int j = 0; j < 65; j++) + { + m_blockSizeToIndex[i][j] = -1; + } + } + + m_blockSizeToIndex[8][8] = 0; + m_blockSizeToIndex[16][16] = 1; + m_blockSizeToIndex[32][32] = 2; + m_blockSizeToIndex[64][64] = 3; + m_blockSizeToIndex[4][4] = 4; + m_blockSizeToIndex[4][8] = 5; + m_blockSizeToIndex[8][4] = 6; +} + +uint32_t TComHash::getCRCValue1(unsigned char* p, int length) +{ + m_crcCalculator1.reset(); + m_crcCalculator1.processData(p, length); + return m_crcCalculator1.getCRC(); +} + +uint32_t TComHash::getCRCValue2(unsigned char* p, int length) +{ + m_crcCalculator2.reset(); + m_crcCalculator2.processData(p, length); + return m_crcCalculator2.getCRC(); +} +//! \} diff --git a/source/Lib/CommonLib/Hash.h b/source/Lib/CommonLib/Hash.h new file mode 100644 index 0000000000000000000000000000000000000000..d69787cfc70eb38306153b2fc0e913793098fa66 --- /dev/null +++ b/source/Lib/CommonLib/Hash.h @@ -0,0 +1,134 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2019, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file Hash.h + \brief Hash class (header) + */ + + +#ifndef __HASH__ +#define __HASH__ + + // Include files + +#include "CommonLib/Buffer.h" +#include "CommonLib/CommonDef.h" +#include "CommonLib/TrQuant.h" +#include "CommonLib/Unit.h" +#include "CommonLib/UnitPartitioner.h" +#include <vector> + + +struct BlockHash +{ + short x; + short y; + uint32_t hashValue2; +}; + +typedef std::vector<BlockHash>::iterator MapIterator; + +// ==================================================================================================================== +// Class definitions +// ==================================================================================================================== + + +struct TCRCCalculatorLight +{ +public: + TCRCCalculatorLight(uint32_t bits, uint32_t truncPoly); + ~TCRCCalculatorLight(); + +public: + void processData(unsigned char* curData, uint32_t dataLength); + void reset() { m_remainder = 0; } + uint32_t getCRC() { return m_remainder & m_finalResultMask; } + +private: + void xInitTable(); + +private: + uint32_t m_remainder; + uint32_t m_truncPoly; + uint32_t m_bits; + uint32_t m_table[256]; + uint32_t m_finalResultMask; +}; + + +struct TComHash +{ +public: + TComHash(); + ~TComHash(); + void create(); + void clearAll(); + void addToTable(uint32_t hashValue, const BlockHash& blockHash); + int count(uint32_t hashValue); + int count(uint32_t hashValue) const; + MapIterator getFirstIterator(uint32_t hashValue); + const MapIterator getFirstIterator(uint32_t hashValue) const; + bool hasExactMatch(uint32_t hashValue1, uint32_t hashValue2); + + void generateBlock2x2HashValue(const PelUnitBuf &curPicBuf, int picWidth, int picHeight, const BitDepths bitDepths, uint32_t* picBlockHash[2], bool* picBlockSameInfo[3]); + void generateBlockHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]); + void generateRectangleHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]); + void addToHashMapByRowWithPrecalData(uint32_t* srcHash[2], bool* srcIsSame, int picWidth, int picHeight, int width, int height); + bool isInitial() { return tableHasContent; } + void setInitial() { tableHasContent = true; } + + + +public: + static uint32_t getCRCValue1(unsigned char* p, int length); + static uint32_t getCRCValue2(unsigned char* p, int length); + static void getPixelsIn1DCharArrayByBlock2x2(const PelUnitBuf &curPicBuf, unsigned char* pixelsIn1D, int xStart, int yStart, const BitDepths& bitDepths, bool includeAllComponent = true); + static bool isBlock2x2RowSameValue(unsigned char* p, bool includeAllComponent = true); + static bool isBlock2x2ColSameValue(unsigned char* p, bool includeAllComponent = true); + static bool getBlockHashValue(const PelUnitBuf &curPicBuf, int width, int height, int xStart, int yStart, const BitDepths bitDepths, uint32_t& hashValue1, uint32_t& hashValue2); + static void initBlockSizeToIndex(); + +private: + std::vector<BlockHash>** m_lookupTable; + bool tableHasContent; + +private: + static const int m_CRCBits = 16; + static const int m_blockSizeBits = 3; + static int m_blockSizeToIndex[65][65]; + + static TCRCCalculatorLight m_crcCalculator1; + static TCRCCalculatorLight m_crcCalculator2; +}; + +#endif // __HASH__ diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp index 205d74394e0cf0adc52f44834c3280f42728888d..473d844c98a0b024bc37dab51e6684a192f0233e 100644 --- a/source/Lib/CommonLib/InterPrediction.cpp +++ b/source/Lib/CommonLib/InterPrediction.cpp @@ -82,7 +82,15 @@ InterPrediction::InterPrediction() m_filteredBlockTmp[i][c] = nullptr; } } - +#if JVET_M0147_DMVR + m_cYuvPredTempDMVRL1 = nullptr; + m_cYuvPredTempDMVRL0 = nullptr; + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + m_cRefSamplesDMVRL0[ch] = nullptr; + m_cRefSamplesDMVRL1[ch] = nullptr; + } +#endif } InterPrediction::~InterPrediction() @@ -128,6 +136,19 @@ void InterPrediction::destroy() xFree(m_gradY0); m_gradY0 = nullptr; xFree(m_gradX1); m_gradX1 = nullptr; xFree(m_gradY1); m_gradY1 = nullptr; +#if JVET_M0147_DMVR + xFree(m_cYuvPredTempDMVRL0); + m_cYuvPredTempDMVRL0 = nullptr; + xFree(m_cYuvPredTempDMVRL1); + m_cYuvPredTempDMVRL1 = nullptr; + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + xFree(m_cRefSamplesDMVRL0[ch]); + m_cRefSamplesDMVRL0[ch] = nullptr; + xFree(m_cRefSamplesDMVRL1[ch]); + m_cRefSamplesDMVRL1[ch] = nullptr; + } +#endif } void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC ) @@ -148,6 +169,10 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC ) { int extWidth = MAX_CU_SIZE + (2 * BIO_EXTEND_SIZE + 2) + 16; int extHeight = MAX_CU_SIZE + (2 * BIO_EXTEND_SIZE + 2) + 1; +#if JVET_M0147_DMVR + extWidth = extWidth > (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 16) ? extWidth : MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 16; + extHeight = extHeight > (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 1) ? extHeight : MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + 1; +#endif for( uint32_t i = 0; i < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS_SIGNAL; i++ ) { m_filteredBlockTmp[i][c] = ( Pel* ) xMalloc( Pel, ( extWidth + 4 ) * ( extHeight + 7 + 4 ) ); @@ -168,13 +193,22 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC ) m_triangleBuf.create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); m_iRefListIdx = -1; - + m_gradX0 = (Pel*)xMalloc(Pel, BIO_TEMP_BUFFER_SIZE); m_gradY0 = (Pel*)xMalloc(Pel, BIO_TEMP_BUFFER_SIZE); m_gradX1 = (Pel*)xMalloc(Pel, BIO_TEMP_BUFFER_SIZE); m_gradY1 = (Pel*)xMalloc(Pel, BIO_TEMP_BUFFER_SIZE); } +#if JVET_M0147_DMVR + m_cYuvPredTempDMVRL0 = (Pel*)xMalloc(Pel, (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION)) * (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION))); + m_cYuvPredTempDMVRL1 = (Pel*)xMalloc(Pel, (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION)) * (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION))); + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + m_cRefSamplesDMVRL0[ch] = (Pel*)xMalloc(Pel, (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + NTAPS_LUMA) * (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + NTAPS_LUMA)); + m_cRefSamplesDMVRL1[ch] = (Pel*)xMalloc(Pel, (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + NTAPS_LUMA) * (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + NTAPS_LUMA)); + } +#endif #if !JVET_J0090_MEMORY_BANDWITH_MEASURE m_if.initInterpolationFilter( true ); #endif @@ -326,7 +360,12 @@ void InterPrediction::xSubPuMC( PredictionUnit& pu, PelUnitBuf& predBuf, const R subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy))); subPu = curMi; PelUnitBuf subPredBuf = predBuf.subBuf(UnitAreaRelative(pu, subPu)); - +#if JVET_M0823_MMVD_ENCOPT + subPu.mmvdEncOptMode = 0; +#endif +#if JVET_M0147_DMVR + subPu.mvRefine = false; +#endif motionCompensation(subPu, subPredBuf, eRefPicList); secDim = later - secStep; } @@ -365,8 +404,8 @@ void InterPrediction::xChromaMC(PredictionUnit &pu, PelUnitBuf& pcYuvPred) } -void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const bool& bi - , const bool& bioApplied +void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const bool& bi + , const bool& bioApplied , const bool luma, const bool chroma ) { @@ -375,7 +414,11 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& int iRefIdx = pu.refIdx[eRefPicList]; Mv mv[3]; bool isIBC = false; +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) +#else if (pu.cs->slice->getRefPic(eRefPicList, iRefIdx)->getPOC() == pu.cs->slice->getPOC()) +#endif { isIBC = true; } @@ -396,7 +439,6 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& pu.cu->lumaSize(), sps); - for( uint32_t comp = COMPONENT_Y; comp < pcYuvPred.bufs.size() && comp <= m_maxCompIDToPred; comp++ ) { const ComponentID compID = ComponentID( comp ); @@ -411,11 +453,27 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& } else { +#if JVET_M0483_IBC + if (isIBC) + { + xPredInterBlk(compID, pu, pu.cu->slice->getPic(), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng(compID) + , bioApplied + , isIBC + ); + } + else + { + xPredInterBlk(compID, pu, pu.cu->slice->getRefPic(eRefPicList, iRefIdx), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng(compID) + , bioApplied + , isIBC + ); + } +#else xPredInterBlk( compID, pu, pu.cu->slice->getRefPic( eRefPicList, iRefIdx ), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng( compID ) , bioApplied , isIBC ); - +#endif } } } @@ -453,12 +511,20 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) } #endif - if (pu.cu->cs->sps->getSpsNext().getUseGBi() && bioApplied && pu.cu->GBiIdx != GBI_DEFAULT) + if (pu.cu->cs->sps->getUseGBi() && bioApplied && pu.cu->GBiIdx != GBI_DEFAULT) { bioApplied = false; } } - +#if JVET_M0823_MMVD_ENCOPT + if (pu.mmvdEncOptMode == 2 && pu.mmvdMergeFlag) { + bioApplied = false; + } +#endif +#if JVET_M0147_DMVR + bool dmvrApplied = false; + dmvrApplied = (pu.mvRefine) && PU::checkDMVRCondition(pu); +#endif for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++) { if( pu.refIdx[refList] < 0) @@ -468,7 +534,13 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0); +#if JVET_M0483_IBC + CHECK(CU::isIBC(*pu.cu) && eRefPicList != REF_PIC_LIST_0, "Invalid interdir for ibc mode"); + CHECK(CU::isIBC(*pu.cu) && pu.refIdx[refList] != MAX_NUM_REF, "Invalid reference index for ibc mode"); + CHECK((CU::isInter(*pu.cu) && pu.refIdx[refList] >= slice.getNumRefIdx(eRefPicList)), "Invalid reference index"); +#else CHECK( pu.refIdx[refList] >= slice.getNumRefIdx( eRefPicList ), "Invalid reference index" ); +#endif m_iRefListIdx = refList; PelUnitBuf pcMbBuf = ( pu.chromaFormat == CHROMA_400 ? @@ -477,6 +549,10 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0) { +#if JVET_M0147_DMVR + if (dmvrApplied) + continue; // mc will happen in processDMVR +#endif xPredInterUni ( pu, eRefPicList, pcMbBuf, true , bioApplied , true, true @@ -486,20 +562,26 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) { if( ( (pps.getUseWP() && slice.getSliceType() == P_SLICE) || (pps.getWPBiPred() && slice.getSliceType() == B_SLICE) ) ) { - xPredInterUni ( pu, eRefPicList, pcMbBuf, true + xPredInterUni ( pu, eRefPicList, pcMbBuf, true , bioApplied , true, true ); } else { - xPredInterUni( pu, eRefPicList, pcMbBuf, pu.cu->triangle + xPredInterUni( pu, eRefPicList, pcMbBuf, pu.cu->triangle , bioApplied , true, true ); } } } +#if JVET_M0147_DMVR + if (dmvrApplied) + { + xProcessDMVR(pu, pcYuvPred, slice.clpRngs(), bioApplied); + } +#endif CPelUnitBuf srcPred0 = ( pu.chromaFormat == CHROMA_400 ? @@ -518,14 +600,33 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) } else { +#if JVET_M0147_DMVR + if (dmvrApplied == false) + { +#endif xWeightedAverage( pu, srcPred0, srcPred1, pcYuvPred, slice.getSPS()->getBitDepths(), slice.clpRngs(), bioApplied ); +#if JVET_M0147_DMVR + } +#endif } } +#if JVET_M0147_DMVR +void InterPrediction::xPredInterBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv& _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng + , const bool& bioApplied + , bool isIBC + , SizeType dmvrWidth + , SizeType dmvrHeight + , bool bilinearMC + , Pel *srcPadBuf + , int32_t srcPadStride + ) +#else void InterPrediction::xPredInterBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv& _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng , const bool& bioApplied , bool isIBC ) +#endif { JVET_J0090_SET_REF_PICTURE( refPic, compID ); const ChromaFormat chFmt = pu.chromaFormat; @@ -549,9 +650,28 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio CPelBuf refBuf; { Position offset = pu.blocks[compID].pos().offset( _mv.getHor() >> shiftHor, _mv.getVer() >> shiftVer ); +#if JVET_M0147_DMVR + if (dmvrWidth) + { + refBuf = refPic->getRecoBuf(CompArea(compID, chFmt, offset, Size(dmvrWidth, dmvrHeight))); + } + else +#endif refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, offset, pu.blocks[compID].size() ) ); } +#if JVET_M0147_DMVR + if (NULL != srcPadBuf) + { + refBuf.buf = srcPadBuf; + refBuf.stride = srcPadStride; + } + if (dmvrWidth) + { + width = dmvrWidth; + height = dmvrHeight; + } +#endif // backup data int backupWidth = width; int backupHeight = height; @@ -570,21 +690,49 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio if( yFrac == 0 ) { +#if JVET_M0147_DMVR + m_if.filterHor(compID, (Pel*)refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, xFrac, rndRes, chFmt, clpRng, bilinearMC, bilinearMC); +#else m_if.filterHor(compID, (Pel*)refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, xFrac, rndRes, chFmt, clpRng); +#endif } else if( xFrac == 0 ) { +#if JVET_M0147_DMVR + m_if.filterVer(compID, (Pel*)refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, true, rndRes, chFmt, clpRng, bilinearMC, bilinearMC); +#else m_if.filterVer(compID, (Pel*)refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, true, rndRes, chFmt, clpRng); +#endif } else { +#if JVET_M0147_DMVR + PelBuf tmpBuf = dmvrWidth ? PelBuf(m_filteredBlockTmp[0][compID], Size(dmvrWidth, dmvrHeight)) : PelBuf(m_filteredBlockTmp[0][compID], pu.blocks[compID]); + if (dmvrWidth == 0) + tmpBuf.stride = dstBuf.stride; +#else PelBuf tmpBuf = PelBuf(m_filteredBlockTmp[0][compID], pu.blocks[compID]); tmpBuf.stride = dstBuf.stride; +#endif int vFilterSize = isLuma(compID) ? NTAPS_LUMA : NTAPS_CHROMA; +#if JVET_M0147_DMVR + if (bilinearMC) + { + vFilterSize = NTAPS_BILINEAR; + } +#endif +#if JVET_M0147_DMVR + m_if.filterHor(compID, (Pel*)refBuf.buf - ((vFilterSize >> 1) - 1) * refBuf.stride, refBuf.stride, tmpBuf.buf, tmpBuf.stride, backupWidth, backupHeight + vFilterSize - 1, xFrac, false, chFmt, clpRng, bilinearMC, bilinearMC); +#else m_if.filterHor(compID, (Pel*)refBuf.buf - ((vFilterSize >> 1) - 1) * refBuf.stride, refBuf.stride, tmpBuf.buf, tmpBuf.stride, backupWidth, backupHeight + vFilterSize - 1, xFrac, false, chFmt, clpRng); +#endif JVET_J0090_SET_CACHE_ENABLE( false ); +#if JVET_M0147_DMVR + m_if.filterVer(compID, (Pel*)tmpBuf.buf + ((vFilterSize >> 1) - 1) * tmpBuf.stride, tmpBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, false, rndRes, chFmt, clpRng, bilinearMC, bilinearMC); +#else m_if.filterVer(compID, (Pel*)tmpBuf.buf + ((vFilterSize >> 1) - 1) * tmpBuf.stride, tmpBuf.stride, dstBuf.buf, dstBuf.stride, backupWidth, backupHeight, yFrac, false, rndRes, chFmt, clpRng); +#endif } JVET_J0090_SET_CACHE_ENABLE( true ); if (bioApplied && compID == COMPONENT_Y) @@ -622,11 +770,18 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio } #else refBuf.buf = refBuf.buf - refBuf.stride - 1; +#if JVET_M0147_DMVR + if (srcPadBuf) + { + refBuf.buf = srcPadBuf - srcPadStride - 1; + refBuf.stride = srcPadStride; + } +#endif dstBuf.buf = m_filteredBlockTmp[2 + m_iRefListIdx][compID] + dstBuf.stride + 1; bioSampleExtendBilinearFilter(refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, width - 2, height - 2, 1, xFrac, yFrac, rndRes, chFmt, clpRng); #endif - // restore data + // restore data width = backupWidth; height = backupHeight; dstBuf.buf = backupDstBufPtr; @@ -724,6 +879,12 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (iHalfBW + w) + iDMvVerX * (iHalfBH + h); iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (iHalfBW + w) + iDMvVerY * (iHalfBH + h); roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift); +#if JVET_M0145_AFFINE_MV_CLIP + Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer); + tmpMv.clipToStorageBitDepth(); + iMvScaleTmpHor = tmpMv.getHor(); + iMvScaleTmpVer = tmpMv.getVer(); +#endif // clip and scale if (sps.getWrapAroundEnabledFlag()) @@ -736,24 +897,55 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio } else { +#if JVET_M0265_MV_ROUNDING_CLEANUP + m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer); +#endif iMvScaleTmpHor = std::min<int>(iHorMax, std::max<int>(iHorMin, iMvScaleTmpHor)); iMvScaleTmpVer = std::min<int>(iVerMax, std::max<int>(iVerMin, iMvScaleTmpVer)); - +#if !JVET_M0265_MV_ROUNDING_CLEANUP m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer); +#endif } } else { +#if JVET_M0265_MV_ROUNDING_CLEANUP +#if JVET_M0192_AFF_CHROMA_SIMPL + Mv curMv = m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE) * MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)]; + roundAffineMv(curMv.hor, curMv.ver, 1); +#else + Mv curMv = m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE) * MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)] + + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)]; + roundAffineMv(curMv.hor, curMv.ver, 2); +#endif +#else +#if JVET_M0192_AFF_CHROMA_SIMPL + Mv curMv = m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE) * MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)]; + roundAffineMv(curMv.hor, curMv.ver, 1); +#else Mv curMv = (m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE) * MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE)] + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)] + m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)] + Mv(2, 2)); - curMv.set(curMv.getHor() >> 2, curMv.getVer() >> 2); + curMv.set(curMv.getHor() >> 2, curMv.getVer() >> 2); +#endif +#endif if (sps.getWrapAroundEnabledFlag()) { clipMv(curMv, Position(pu.Y().x + (w << iScaleX), pu.Y().y + (h << iScaleY)), Size(blockWidth << iScaleX, blockHeight << iScaleY), sps); } +#if JVET_M0265_MV_ROUNDING_CLEANUP + else + { + curMv.hor = std::min<int>(iHorMax, std::max<int>(iHorMin, curMv.hor)); + curMv.ver = std::min<int>(iVerMax, std::max<int>(iVerMin, curMv.ver)); + } +#endif iMvScaleTmpHor = curMv.hor; iMvScaleTmpVer = curMv.ver; } @@ -850,7 +1042,11 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf Pel* gradY = (refList == 0) ? m_gradY0 : m_gradY1; Pel* gradX = (refList == 0) ? m_gradX0 : m_gradX1; +#if JVET_M0063_BDOF_FIX + xBioGradFilter(dstTempPtr, stridePredMC, widthG, heightG, widthG, gradX, gradY, clipBitDepths.recon[toChannelType(COMPONENT_Y)]); +#else xBioGradFilter(dstTempPtr, stridePredMC, widthG, heightG, widthG, gradX, gradY); +#endif Pel* padStr = m_filteredBlockTmp[2 + refList][COMPONENT_Y] + 2 * stridePredMC + 2; for (int y = 0; y< height; y++) { @@ -868,7 +1064,11 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf const int bitDepth = clipBitDepths.recon[toChannelType(COMPONENT_Y)]; const int shiftNum = IF_INTERNAL_PREC + 1 - bitDepth; const int offset = (1 << (shiftNum - 1)) + 2 * IF_INTERNAL_OFFS; +#if JVET_M0063_BDOF_FIX + const int limit = (bitDepth>12)? 2 : ((int)1 << (4 + IF_INTERNAL_PREC - bitDepth - 5)); +#else const int limit = ((int)1 << (4 + IF_INTERNAL_PREC - bitDepth - 5)); +#endif int* dotProductTemp1 = m_dotProduct1; int* dotProductTemp2 = m_dotProduct2; @@ -876,7 +1076,11 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf int* dotProductTemp5 = m_dotProduct5; int* dotProductTemp6 = m_dotProduct6; +#if JVET_M0063_BDOF_FIX + xCalcBIOPar(srcY0Temp, srcY1Temp, gradX0, gradX1, gradY0, gradY1, dotProductTemp1, dotProductTemp2, dotProductTemp3, dotProductTemp5, dotProductTemp6, src0Stride, src1Stride, widthG, widthG, heightG, bitDepth); +#else xCalcBIOPar(srcY0Temp, srcY1Temp, gradX0, gradX1, gradY0, gradY1, dotProductTemp1, dotProductTemp2, dotProductTemp3, dotProductTemp5, dotProductTemp6, src0Stride, src1Stride, widthG, widthG, heightG); +#endif int xUnit = (width >> 2); int yUnit = (height >> 2); @@ -1041,6 +1245,17 @@ void InterPrediction::xAddBIOAvg4(const Pel* src0, int src0Stride, const Pel* sr g_pelBufOP.addBIOAvg4(src0, src0Stride, src1, src1Stride, dst, dstStride, gradX0, gradX1, gradY0, gradY1, gradStride, width, height, tmpx, tmpy, shift, offset, clpRng); } +#if JVET_M0063_BDOF_FIX +void InterPrediction::xBioGradFilter(Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, int bitDepth) +{ + g_pelBufOP.bioGradFilter(pSrc, srcStride, width, height, gradStride, gradX, gradY, bitDepth); +} + +void InterPrediction::xCalcBIOPar(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, int bitDepth) +{ + g_pelBufOP.calcBIOPar(srcY0Temp, srcY1Temp, gradX0, gradX1, gradY0, gradY1, dotProductTemp1, dotProductTemp2, dotProductTemp3, dotProductTemp5, dotProductTemp6, src0Stride, src1Stride, gradStride, widthG, heightG, bitDepth); +} +#else void InterPrediction::xBioGradFilter(Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY) { g_pelBufOP.bioGradFilter(pSrc, srcStride, width, height, gradStride, gradX, gradY); @@ -1050,6 +1265,7 @@ void InterPrediction::xCalcBIOPar(const Pel* srcY0Temp, const Pel* srcY1Temp, co { g_pelBufOP.calcBIOPar(srcY0Temp, srcY1Temp, gradX0, gradX1, gradY0, gradY1, dotProductTemp1, dotProductTemp2, dotProductTemp3, dotProductTemp5, dotProductTemp6, src0Stride, src1Stride, gradStride, widthG, heightG); } +#endif void InterPrediction::xCalcBlkGradient(int sx, int sy, int *arraysGx2, int *arraysGxGy, int *arraysGxdI, int *arraysGy2, int *arraysGydI, int &sGx2, int &sGy2, int &sGxGy, int &sGxdI, int &sGydI, int width, int height, int unitSize) { @@ -1108,12 +1324,12 @@ void InterPrediction::xWeightedAverage(const PredictionUnit& pu, const CPelUnitB } } -void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBuf, const RefPicList &eRefPicList +void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBuf, const RefPicList &eRefPicList , const bool luma, const bool chroma ) { // dual tree handling for IBC as the only ref - if (!luma || !chroma) + if ((!luma || !chroma) && eRefPicList == REF_PIC_LIST_0) { if (!luma && chroma) { @@ -1137,7 +1353,7 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu { if( ( ( sliceType == P_SLICE && pps.getUseWP() ) || ( sliceType == B_SLICE && pps.getWPBiPred() ) ) ) { - xPredInterUni ( pu, eRefPicList, predBuf, true + xPredInterUni ( pu, eRefPicList, predBuf, true , false , true, true ); @@ -1145,7 +1361,7 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu } else { - xPredInterUni( pu, eRefPicList, predBuf, false + xPredInterUni( pu, eRefPicList, predBuf, false , false , true, true ); @@ -1159,7 +1375,7 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu } else if( xCheckIdenticalMotion( pu ) ) { - xPredInterUni( pu, REF_PIC_LIST_0, predBuf, false + xPredInterUni( pu, REF_PIC_LIST_0, predBuf, false , false , true, true ); @@ -1172,25 +1388,31 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu return; } -void InterPrediction::motionCompensation( CodingUnit &cu, const RefPicList &eRefPicList +void InterPrediction::motionCompensation( CodingUnit &cu, const RefPicList &eRefPicList , const bool luma, const bool chroma ) { for( auto &pu : CU::traversePUs( cu ) ) { PelUnitBuf predBuf = cu.cs->getPredBuf( pu ); - motionCompensation( pu, predBuf, eRefPicList +#if JVET_M0147_DMVR + pu.mvRefine = true; +#endif + motionCompensation( pu, predBuf, eRefPicList , luma, chroma ); +#if JVET_M0147_DMVR + pu.mvRefine = false; +#endif } } -void InterPrediction::motionCompensation( PredictionUnit &pu, const RefPicList &eRefPicList /*= REF_PIC_LIST_X*/ +void InterPrediction::motionCompensation( PredictionUnit &pu, const RefPicList &eRefPicList /*= REF_PIC_LIST_X*/ , const bool luma, const bool chroma ) { PelUnitBuf predBuf = pu.cs->getPredBuf( pu ); - motionCompensation( pu, predBuf, eRefPicList + motionCompensation( pu, predBuf, eRefPicList , luma, chroma ); } @@ -1220,21 +1442,46 @@ void InterPrediction::motionCompensation4Triangle( CodingUnit &cu, MergeCtx &tri const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, pu.lwidth(), pu.lheight() ) ); PelUnitBuf tmpTriangleBuf = m_triangleBuf.getBuf( localUnitArea ); PelUnitBuf predBuf = cu.cs->getPredBuf( pu ); - + triangleMrgCtx.setMergeInfo( pu, candIdx0 ); PU::spanMotionInfo( pu ); motionCompensation( pu, tmpTriangleBuf ); - + triangleMrgCtx.setMergeInfo( pu, candIdx1 ); PU::spanMotionInfo( pu ); motionCompensation( pu, predBuf ); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + weightedTriangleBlk( pu, splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, tmpTriangleBuf, predBuf ); +#else weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, tmpTriangleBuf, predBuf ); +#endif } } +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP +void InterPrediction::weightedTriangleBlk( PredictionUnit &pu, const bool splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ) +#else void InterPrediction::weightedTriangleBlk( PredictionUnit &pu, bool weights, const bool splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ) +#endif { +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + if( channel == CHANNEL_TYPE_LUMA ) + { + xWeightedTriangleBlk( pu, pu.lumaSize().width, pu.lumaSize().height, COMPONENT_Y, splitDir, predDst, predSrc0, predSrc1 ); + } + else if( channel == CHANNEL_TYPE_CHROMA ) + { + xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1 ); + xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1 ); + } + else + { + xWeightedTriangleBlk( pu, pu.lumaSize().width, pu.lumaSize().height, COMPONENT_Y, splitDir, predDst, predSrc0, predSrc1 ); + xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cb, splitDir, predDst, predSrc0, predSrc1 ); + xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, predDst, predSrc0, predSrc1 ); + } +#else if( channel == CHANNEL_TYPE_LUMA ) { xWeightedTriangleBlk( pu, pu.lumaSize().width, pu.lumaSize().height, COMPONENT_Y, splitDir, weights, predDst, predSrc0, predSrc1 ); @@ -1250,9 +1497,14 @@ void InterPrediction::weightedTriangleBlk( PredictionUnit &pu, bool weights, con xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cb, splitDir, weights, predDst, predSrc0, predSrc1 ); xWeightedTriangleBlk( pu, pu.chromaSize().width, pu.chromaSize().height, COMPONENT_Cr, splitDir, weights, predDst, predSrc0, predSrc1 ); } +#endif } +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP +void InterPrediction::xWeightedTriangleBlk( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ) +#else void InterPrediction::xWeightedTriangleBlk( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, const bool weights, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ) +#endif { Pel* dst = predDst .get(compIdx).buf; Pel* src0 = predSrc0.get(compIdx).buf; @@ -1268,18 +1520,28 @@ void InterPrediction::xWeightedTriangleBlk( const PredictionUnit &pu, const uint const int32_t offsetDefault = (1<<(shiftDefault-1)) + IF_INTERNAL_OFFS; const int32_t shiftWeighted = std::max<int>(2, (IF_INTERNAL_PREC - clipbd)) + log2WeightBase; const int32_t offsetWeighted = (1 << (shiftWeighted - 1)) + (IF_INTERNAL_OFFS << log2WeightBase); - + const int32_t ratioWH = (width > height) ? (width / height) : 1; const int32_t ratioHW = (width > height) ? 1 : (height / width); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + const bool longWeight = (compIdx == COMPONENT_Y) || ( predDst.chromaFormat == CHROMA_444 ); + const int32_t weightedLength = longWeight ? 7 : 3; +#else const Pel* pelWeighted = (compIdx == COMPONENT_Y) ? g_trianglePelWeightedLuma[splitDir][weights] : g_trianglePelWeightedChroma[predDst.chromaFormat == CHROMA_444 ? 0 : 1][splitDir][weights]; const int32_t weightedLength = (compIdx == COMPONENT_Y) ? g_triangleWeightLengthLuma[weights] : g_triangleWeightLengthChroma[predDst.chromaFormat == CHROMA_444 ? 0 : 1][weights]; +#endif int32_t weightedStartPos = ( splitDir == 0 ) ? ( 0 - (weightedLength >> 1) * ratioWH ) : ( width - ((weightedLength + 1) >> 1) * ratioWH ); int32_t weightedEndPos = weightedStartPos + weightedLength * ratioWH - 1; int32_t weightedPosoffset =( splitDir == 0 ) ? ratioWH : -ratioWH; - + +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + Pel tmpPelWeighted; + int32_t weightIdx; +#else const Pel* tmpPelWeighted; +#endif int32_t x, y, tmpX, tmpY, tmpWeightedStart, tmpWeightedEnd; - + for( y = 0; y < height; y+= ratioHW ) { for( tmpY = ratioHW; tmpY > 0; tmpY-- ) @@ -1293,18 +1555,36 @@ void InterPrediction::xWeightedTriangleBlk( const PredictionUnit &pu, const uint tmpWeightedStart = std::max((int32_t)0, weightedStartPos); tmpWeightedEnd = std::min(weightedEndPos, (int32_t)(width - 1)); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + weightIdx = 1; +#else tmpPelWeighted = pelWeighted; +#endif if( weightedStartPos < 0 ) { +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + weightIdx += abs(weightedStartPos) / ratioWH; +#else tmpPelWeighted += abs(weightedStartPos) / ratioWH; +#endif } for( x = tmpWeightedStart; x <= tmpWeightedEnd; x+= ratioWH ) { for( tmpX = ratioWH; tmpX > 0; tmpX-- ) { +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + tmpPelWeighted = Clip3( 1, 7, longWeight ? weightIdx : (weightIdx * 2)); + tmpPelWeighted = splitDir ? ( 8 - tmpPelWeighted ) : tmpPelWeighted; + *dst++ = ClipPel( rightShift( (tmpPelWeighted*(*src0++) + ((8 - tmpPelWeighted) * (*src1++)) + offsetWeighted), shiftWeighted ), clipRng ); +#else *dst++ = ClipPel( rightShift( ((*tmpPelWeighted)*(*src0++) + ((8 - (*tmpPelWeighted)) * (*src1++)) + offsetWeighted), shiftWeighted ), clipRng ); +#endif } +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + weightIdx ++; +#else tmpPelWeighted++; +#endif } for( x = weightedEndPos + 1; x < width; x++ ) @@ -1323,6 +1603,445 @@ void InterPrediction::xWeightedTriangleBlk( const PredictionUnit &pu, const uint } } +#if JVET_M0147_DMVR +void InterPrediction::xPrefetchPad(PredictionUnit& pu, PelUnitBuf &pcPad, RefPicList refId) +{ + int offset, width, height; + int padsize; + Mv cMv; + const Picture* refPic = pu.cu->slice->getRefPic(refId, pu.refIdx[refId]); + int mvShift = (MV_FRACTIONAL_BITS_INTERNAL); + for (int compID = 0; compID < MAX_NUM_COMPONENT; compID++) + { + cMv = Mv(pu.mv[refId].getHor(), pu.mv[refId].getVer()); + pcPad.bufs[compID].stride = (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION) + NTAPS_LUMA); + int filtersize = (compID == (COMPONENT_Y)) ? NTAPS_LUMA : NTAPS_CHROMA; + width = pcPad.bufs[compID].width; + height = pcPad.bufs[compID].height; + offset = (DMVR_NUM_ITERATION) * (pcPad.bufs[compID].stride + 1); + padsize = (DMVR_NUM_ITERATION) >> getComponentScaleX((ComponentID)compID, pu.chromaFormat); + int mvshiftTemp = mvShift + getComponentScaleX((ComponentID)compID, pu.chromaFormat); + width += (filtersize - 1); + height += (filtersize - 1); + cMv += Mv(-(((filtersize >> 1) - 1) << mvshiftTemp), + -(((filtersize >> 1) - 1) << mvshiftTemp)); + clipMv(cMv, pu.lumaPos(), pu.lumaSize(),*pu.cs->sps); + /* Pre-fetch similar to HEVC*/ + { + CPelBuf refBuf; + Position Rec_offset = pu.blocks[compID].pos().offset(cMv.getHor() >> mvshiftTemp, cMv.getVer() >> mvshiftTemp); + refBuf = refPic->getRecoBuf(CompArea((ComponentID)compID, pu.chromaFormat, Rec_offset, pu.blocks[compID].size())); + PelBuf &dstBuf = pcPad.bufs[compID]; + g_pelBufOP.copyBuffer((Pel *)refBuf.buf, refBuf.stride, ((Pel *)dstBuf.buf) + offset, dstBuf.stride, width, height); + } + /*padding on all side of size DMVR_PAD_LENGTH*/ + { + g_pelBufOP.padding(pcPad.bufs[compID].buf + offset, pcPad.bufs[compID].stride, width, height, padsize); + } + } +} +inline int32_t div_for_maxq7(int64_t N, int64_t D) +{ + int32_t sign, q; + sign = 0; + if (N < 0) + { + sign = 1; + N = -N; + } + + q = 0; + D = (D << 3); + if (N >= D) + { + N -= D; + q++; + } + q = (q << 1); + + D = (D >> 1); + if (N >= D) + { + N -= D; + q++; + } + q = (q << 1); + + if (N >= (D >> 1)) + q++; + + if (sign) + return (-q); + return(q); +} + +void xSubPelErrorSrfc(uint64_t *sadBuffer, int32_t *deltaMv) +{ + int64_t numerator, denominator; + int32_t mvDeltaSubPel; + int32_t mvSubPelLvl = 4;/*1: half pel, 2: Qpel, 3:1/8, 4: 1/16*/ + /*horizontal*/ + numerator = (int64_t)((sadBuffer[1] - sadBuffer[3]) << mvSubPelLvl); + denominator = (int64_t)((sadBuffer[1] + sadBuffer[3] - (sadBuffer[0] << 1))); + + if (0 != denominator) + { + if ((sadBuffer[1] != sadBuffer[0]) && (sadBuffer[3] != sadBuffer[0])) + { + mvDeltaSubPel = div_for_maxq7(numerator, denominator); + deltaMv[0] = (mvDeltaSubPel); + } + else + { + if (sadBuffer[1] == sadBuffer[0]) + { + deltaMv[0] = -8;// half pel + } + else + { + deltaMv[0] = 8;// half pel + } + } + } + + /*vertical*/ + numerator = (int64_t)((sadBuffer[2] - sadBuffer[4]) << mvSubPelLvl); + denominator = (int64_t)((sadBuffer[2] + sadBuffer[4] - (sadBuffer[0] << 1))); + if (0 != denominator) + { + if ((sadBuffer[2] != sadBuffer[0]) && (sadBuffer[4] != sadBuffer[0])) + { + mvDeltaSubPel = div_for_maxq7(numerator, denominator); + deltaMv[1] = (mvDeltaSubPel); + } + else + { + if (sadBuffer[2] == sadBuffer[0]) + { + deltaMv[1] = -8;// half pel + } + else + { + deltaMv[1] = 8;// half pel + } + } + } + return; +} + +void InterPrediction::xBIPMVRefine(int bd, Pel *pRefL0, Pel *pRefL1, uint64_t& minCost, int16_t *deltaMV, uint64_t *pSADsArray, int width, int height) +{ + const int32_t refStrideL0 = m_biLinearBufStride; + const int32_t refStrideL1 = m_biLinearBufStride; + Pel *pRefL0Orig = pRefL0; + Pel *pRefL1Orig = pRefL1; + for (int nIdx = SAD_BOTTOM; nIdx <= SAD_TOP_LEFT; ++nIdx) + { + int32_t sadOffset = ((m_pSearchOffset[nIdx].getVer() * ((2 * DMVR_NUM_ITERATION) + 1)) + m_pSearchOffset[nIdx].getHor()); + pRefL0 = pRefL0Orig + m_pSearchOffset[nIdx].hor + (m_pSearchOffset[nIdx].ver * refStrideL0); + pRefL1 = pRefL1Orig - m_pSearchOffset[nIdx].hor - (m_pSearchOffset[nIdx].ver * refStrideL1); + if (*(pSADsArray + sadOffset) == MAX_UINT64) + { + const uint64_t cost = xDMVRCost(bd, pRefL0, refStrideL0, pRefL1, refStrideL1, width, height); + *(pSADsArray + sadOffset) = cost; + } + if (nIdx == SAD_LEFT) + { + int32_t down = -1, right = -1; + if (pSADsArray[(((2 * DMVR_NUM_ITERATION) + 1))] < pSADsArray[-(((2 * DMVR_NUM_ITERATION) + 1))]) + { + down = 1; + } + if (pSADsArray[1] < pSADsArray[-1]) + { + right = 1; + } + m_pSearchOffset[SAD_TOP_LEFT].set(right, down); + } + if (*(pSADsArray + sadOffset) < minCost) + { + minCost = *(pSADsArray + sadOffset); + deltaMV[0] = m_pSearchOffset[nIdx].getHor(); + deltaMV[1] = m_pSearchOffset[nIdx].getVer(); + } + } +} + +void InterPrediction::xFinalPaddedMCForDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvSrc0, PelUnitBuf &pcYuvSrc1, PelUnitBuf &pcPad0, PelUnitBuf &pcPad1, const bool bioApplied + , const Mv mergeMV[NUM_REF_PIC_LIST_01] +) +{ + int offset, deltaIntMvX, deltaIntMvY; + + PelUnitBuf pcYUVTemp = pcYuvSrc0; + PelUnitBuf pcPadTemp = pcPad0; + /*always high precision MVs are used*/ + int mvShift = MV_FRACTIONAL_BITS_INTERNAL; + + for (int k = 0; k < NUM_REF_PIC_LIST_01; k++) + { + RefPicList refId = (RefPicList)k; + Mv cMv = pu.mv[refId]; + m_iRefListIdx = refId; + const Picture* refPic = pu.cu->slice->getRefPic(refId, pu.refIdx[refId]); + clipMv(cMv, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps); + + Mv startMv = mergeMV[refId]; + clipMv(startMv, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps); + + for (int compID = 0; compID < MAX_NUM_COMPONENT; compID++) + { + int mvshiftTemp = mvShift + getComponentScaleX((ComponentID)compID, pu.chromaFormat); + int leftPixelExtra; + if (compID == COMPONENT_Y) + { + leftPixelExtra = (NTAPS_LUMA >> 1) - 1; + } + else + { + leftPixelExtra = (NTAPS_CHROMA >> 1) - 1; + } + + deltaIntMvX = (cMv.getHor() >> mvshiftTemp) - + (startMv.getHor() >> mvshiftTemp); + deltaIntMvY = (cMv.getVer() >> mvshiftTemp) - + (startMv.getVer() >> mvshiftTemp); + + CHECK((abs(deltaIntMvX) > DMVR_NUM_ITERATION) || (abs(deltaIntMvY) > DMVR_NUM_ITERATION), "not expected DMVR movement"); + + offset = (DMVR_NUM_ITERATION + leftPixelExtra) * (pcPadTemp.bufs[compID].stride + 1); + offset += (deltaIntMvY)* pcPadTemp.bufs[compID].stride; + offset += (deltaIntMvX); + PelBuf &srcBuf = pcPadTemp.bufs[compID]; + xPredInterBlk((ComponentID)compID, pu, refPic, cMv, pcYUVTemp, true, pu.cs->slice->getClpRngs().comp[compID], + bioApplied, false, 0, 0, 0, (srcBuf.buf + offset), pcPadTemp.bufs[compID].stride); + } + pcYUVTemp = pcYuvSrc1; + pcPadTemp = pcPad1; + } +} + +uint64_t InterPrediction::xDMVRCost(int bitDepth, Pel* pOrg, uint32_t refStride, const Pel* pRef, uint32_t orgStride, int width, int height) +{ + DistParam cDistParam; + cDistParam.applyWeight = false; + cDistParam.useMR = false; + m_pcRdCost->setDistParam(cDistParam, pOrg, pRef, orgStride, refStride, bitDepth, COMPONENT_Y, width, height, 1); + uint64_t uiCost = cDistParam.distFunc(cDistParam); + return uiCost; +} + +void xDMVRSubPixelErrorSurface(bool notZeroCost, int16_t *totalDeltaMV, int16_t *deltaMV, uint64_t *pSADsArray) +{ + + int sadStride = (((2 * DMVR_NUM_ITERATION) + 1)); + uint64_t sadbuffer[5]; + if (notZeroCost && deltaMV[0] == 0 && deltaMV[1] == 0) + { + int32_t tempDeltaMv[2] = { 0,0 }; + sadbuffer[0] = pSADsArray[0]; + sadbuffer[1] = pSADsArray[-1]; + sadbuffer[2] = pSADsArray[-sadStride]; + sadbuffer[3] = pSADsArray[1]; + sadbuffer[4] = pSADsArray[sadStride]; + xSubPelErrorSrfc(sadbuffer, tempDeltaMv); + totalDeltaMV[0] += tempDeltaMv[0]; + totalDeltaMV[1] += tempDeltaMv[1]; + } +} + +void InterPrediction::xinitMC(PredictionUnit& pu, const ClpRngs &clpRngs) +{ + const int refIdx0 = pu.refIdx[0]; + const int refIdx1 = pu.refIdx[1]; + /*use merge MV as starting MV*/ + Mv mergeMVL0(pu.mv[REF_PIC_LIST_0]); + Mv mergeMVL1(pu.mv[REF_PIC_LIST_1]); + + /*Clip the starting MVs*/ + clipMv(mergeMVL0, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps); + clipMv(mergeMVL1, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps); + + /*L0 MC for refinement*/ + { + int offset; + int leftPixelExtra = (NTAPS_LUMA >> 1) - 1; + offset = (DMVR_NUM_ITERATION + leftPixelExtra) * (m_cYuvRefBuffDMVRL0.bufs[COMPONENT_Y].stride + 1); + offset += (-(int)DMVR_NUM_ITERATION)* (int)m_cYuvRefBuffDMVRL0.bufs[COMPONENT_Y].stride; + offset += (-(int)DMVR_NUM_ITERATION); + PelBuf srcBuf = m_cYuvRefBuffDMVRL0.bufs[COMPONENT_Y]; + PelUnitBuf yuvPredTempL0 = PelUnitBuf(pu.chromaFormat, PelBuf(m_cYuvPredTempDMVRL0, + (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION)), pu.lwidth() + (2 * DMVR_NUM_ITERATION), pu.lheight() + (2 * DMVR_NUM_ITERATION))); + + xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_0, refIdx0), mergeMVL0, yuvPredTempL0, true, clpRngs.comp[COMPONENT_Y], + false, false, pu.lwidth() + (2 * DMVR_NUM_ITERATION), pu.lheight() + (2 * DMVR_NUM_ITERATION), true, ((Pel *)srcBuf.buf) + offset, srcBuf.stride + ); + } + + /*L1 MC for refinement*/ + { + int offset; + int leftPixelExtra = (NTAPS_LUMA >> 1) - 1; + offset = (DMVR_NUM_ITERATION + leftPixelExtra) * (m_cYuvRefBuffDMVRL1.bufs[COMPONENT_Y].stride + 1); + offset += (-(int)DMVR_NUM_ITERATION)* (int)m_cYuvRefBuffDMVRL1.bufs[COMPONENT_Y].stride; + offset += (-(int)DMVR_NUM_ITERATION); + PelBuf srcBuf = m_cYuvRefBuffDMVRL1.bufs[COMPONENT_Y]; + PelUnitBuf yuvPredTempL1 = PelUnitBuf(pu.chromaFormat, PelBuf(m_cYuvPredTempDMVRL1, + (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION)), pu.lwidth() + (2 * DMVR_NUM_ITERATION), pu.lheight() + (2 * DMVR_NUM_ITERATION))); + + xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_1, refIdx1), mergeMVL1, yuvPredTempL1, true, clpRngs.comp[COMPONENT_Y], + false, false, pu.lwidth() + (2 * DMVR_NUM_ITERATION), pu.lheight() + (2 * DMVR_NUM_ITERATION), true, ((Pel *)srcBuf.buf) + offset, srcBuf.stride + ); + } +} + +void InterPrediction::xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied) +{ + int iterationCount = DMVR_NUM_ITERATION; + /*Always High Precision*/ + int mvShift = MV_FRACTIONAL_BITS_INTERNAL; + + /*use merge MV as starting MV*/ + Mv mergeMv[] = { pu.mv[REF_PIC_LIST_0] , pu.mv[REF_PIC_LIST_1] }; + + m_biLinearBufStride = (MAX_CU_SIZE + (2 * DMVR_NUM_ITERATION)); + + int dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT); + int dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH); + /*L0 Padding*/ + m_cYuvRefBuffDMVRL0 = (pu.chromaFormat == CHROMA_400 ? + PelUnitBuf(pu.chromaFormat, PelBuf(m_cRefSamplesDMVRL0[0], pcYuvDst.Y())) : + PelUnitBuf(pu.chromaFormat, PelBuf(m_cRefSamplesDMVRL0[0], pcYuvDst.Y()), + PelBuf(m_cRefSamplesDMVRL0[1], pcYuvDst.Cb()), PelBuf(m_cRefSamplesDMVRL0[2], pcYuvDst.Cr()))); + + xPrefetchPad(pu, m_cYuvRefBuffDMVRL0, REF_PIC_LIST_0); + + /*L1 Padding*/ + m_cYuvRefBuffDMVRL1 = (pu.chromaFormat == CHROMA_400 ? + PelUnitBuf(pu.chromaFormat, PelBuf(m_cRefSamplesDMVRL1[0], pcYuvDst.Y())) : + PelUnitBuf(pu.chromaFormat, PelBuf(m_cRefSamplesDMVRL1[0], pcYuvDst.Y()), PelBuf(m_cRefSamplesDMVRL1[1], pcYuvDst.Cb()), + PelBuf(m_cRefSamplesDMVRL1[2], pcYuvDst.Cr()))); + + xPrefetchPad(pu, m_cYuvRefBuffDMVRL1, REF_PIC_LIST_1); + + xinitMC(pu, clpRngs); + + // point mc buffer to cetre point to avoid multiplication to reach each iteration to the begining + Pel *biLinearPredL0 = m_cYuvPredTempDMVRL0 + (iterationCount * m_biLinearBufStride) + iterationCount; + Pel *biLinearPredL1 = m_cYuvPredTempDMVRL1 + (iterationCount * m_biLinearBufStride) + iterationCount; + + Position puPos = pu.lumaPos(); + + int bd = pu.cs->slice->getClpRngs().comp[COMPONENT_Y].bd; + + { + int num = 0; + + int yStart = 0; + for (int y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy, yStart = yStart + dy) + { + for (int x = puPos.x, xStart = 0; x < (puPos.x + pu.lumaSize().width); x = x + dx, xStart = xStart + dx) + { + uint64_t minCost = MAX_UINT64; + bool notZeroCost = true; + int16_t totalDeltaMV[2] = { 0,0 }; + int16_t deltaMV[2] = { 0, 0 }; + uint64_t *pSADsArray; + for (int i = 0; i < (((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)); i++) + { + m_SADsArray[i] = MAX_UINT64; + } + pSADsArray = &m_SADsArray[(((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)) >> 1]; + + Pel *addrL0Centre = biLinearPredL0 + yStart * m_biLinearBufStride + xStart; + Pel *addrL1Centre = biLinearPredL1 + yStart * m_biLinearBufStride + xStart; + for (int i = 0; i < iterationCount; i++) + { + deltaMV[0] = 0; + deltaMV[1] = 0; + Pel *addrL0 = addrL0Centre + totalDeltaMV[0] + (totalDeltaMV[1] * m_biLinearBufStride); + Pel *addrL1 = addrL1Centre - totalDeltaMV[0] - (totalDeltaMV[1] * m_biLinearBufStride); + if (i == 0) + { + minCost = xDMVRCost(clpRngs.comp[COMPONENT_Y].bd, addrL0, m_biLinearBufStride, addrL1, m_biLinearBufStride, dx, dy); + if (minCost < ((4 * dx * (dy >> 1/*for alternate line*/)))) + { + notZeroCost = false; + break; + } + pSADsArray[0] = minCost; + } + if (!minCost) + { + notZeroCost = false; + break; + } + + xBIPMVRefine(bd, addrL0, addrL1, minCost, deltaMV, pSADsArray, dx, dy); + + if (deltaMV[0] == 0 && deltaMV[1] == 0) + { + break; + } + totalDeltaMV[0] += deltaMV[0]; + totalDeltaMV[1] += deltaMV[1]; + pSADsArray += ((deltaMV[1] * (((2 * DMVR_NUM_ITERATION) + 1))) + deltaMV[0]); + } + + totalDeltaMV[0] = (totalDeltaMV[0] << mvShift); + totalDeltaMV[1] = (totalDeltaMV[1] << mvShift); + xDMVRSubPixelErrorSurface(notZeroCost, totalDeltaMV, deltaMV, pSADsArray); + + pu.mvdL0SubPu[num] = Mv(totalDeltaMV[0], totalDeltaMV[1]); + + num++; + } + } + } + + { + PredictionUnit subPu = pu; + subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(puPos.x, puPos.y, dx, dy))); + PelUnitBuf m_cYuvRefBuffSubCuDMVRL0; + PelUnitBuf m_cYuvRefBuffSubCuDMVRL1; + PelUnitBuf srcPred0 = (pu.chromaFormat == CHROMA_400 ? + PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[0][0], pcYuvDst.Y())) : + PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[0][0], pcYuvDst.Y()), PelBuf(m_acYuvPred[0][1], pcYuvDst.Cb()), PelBuf(m_acYuvPred[0][2], pcYuvDst.Cr()))); + PelUnitBuf srcPred1 = (pu.chromaFormat == CHROMA_400 ? + PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[1][0], pcYuvDst.Y())) : + PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[1][0], pcYuvDst.Y()), PelBuf(m_acYuvPred[1][1], pcYuvDst.Cb()), PelBuf(m_acYuvPred[1][2], pcYuvDst.Cr()))); + + srcPred0 = srcPred0.subBuf(UnitAreaRelative(pu, subPu)); + srcPred1 = srcPred1.subBuf(UnitAreaRelative(pu, subPu)); + PelUnitBuf subPredBuf = pcYuvDst.subBuf(UnitAreaRelative(pu, subPu)); + + int x = 0, y = 0; + int xStart = 0, yStart = 0; + int num = 0; + + int dstStride[MAX_NUM_COMPONENT] = { pcYuvDst.bufs[COMPONENT_Y].stride, pcYuvDst.bufs[COMPONENT_Cb].stride, pcYuvDst.bufs[COMPONENT_Cr].stride }; + for (y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy, yStart = yStart + dy) + { + for (x = puPos.x, xStart = 0; x < (puPos.x + pu.lumaSize().width); x = x + dx, xStart = xStart + dx) + { + subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy))); + + subPu.mv[0] = mergeMv[REF_PIC_LIST_0] + pu.mvdL0SubPu[num]; + subPu.mv[1] = mergeMv[REF_PIC_LIST_1] - pu.mvdL0SubPu[num]; + m_cYuvRefBuffSubCuDMVRL0 = m_cYuvRefBuffDMVRL0.subBuf(UnitAreaRelative(pu, subPu)); + m_cYuvRefBuffSubCuDMVRL1 = m_cYuvRefBuffDMVRL1.subBuf(UnitAreaRelative(pu, subPu)); + xFinalPaddedMCForDMVR(subPu, srcPred0, srcPred1, m_cYuvRefBuffSubCuDMVRL0, m_cYuvRefBuffSubCuDMVRL1, bioApplied, mergeMv); + + subPredBuf.bufs[COMPONENT_Y].buf = pcYuvDst.bufs[COMPONENT_Y].buf + xStart + yStart * dstStride[COMPONENT_Y]; + subPredBuf.bufs[COMPONENT_Cb].buf = pcYuvDst.bufs[COMPONENT_Cb].buf + (xStart >> 1) + ((yStart >> 1) * dstStride[COMPONENT_Cb]); + subPredBuf.bufs[COMPONENT_Cr].buf = pcYuvDst.bufs[COMPONENT_Cr].buf + (xStart >> 1) + ((yStart >> 1) * dstStride[COMPONENT_Cr]); + xWeightedAverage(subPu, srcPred0, srcPred1, subPredBuf, subPu.cu->slice->getSPS()->getBitDepths(), subPu.cu->slice->clpRngs(), bioApplied); + num++; + } + } + } +} +#endif #if JVET_J0090_MEMORY_BANDWITH_MEASURE void InterPrediction::cacheAssign( CacheModel *cache ) { diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h index 145431e2777417e854efa484d18fe1fba7418ad4..5c0b4b9ab02652d33724e9b8ecabdcaaccd28dce 100644 --- a/source/Lib/CommonLib/InterPrediction.h +++ b/source/Lib/CommonLib/InterPrediction.h @@ -94,7 +94,34 @@ protected: int m_iRefListIdx; PelStorage m_triangleBuf; Mv* m_storedMv; - +#if JVET_M0147_DMVR + /*buffers for bilinear Filter data for DMVR refinement*/ + Pel* m_cYuvPredTempDMVRL0; + Pel* m_cYuvPredTempDMVRL1; + int m_biLinearBufStride; + /*buffers for padded data*/ + PelUnitBuf m_cYuvRefBuffDMVRL0; + PelUnitBuf m_cYuvRefBuffDMVRL1; + Pel* m_cRefSamplesDMVRL0[MAX_NUM_COMPONENT]; + Pel* m_cRefSamplesDMVRL1[MAX_NUM_COMPONENT]; + enum SAD_POINT_INDEX + { + NOT_AVAILABLE = -1, + SAD_BOTTOM = 0, + SAD_TOP, + SAD_RIGHT, + SAD_LEFT, + SAD_TOP_LEFT, + SAD_TOP_RIGHT, + SAD_BOTTOM_LEFT, + SAD_BOTTOM_RIGHT, + SAD_CENTER, + SAD_COUNT + }; + Mv m_pSearchOffset[5] = { Mv(0, 1), Mv(0, -1), Mv(1, 0), Mv(-1, 0), Mv(0, 0) }; + uint64_t m_SADsArray[((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)]; +#endif + Pel* m_gradX0; Pel* m_gradY0; Pel* m_gradX1; @@ -107,24 +134,45 @@ protected: #if !JVET_M0487_INT_EXTEND void bioSampleExtendBilinearFilter(Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int dim, int fracX, int fracY, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng); #endif - void xPredInterUni ( const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const bool& bi - , const bool& bioApplied + void xPredInterUni ( const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const bool& bi + , const bool& bioApplied , const bool luma, const bool chroma ); void xPredInterBi ( PredictionUnit& pu, PelUnitBuf &pcYuvPred ); +#if JVET_M0147_DMVR + void xPredInterBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv& _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng + , const bool& bioApplied + , bool isIBC + , SizeType dmvrWidth = 0 + , SizeType dmvrHeight = 0 + , bool bilinearMC = false + , Pel *srcPadBuf = NULL + , int32_t srcPadStride = 0 + ); +#else void xPredInterBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv& _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng , const bool& bioApplied , bool isIBC ); +#endif void xAddBIOAvg4 (const Pel* src0, int src0Stride, const Pel* src1, int src1Stride, Pel *dst, int dstStride, const Pel *gradX0, const Pel *gradX1, const Pel *gradY0, const Pel*gradY1, int gradStride, int width, int height, int tmpx, int tmpy, int shift, int offset, const ClpRng& clpRng); +#if JVET_M0063_BDOF_FIX + void xBioGradFilter (Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, int bitDepth); + void xCalcBIOPar (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, int bitDepth); +#else void xBioGradFilter (Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY); void xCalcBIOPar (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG); +#endif void xCalcBlkGradient (int sx, int sy, int *arraysGx2, int *arraysGxGy, int *arraysGxdI, int *arraysGy2, int *arraysGydI, int &sGx2, int &sGy2, int &sGxGy, int &sGxdI, int &sGydI, int width, int height, int unitSize); void xWeightedAverage ( const PredictionUnit& pu, const CPelUnitBuf& pcYuvSrc0, const CPelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs, const bool& bioApplied ); void xPredAffineBlk( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng ); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + void xWeightedTriangleBlk ( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ); +#else void xWeightedTriangleBlk ( const PredictionUnit &pu, const uint32_t width, const uint32_t height, const ComponentID compIdx, const bool splitDir, const bool weights, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ); +#endif static bool xCheckIdenticalMotion( const PredictionUnit& pu ); @@ -155,7 +203,21 @@ public: ); void motionCompensation4Triangle( CodingUnit &cu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 ); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + void weightedTriangleBlk ( PredictionUnit &pu, const bool splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ); +#else void weightedTriangleBlk ( PredictionUnit &pu, bool weights, const bool splitDir, int32_t channel, PelUnitBuf& predDst, PelUnitBuf& predSrc0, PelUnitBuf& predSrc1 ); +#endif +#if JVET_M0147_DMVR + void xPrefetchPad(PredictionUnit& pu, PelUnitBuf &pcPad, RefPicList refId); + void xFinalPaddedMCForDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvSrc0, PelUnitBuf &pcYuvSrc1, PelUnitBuf &pcPad0, PelUnitBuf &pcPad1, const bool bioApplied + , const Mv startMV[NUM_REF_PIC_LIST_01] + ); + void xBIPMVRefine(int bd, Pel *pRefL0, Pel *pRefL1, uint64_t& minCost, int16_t *deltaMV, uint64_t *pSADsArray, int width, int height); + uint64_t xDMVRCost(int bitDepth, Pel* pRef, uint32_t refStride, const Pel* pOrg, uint32_t orgStride, int width, int height); + void xinitMC(PredictionUnit& pu, const ClpRngs &clpRngs); + void xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied ); +#endif #if JVET_J0090_MEMORY_BANDWITH_MEASURE void cacheAssign( CacheModel *cache ); diff --git a/source/Lib/CommonLib/InterpolationFilter.cpp b/source/Lib/CommonLib/InterpolationFilter.cpp index 4daa5056e7e2a603f5773e009e481101d6bde309..845cb3dcee14f227fa9e5b0b751c675ebe011547 100644 --- a/source/Lib/CommonLib/InterpolationFilter.cpp +++ b/source/Lib/CommonLib/InterpolationFilter.cpp @@ -131,6 +131,27 @@ const TFilterCoeff InterpolationFilter::m_bilinearFilter[LUMA_INTERPOLATION_FILT { 4, 60, }, }; +#if JVET_M0147_DMVR +const TFilterCoeff InterpolationFilter::m_bilinearFilterPrec4[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_BILINEAR] = +{ + { 16, 0, }, + { 15, 1, }, + { 14, 2, }, + { 13, 3, }, + { 12, 4, }, + { 11, 5, }, + { 10, 6, }, + { 9, 7, }, + { 8, 8, }, + { 7, 9, }, + { 6, 10, }, + { 5, 11, }, + { 4, 12, }, + { 3, 13, }, + { 2, 14, }, + { 1, 15, } +}; +#endif // ==================================================================================================================== // Private member functions // ==================================================================================================================== @@ -197,7 +218,11 @@ InterpolationFilter::InterpolationFilter() // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<bool isFirst, bool isLast> +#if JVET_M0147_DMVR +void InterpolationFilter::filterCopy( const ClpRng& clpRng, const Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool biMCForDMVR) +#else void InterpolationFilter::filterCopy( const ClpRng& clpRng, const Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height ) +#endif { int row, col; @@ -223,6 +248,40 @@ void InterpolationFilter::filterCopy( const ClpRng& clpRng, const Pel *src, int { const int shift = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd)); +#if JVET_M0147_DMVR + if (biMCForDMVR) + { + int shift10BitOut, offset; + if ((clpRng.bd - IF_INTERNAL_PREC_BILINEAR) > 0) + { + shift10BitOut = (clpRng.bd - IF_INTERNAL_PREC_BILINEAR); + offset = (1 << (shift10BitOut - 1)); + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + dst[col] = (src[col] + offset) >> shift10BitOut; + } + src += srcStride; + dst += dstStride; + } + } + else + { + shift10BitOut = (IF_INTERNAL_PREC_BILINEAR - clpRng.bd); + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + dst[col] = src[col] << shift10BitOut; + } + src += srcStride; + dst += dstStride; + } + } + } + else +#endif for (row = 0; row < height; row++) { for (col = 0; col < width; col++) @@ -240,6 +299,40 @@ void InterpolationFilter::filterCopy( const ClpRng& clpRng, const Pel *src, int { const int shift = std::max<int>(2, (IF_INTERNAL_PREC - clpRng.bd)); +#if JVET_M0147_DMVR + if (biMCForDMVR) + { + int shift10BitOut, offset; + if ((clpRng.bd - IF_INTERNAL_PREC_BILINEAR) > 0) + { + shift10BitOut = (clpRng.bd - IF_INTERNAL_PREC_BILINEAR); + offset = (1 << (shift10BitOut - 1)); + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + dst[col] = (src[col] + offset) >> shift10BitOut; + } + src += srcStride; + dst += dstStride; + } + } + else + { + shift10BitOut = (IF_INTERNAL_PREC_BILINEAR - clpRng.bd); + for (row = 0; row < height; row++) + { + for (col = 0; col < width; col++) + { + dst[col] = src[col] << shift10BitOut; + } + src += srcStride; + dst += dstStride; + } + } + } + else +#endif for (row = 0; row < height; row++) { for (col = 0; col < width; col++) @@ -282,7 +375,11 @@ void InterpolationFilter::filterCopy( const ClpRng& clpRng, const Pel *src, int // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<int N, bool isVertical, bool isFirst, bool isLast> +#if JVET_M0147_DMVR +void InterpolationFilter::filter(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR) +#else void InterpolationFilter::filter(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff) +#endif { int row, col; @@ -327,6 +424,13 @@ void InterpolationFilter::filter(const ClpRng& clpRng, Pel const *src, int srcSt offset = (isFirst) ? -IF_INTERNAL_OFFS << shift : 0; } +#if JVET_M0147_DMVR + if (biMCForDMVR) + { + shift = IF_FILTER_PREC_BILINEAR - (IF_INTERNAL_PREC_BILINEAR - clpRng.bd); + offset = 1 << (shift - 1); + } +#endif for (row = 0; row < height; row++) { for (col = 0; col < width; col++) @@ -387,20 +491,36 @@ void InterpolationFilter::filter(const ClpRng& clpRng, Pel const *src, int srcSt * \param coeff Pointer to filter taps */ template<int N> +#if JVET_M0147_DMVR +void InterpolationFilter::filterHor(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isLast, TFilterCoeff const *coeff, bool biMCForDMVR) +#else void InterpolationFilter::filterHor(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isLast, TFilterCoeff const *coeff) +#endif { //#if ENABLE_SIMD_OPT_MCIF if( N == 8 ) { +#if JVET_M0147_DMVR + m_filterHor[0][1][isLast](clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterHor[0][1][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else if( N == 4 ) { +#if JVET_M0147_DMVR + m_filterHor[1][1][isLast](clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterHor[1][1][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else if( N == 2 ) { +#if JVET_M0147_DMVR + m_filterHor[2][1][isLast](clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterHor[2][1][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else { @@ -424,20 +544,36 @@ void InterpolationFilter::filterHor(const ClpRng& clpRng, Pel const *src, int sr * \param coeff Pointer to filter taps */ template<int N> +#if JVET_M0147_DMVR +void InterpolationFilter::filterVer(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isFirst, bool isLast, TFilterCoeff const *coeff, bool biMCForDMVR) +#else void InterpolationFilter::filterVer(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isFirst, bool isLast, TFilterCoeff const *coeff) +#endif { //#if ENABLE_SIMD_OPT_MCIF if( N == 8 ) { +#if JVET_M0147_DMVR + m_filterVer[0][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterVer[0][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else if( N == 4 ) { +#if JVET_M0147_DMVR + m_filterVer[1][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterVer[1][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else if( N == 2 ) { +#if JVET_M0147_DMVR + m_filterVer[2][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff, biMCForDMVR); +#else m_filterVer[2][isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height, coeff ); +#endif } else{ THROW( "Invalid tap number" ); @@ -463,29 +599,49 @@ void InterpolationFilter::filterVer(const ClpRng& clpRng, Pel const *src, int sr * \param fmt Chroma format * \param bitDepth Bit depth */ +#if JVET_M0147_DMVR +void InterpolationFilter::filterHor( const ComponentID compID, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx, bool biMCForDMVR) +#else void InterpolationFilter::filterHor( const ComponentID compID, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx ) +#endif { if( frac == 0 ) { +#if JVET_M0147_DMVR + m_filterCopy[true][isLast](clpRng, src, srcStride, dst, dstStride, width, height, biMCForDMVR); +#else m_filterCopy[true][isLast]( clpRng, src, srcStride, dst, dstStride, width, height ); +#endif } else if( isLuma( compID ) ) { CHECK( frac < 0 || frac >= LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS, "Invalid fraction" ); if( nFilterIdx == 1 ) { +#if JVET_M0147_DMVR + filterHor<NTAPS_BILINEAR>(clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_bilinearFilterPrec4[frac], biMCForDMVR); +#else filterHor<NTAPS_BILINEAR>(clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_bilinearFilter[frac]); +#endif } else { +#if JVET_M0147_DMVR + filterHor<NTAPS_LUMA>( clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_lumaFilter[frac], biMCForDMVR); +#else filterHor<NTAPS_LUMA>( clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_lumaFilter[frac] ); +#endif } } else { const uint32_t csx = getComponentScaleX( compID, fmt ); CHECK( frac < 0 || csx >= 2 || ( frac << ( 1 - csx ) ) >= CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS, "Invalid fraction" ); +#if JVET_M0147_DMVR + filterHor<NTAPS_CHROMA>( clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_chromaFilter[frac << ( 1 - csx )], biMCForDMVR); +#else filterHor<NTAPS_CHROMA>( clpRng, src, srcStride, dst, dstStride, width, height, isLast, m_chromaFilter[frac << ( 1 - csx )] ); +#endif } } @@ -506,29 +662,49 @@ void InterpolationFilter::filterHor( const ComponentID compID, Pel const *src, i * \param fmt Chroma format * \param bitDepth Bit depth */ +#if JVET_M0147_DMVR +void InterpolationFilter::filterVer( const ComponentID compID, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isFirst, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx, bool biMCForDMVR) +#else void InterpolationFilter::filterVer( const ComponentID compID, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isFirst, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx) +#endif { if( frac == 0 ) { +#if JVET_M0147_DMVR + m_filterCopy[isFirst][isLast](clpRng, src, srcStride, dst, dstStride, width, height, biMCForDMVR); +#else m_filterCopy[isFirst][isLast]( clpRng, src, srcStride, dst, dstStride, width, height ); +#endif } else if( isLuma( compID ) ) { CHECK( frac < 0 || frac >= LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS, "Invalid fraction" ); if (nFilterIdx == 1) { +#if JVET_M0147_DMVR + filterVer<NTAPS_BILINEAR>(clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_bilinearFilterPrec4[frac], biMCForDMVR); +#else filterVer<NTAPS_BILINEAR>(clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_bilinearFilter[frac]); +#endif } else { +#if JVET_M0147_DMVR + filterVer<NTAPS_LUMA>( clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_lumaFilter[frac], biMCForDMVR); +#else filterVer<NTAPS_LUMA>( clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_lumaFilter[frac] ); +#endif } } else { const uint32_t csy = getComponentScaleY( compID, fmt ); CHECK( frac < 0 || csy >= 2 || ( frac << ( 1 - csy ) ) >= CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS, "Invalid fraction" ); +#if JVET_M0147_DMVR + filterVer<NTAPS_CHROMA>(clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_chromaFilter[frac << (1 - csy)], biMCForDMVR); +#else filterVer<NTAPS_CHROMA>( clpRng, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_chromaFilter[frac << ( 1 - csy )] ); +#endif } } diff --git a/source/Lib/CommonLib/InterpolationFilter.h b/source/Lib/CommonLib/InterpolationFilter.h index e4ca95491de7a1f841fb35aed7a2ebf7b2053036..be366a5477bc1ad7a38ee3bcf092684a93f93407 100644 --- a/source/Lib/CommonLib/InterpolationFilter.h +++ b/source/Lib/CommonLib/InterpolationFilter.h @@ -48,7 +48,10 @@ #define IF_INTERNAL_PREC 14 ///< Number of bits for internal precision #define IF_FILTER_PREC 6 ///< Log2 of sum of filter taps #define IF_INTERNAL_OFFS (1<<(IF_INTERNAL_PREC-1)) ///< Offset used internally - +#if JVET_M0147_DMVR +#define IF_INTERNAL_PREC_BILINEAR 10 ///< Number of bits for internal precision +#define IF_FILTER_PREC_BILINEAR 4 ///< Bilinear filter coeff precision so that intermediate value will not exceed 16 bit for SIMD - bit exact +#endif /** * \brief Interpolation filter class */ @@ -57,17 +60,36 @@ class InterpolationFilter static const TFilterCoeff m_lumaFilter[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_LUMA]; ///< Luma filter taps static const TFilterCoeff m_chromaFilter[CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_CHROMA]; ///< Chroma filter taps static const TFilterCoeff m_bilinearFilter[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_BILINEAR]; ///< bilinear filter taps +#if JVET_M0147_DMVR + static const TFilterCoeff m_bilinearFilterPrec4[LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS][NTAPS_BILINEAR]; ///< bilinear filter taps +#endif public: template<bool isFirst, bool isLast> +#if JVET_M0147_DMVR + static void filterCopy( const ClpRng& clpRng, const Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool biMCForDMVR); +#else static void filterCopy( const ClpRng& clpRng, const Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height ); +#endif template<int N, bool isVertical, bool isFirst, bool isLast> +#if JVET_M0147_DMVR + static void filter(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR); +#else static void filter(const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff); - +#endif template<int N> +#if JVET_M0147_DMVR + void filterHor(const ClpRng& clpRng, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isLast, TFilterCoeff const *coeff, bool biMCForDMVR); +#else void filterHor(const ClpRng& clpRng, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isLast, TFilterCoeff const *coeff); +#endif + template<int N> +#if JVET_M0147_DMVR + void filterVer(const ClpRng& clpRng, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isFirst, bool isLast, TFilterCoeff const *coeff, bool biMCForDMVR); +#else void filterVer(const ClpRng& clpRng, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, bool isFirst, bool isLast, TFilterCoeff const *coeff); +#endif protected: #if JVET_J0090_MEMORY_BANDWITH_MEASURE @@ -76,10 +98,21 @@ protected: public: InterpolationFilter(); ~InterpolationFilter() {} - +#if JVET_M0147_DMVR + void( *m_filterHor[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR); +#else void( *m_filterHor[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff ); +#endif +#if JVET_M0147_DMVR + void( *m_filterVer[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR); +#else void( *m_filterVer[3][2][2] )( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff ); +#endif +#if JVET_M0147_DMVR + void( *m_filterCopy[2][2] ) ( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, bool biMCForDMVR); +#else void( *m_filterCopy[2][2] ) ( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height ); +#endif void initInterpolationFilter( bool enable ); #ifdef TARGET_SIMD_X86 @@ -87,9 +120,16 @@ public: template <X86_VEXT vext> void _initInterpolationFilterX86(); #endif - +#if JVET_M0147_DMVR + void filterHor(const ComponentID compID, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx = 0, bool biMCForDMVR = false); +#else void filterHor(const ComponentID compID, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx = 0); +#endif +#if JVET_M0147_DMVR + void filterVer(const ComponentID compID, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isFirst, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx = 0, bool biMCForDMVR = false); +#else void filterVer(const ComponentID compID, Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int frac, bool isFirst, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng, int nFilterIdx = 0); +#endif #if JVET_J0090_MEMORY_BANDWITH_MEASURE void cacheAssign( CacheModel *cache ) { m_cacheModel = cache; } #endif diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index e49e92eceee0a95924f7d469f72ff4934e80877e..da5a61234c02c36857d8b889deff44a74c0ed80d 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -212,11 +212,6 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth } } - int shift = bitDepthY + 4; - for (int i = 32; i < 64; i++) - { - m_auShiftLM[i - 32] = ((1 << shift) + i / 2) / i; - } if (m_piTemp == nullptr) { m_piTemp = new Pel[(MAX_CU_SIZE + 1) * (MAX_CU_SIZE + 1)]; @@ -299,6 +294,9 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co const ChannelType channelType = toChannelType( compID ); const int iWidth = piPred.width; const int iHeight = piPred.height; +#if JVET_M0102_INTRA_SUBPARTITIONS + const Size cuSize = Size( pu.cu->blocks[compId].width, pu.cu->blocks[compId].height ); +#endif const uint32_t uiDirMode = PU::getFinalIntraMode( pu, channelType ); @@ -306,8 +304,14 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" ); const int multiRefIdx = (compID == COMPONENT_Y) ? pu.multiRefIdx : 0; +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useISP = pu.cu->ispMode && isLuma( compID ); + const int whRatio = useISP ? std::max( unsigned( 1 ), cuSize.width / cuSize.height ) : std::max( 1, iWidth / iHeight ); + const int hwRatio = useISP ? std::max( unsigned( 1 ), cuSize.height / cuSize.width ) : std::max( 1, iHeight / iWidth ); +#else int whRatio = std::max(1, iWidth / iHeight); int hwRatio = std::max(1, iHeight / iWidth); +#endif const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; @@ -321,20 +325,34 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co case(2): case(DIA_IDX): case(VDIA_IDX): +#if JVET_M0102_INTRA_SUBPARTITIONS + if (getWideAngle(useISP ? cuSize.width : iWidth, useISP ? cuSize.height : iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle + { + xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, multiRefIdx, useFilteredPredSamples, useISP, cuSize ); +#else if (getWideAngle(iWidth, iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle { xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps , multiRefIdx , useFilteredPredSamples); +#endif break; } +#if JVET_M0102_INTRA_SUBPARTITIONS + default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, multiRefIdx, useFilteredPredSamples, useISP, cuSize); break; +#else default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps , multiRefIdx , useFilteredPredSamples); break; +#endif } bool pdpcCondition = (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX || uiDirMode == HOR_IDX || uiDirMode == VER_IDX); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pdpcCondition && multiRefIdx == 0 && !useISP ) +#else if (pdpcCondition && multiRefIdx == 0) +#endif { const CPelBuf srcBuf = CPelBuf(ptrSrc, srcStride, srcStride); PelBuf dstBuf = piPred; @@ -445,11 +463,20 @@ void IntraPrediction::xPredIntraPlanar( const CPelBuf &pSrc, PelBuf &pDst, const { const uint32_t width = pDst.width; const uint32_t height = pDst.height; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t log2W = g_aucLog2[width < 2 ? 2 : width]; + const uint32_t log2H = g_aucLog2[height < 2 ? 2 : height]; +#else const uint32_t log2W = g_aucLog2[ width ]; const uint32_t log2H = g_aucLog2[ height ]; +#endif int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t offset = 1 << (log2W + log2H); +#else const uint32_t offset = width * height; +#endif // Get left and above reference column and row for( int k = 0; k < width + 1; k++ ) @@ -561,17 +588,28 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch , int multiRefIdx , const bool enableBoundaryFilter ) #else +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, + int multiRefIdx, + const bool useFilteredPredSamples , + const bool useISP, + const Size cuSize ) +#else void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps , int multiRefIdx , const bool useFilteredPredSamples ) #endif +#endif { int width =int(pDst.width); int height=int(pDst.height); CHECK( !( dirMode > DC_IDX && dirMode < NUM_LUMA_MODE ), "Invalid intra dir" ); - +#if JVET_M0102_INTRA_SUBPARTITIONS + int predMode = useISP ? getWideAngle( cuSize.width, cuSize.height, dirMode ) : getWideAngle( width, height, dirMode ); +#else int predMode = getWideAngle(width, height, dirMode); +#endif const bool bIsModeVer = predMode >= DIA_IDX; const int intraPredAngleMode = (bIsModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX); const int absAngMode = abs(intraPredAngleMode); @@ -582,8 +620,8 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch // Set bitshifts and scale the angle parameter to block size - static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 85, 102, 128, 171, 256, 341, 512, 1024 }; - static const int invAngTable[32] = { 0, 8192, 4096, 2731, 2048, 1365, 1024, 819, 683, 585, 512, 455, 410, 356, 315, 282, 256, 234, 210, 182, 160, 144, 128, 112, 96, 80, 64, 48, 32, 24, 16, 8 }; // (256 * 32) / Angle + static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 }; + static const int invAngTable[32] = { 0, 8192, 4096, 2731, 2048, 1365, 1024, 819, 683, 585, 512, 455, 410, 356, 315, 282, 256, 234, 210, 182, 160, 144, 128, 112, 95, 80, 64, 48, 32, 24, 16, 8 }; // (256 * 32) / Angle int invAngle = invAngTable[absAngMode]; int absAng = angTable [absAngMode]; @@ -595,8 +633,13 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const int whRatio = useISP ? std::max( unsigned( 1 ), cuSize.width / cuSize.height ) : std::max( 1, width / height ); + const int hwRatio = useISP ? std::max( unsigned( 1 ), cuSize.height / cuSize.width ) : std::max( 1, height / width ); +#else int whRatio = std::max(1, width / height); int hwRatio = std::max(1, height / width); +#endif // Initialize the Main and Left reference array. if (intraPredAngle < 0) @@ -691,7 +734,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch if( isLuma(channelType) ) { Pel p[4]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useCubicFilter = useISP ? ( width <= 8 ) : ( !useFilteredPredSamples || multiRefIdx > 0 ); +#else const bool useCubicFilter = !useFilteredPredSamples || multiRefIdx > 0; +#endif TFilterCoeff const * const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract]; int refMainIndex = deltaInt + 1; @@ -735,6 +782,10 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch const int numModes = 8; const int scale = ((g_aucLog2[width] - 2 + g_aucLog2[height] - 2 + 2) >> 2); CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31"); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !useISP ) + { +#endif if ((predMode == 2 || predMode == VDIA_IDX) && multiRefIdx == 0) { int wT = 16 >> std::min(31, ((y << 1) >> scale)); @@ -770,10 +821,17 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch if (wL == 0) break; Pel *p = refSide + deltay; +#if JVET_M0238_PDPC_NO_INTERPOLATION + Pel left = p[deltaFrac0 >> 5]; +#else Pel left = (((64 - deltaFrac0) * p[0] + deltaFrac0 * p[1] + 32) >> 6); +#endif pDsty[x] = ClipPel((wL * left + (64 - wL) * pDsty[x] + 32) >> 6, clpRng); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif } #if HEVC_USE_HOR_VER_PREDFILTERING if( edgeFilter && absAng <= 1 ) @@ -941,7 +999,11 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre Pel *refBufUnfiltered = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED]; Pel *refBufFiltered = m_piYuvExt[area.compID][PRED_BUF_FILTERED]; +#if JVET_M0102_INTRA_SUBPARTITIONS + setReferenceArrayLengths( cu.ispMode && isLuma( area.compID ) ? cu.blocks[area.compID] : area ); +#else setReferenceArrayLengths(area); +#endif // ----- Step 1: unfiltered reference samples ----- xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu ); @@ -967,13 +1029,25 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf const int tuHeight = area.height; const int predSize = m_topRefLength; const int predHSize = m_leftRefLength; +#if JVET_M0102_INTRA_SUBPARTITIONS + const int cuWidth = cu.blocks[area.compID].width; + const int cuHeight = cu.blocks[area.compID].height; + const int whRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuWidth / cuHeight) : std::max(1, tuWidth / tuHeight); + const int hwRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuHeight / cuWidth) : std::max(1, tuHeight / tuWidth); +#else int whRatio = std::max(1, tuWidth / tuHeight); int hwRatio = std::max(1, tuHeight / tuWidth); +#endif const int predStride = predSize + 1 + (whRatio + 1) * multiRefIdx; const bool noShift = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split) +#if JVET_M0102_INTRA_SUBPARTITIONS + const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc())); + const int unitHeight = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY(area.compID, sps.getChromaFormatIdc())); +#else const int unitWidth = pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX( area.compID, sps.getChromaFormatIdc() )); const int unitHeight = pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY( area.compID, sps.getChromaFormatIdc() )); +#endif const int totalAboveUnits = (predSize + (unitWidth - 1)) / unitWidth; const int totalLeftUnits = (predHSize + (unitHeight - 1)) / unitHeight; @@ -1289,6 +1363,9 @@ bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, con if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag() ) { return false; } if( !isLuma( chType ) && pu.chromaFormat != CHROMA_444 ) { return false; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu.cu->ispMode && isLuma(compID) ) { return false; } +#endif if( !modeSpecific ) { return true; } @@ -1564,7 +1641,7 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom } } #if JVET_M0142_CCLM_COLLOCATED_CHROMA - else if( pu.cs->sps->getSpsNext().getCclmCollocatedChromaFlag() ) + else if( pu.cs->sps->getCclmCollocatedChromaFlag() ) { piSrc = pRecSrc0 - iRecStride2; @@ -1611,7 +1688,7 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom for (int j = 0; j < uiCHeight + addedLeftBelow; j++) { #if JVET_M0142_CCLM_COLLOCATED_CHROMA - if( pu.cs->sps->getSpsNext().getCclmCollocatedChromaFlag() ) + if( pu.cs->sps->getCclmCollocatedChromaFlag() ) { if( j == 0 && !bAboveAvaillable ) { @@ -1647,7 +1724,7 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom for( int i = 0; i < uiCWidth; i++ ) { #if JVET_M0142_CCLM_COLLOCATED_CHROMA - if( pu.cs->sps->getSpsNext().getCclmCollocatedChromaFlag() ) + if( pu.cs->sps->getCclmCollocatedChromaFlag() ) { if( i == 0 && !bLeftAvaillable ) { diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 7a1995ed2e030f4570228fd40b8aa77c483134b9..63c36a9a91fd63fbc74ad81104eaa133ceaba08e 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -74,8 +74,6 @@ private: static const uint8_t m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS]; - unsigned m_auShiftLM[32]; // Table for substituting division operation by multiplication - Pel* m_piTemp; Pel* m_pMdlmTemp; // for MDLM mode protected: @@ -91,15 +89,23 @@ protected: void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps , int multiRefIdx , const bool enableBoundaryFilter = true ); +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, + int multiRefIdx, + const bool useFilteredPredSamples, + const bool useISP = false, + const Size cuSize = Size( 0, 0 ) ); #else void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps , int multiRefIdx , const bool useFilteredPredSamples ); +#endif #endif Pel xGetPredValDc ( const CPelBuf &pSrc, const Size &dstSize ); void xFillReferenceSamples ( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu ); - void xFilterReferenceSamples ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps + void xFilterReferenceSamples ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps , int multiRefIdx ); diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index f8543f5bc8a63203456999609cfe618e55c3a381..b3362a350a49a9171e438ec58b791a79356ab8a6 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -242,10 +242,24 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir ) const Area area = cu.Y().valid() ? cu.Y() : Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) ); xSetLoopfilterParam( cu ); - +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + bool implicitTU = false; +#endif for( auto &currTU : CU::traverseTUs( cu ) ) { const Area& areaTu = cu.Y().valid() ? currTU.block( COMPONENT_Y ) : area; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const bool xOff = currTU.blocks[cu.chType].x != cu.blocks[cu.chType].x; + const bool yOff = currTU.blocks[cu.chType].y != cu.blocks[cu.chType].y; + if ((yOff != 0) && (edgeDir == EDGE_HOR)) + { + implicitTU = true; + } + if ((xOff != 0) && (edgeDir == EDGE_VER)) + { + implicitTU = true; + } +#endif xSetEdgefilterMultiple( cu, EDGE_VER, areaTu, m_stLFCUParam.internalEdge ); xSetEdgefilterMultiple( cu, EDGE_HOR, areaTu, m_stLFCUParam.internalEdge ); } @@ -282,6 +296,32 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir ) } } } +#if JVET_M0908_CIIP_DB + if (cu.firstPU->mhIntraFlag) + { + const uint32_t dirMode = PU::getFinalIntraMode(*(cu.firstPU), cu.chType); + if (edgeDir == EDGE_VER && dirMode == HOR_IDX) + { + mvSubBlocks = true; + subBlockSize = std::max(8u, (area.width >> 2)); + for (uint32_t off = subBlockSize; off < area.width; off += subBlockSize) + { + const Area mvBlockV(cu.Y().x + off, cu.Y().y, pcv.minCUWidth, cu.Y().height); + xSetEdgefilterMultiple(cu, EDGE_VER, mvBlockV, m_stLFCUParam.internalEdge, 1); + } + } + else if (edgeDir == EDGE_HOR && dirMode == VER_IDX) + { + mvSubBlocks = true; + subBlockSize = std::max(8u, (area.height >> 2)); + for (uint32_t off = subBlockSize; off < area.height; off += subBlockSize) + { + const Area mvBlockH(cu.Y().x, cu.Y().y + off, cu.Y().width, pcv.minCUHeight); + xSetEdgefilterMultiple(cu, EDGE_HOR, mvBlockH, m_stLFCUParam.internalEdge, 1); + } + } + } +#endif const unsigned uiPelsInPart = pcv.minCUWidth; @@ -313,14 +353,50 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir ) unsigned int orthogonalLength = 1; unsigned int orthogonalIncrement = 1; - +#if FIX_DB_MAX_TRANSFORM_SIZE + int maxTsize = 64; + maxTsize = 1 << cu.slice->getSPS()->getQuadtreeTULog2MaxSize(); +#endif +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +#if FIX_DB_MAX_TRANSFORM_SIZE + int maxFilterLengthQ = 7; + int maxFilterLengthP = 7; + if (implicitTU && maxTsize < 32) + { + maxFilterLengthQ = 3; + maxFilterLengthP = 3; + } +#else + int maxFilterLength = 7; +#endif +#endif if (cu.blocks[COMPONENT_Y].valid()) { if (mvSubBlocks) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +#if FIX_DB_MAX_TRANSFORM_SIZE + maxFilterLengthQ = std::min(maxFilterLengthQ, 5); +#else + maxFilterLength = 5; +#endif +#endif orthogonalIncrement = subBlockSize / 4; orthogonalLength = (edgeDir == EDGE_HOR) ? cu.blocks[COMPONENT_Y].height / 4 : cu.blocks[COMPONENT_Y].width / 4; } +#if FIX_DB_MAX_TRANSFORM_SIZE + if ((cu.blocks[COMPONENT_Y].height > maxTsize) && (edgeDir == EDGE_HOR) && !mvSubBlocks) + { + orthogonalIncrement = maxTsize / 4; + orthogonalLength = cu.blocks[COMPONENT_Y].height / 4; + } + if ((cu.blocks[COMPONENT_Y].width > maxTsize) && (edgeDir == EDGE_VER) && !mvSubBlocks) + { + orthogonalIncrement = maxTsize / 4; + orthogonalLength = cu.blocks[COMPONENT_Y].width / 4; + + } +#else if ((cu.blocks[COMPONENT_Y].height > 64) && (edgeDir == EDGE_HOR) && !mvSubBlocks) { orthogonalIncrement = 64 / 4; @@ -332,12 +408,52 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir ) orthogonalLength = cu.blocks[COMPONENT_Y].width / 4; } +#endif } + for (int edge = 0; edge < orthogonalLength; edge += orthogonalIncrement) { if (cu.blocks[COMPONENT_Y].valid()) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (edge == 0) + { +#if FIX_DB_MAX_TRANSFORM_SIZE + xEdgeFilterLuma(cu, edgeDir, edge, maxFilterLengthP, maxFilterLengthQ); +#else + xEdgeFilterLuma(cu, edgeDir, edge, 7, maxFilterLength); +#endif + } + else + { +#if FIX_DB_MAX_TRANSFORM_SIZE + if (implicitTU && ((edge % (maxTsize / 4)) == 0)) +#else + if ( implicitTU && (edge == (64 / 4)) ) +#endif + { +#if FIX_DB_MAX_TRANSFORM_SIZE + xEdgeFilterLuma(cu, edgeDir, edge, maxFilterLengthQ, maxFilterLengthQ); +#else + xEdgeFilterLuma(cu, edgeDir, edge, maxFilterLength, maxFilterLength); +#endif + } +#if FIX_DB_MAX_TRANSFORM_SIZE + else if ((edge == 2 || edge == (orthogonalLength - 2)) || (implicitTU && (((edge - 2) % ((maxTsize) / 4) == 0) || ((edge + 2) % ((maxTsize) / 4) == 0)))) +#else + else if ( (edge == 2 || edge == (orthogonalLength - 2)) || (implicitTU && (edge == (56 / 4) || edge == (72 / 4))) ) +#endif + { + xEdgeFilterLuma(cu, edgeDir, edge, 2, 2); + } + else + { + xEdgeFilterLuma(cu, edgeDir, edge, 3, 3); + } + } +#else xEdgeFilterLuma(cu, edgeDir, edge); +#endif } if (cu.blocks[COMPONENT_Cb].valid() && pcv.chrFormat != CHROMA_400) { @@ -392,52 +508,115 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu ) m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailable ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag()); m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailable ( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag()); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + m_stLFCUParam.internalEdge &= !cu.ispMode; +#endif } unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + // The boundary strength that is output by the function xGetBoundaryStrengthSingle is a multi component boundary strength that contains boundary strength for luma (bits 0 to 1), cb (bits 2 to 3) and cr (bits 4 to 5). +#endif + const Slice& sliceQ = *cu.slice; - const Position& cuPosLuma = cu.lumaPos(); int shiftHor = cu.Y().valid() ? 0 : ::getComponentScaleX(COMPONENT_Cb, cu.firstPU->chromaFormat); int shiftVer = cu.Y().valid() ? 0 : ::getComponentScaleY(COMPONENT_Cb, cu.firstPU->chromaFormat); const Position& posQ = Position{ localPos.x >> shiftHor, localPos.y >> shiftVer }; const Position posP = ( edgeDir == EDGE_VER ) ? posQ.offset( -1, 0 ) : posQ.offset( 0, -1 ); - const bool sameCU = posP.x >= cuPosLuma.x && posP.y >= cuPosLuma.y; - const CodingUnit& cuQ = cu; - const CodingUnit& cuP = sameCU ? cu : *cu.cs->getCU( posP, cu.chType ); + const CodingUnit& cuP = *cu.cs->getCU( posP, cu.chType ); //-- Set BS for Intra MB : BS = 4 or 3 if( ( MODE_INTRA == cuP.predMode ) || ( MODE_INTRA == cuQ.predMode ) ) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + return (BsSet(2, COMPONENT_Y) + BsSet(2, COMPONENT_Cb) + BsSet(2, COMPONENT_Cr)); +#else return 2; +#endif } - const TransformUnit& tuQ = posQ == cuQ.lumaPos() ? *cuQ.firstTU : *cuQ.cs->getTU(posQ, cuQ.chType); - const TransformUnit& tuP = posP == cuP.lumaPos() ? *cuP.firstTU : *cuP.cs->getTU(posP, cuP.chType); + const TransformUnit& tuQ = *cuQ.cs->getTU(posQ, cuQ.chType); + const TransformUnit& tuP = *cuP.cs->getTU(posP, cuP.chType); const PreCalcValues& pcv = *cu.cs->pcv; const unsigned rasterIdx = getRasterIdx( posQ, pcv ); +#if JVET_M0908_CIIP_DB + if (m_aapucBS[edgeDir][rasterIdx] && (cuP.firstPU->mhIntraFlag || cuQ.firstPU->mhIntraFlag)) + { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + return (BsSet(2, COMPONENT_Y) + BsSet(2, COMPONENT_Cb) + BsSet(2, COMPONENT_Cr)); +#else + return 2; +#endif + } +#endif +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + unsigned tmpBs = 0; + //-- Set BS for not Intra MB : BS = 2 or 1 or 0 + // Y + if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Y) || TU::getCbf(tuP, COMPONENT_Y))) + { + tmpBs += BsSet(1, COMPONENT_Y); + } + // U + if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cb) || TU::getCbf(tuP, COMPONENT_Cb))) + { + tmpBs += BsSet(1, COMPONENT_Cb); + } + // V + if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cr) || TU::getCbf(tuP, COMPONENT_Cr))) + { + tmpBs += BsSet(1, COMPONENT_Cr); + } + if (BsGet(tmpBs, COMPONENT_Y) == 1) + { + return tmpBs; + } +#else //-- Set BS for not Intra MB : BS = 2 or 1 or 0 if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Y) || TU::getCbf(tuP, COMPONENT_Y))) { return 1; } +#endif +#if JVET_M0908_CIIP_DB + if ((cuP.firstPU->mhIntraFlag || cuQ.firstPU->mhIntraFlag)) + { + return 1; + } +#endif + +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if ( !cu.Y().valid() ) + { + return tmpBs; + } +#endif // and now the pred - const MotionInfo& miQ = cuQ.cs->getMotionInfo( posQ ); - const MotionInfo& miP = cuP.cs->getMotionInfo( posP ); + const Position& lumaPosQ = Position{ localPos.x, localPos.y }; + const Position lumaPosP = ( edgeDir == EDGE_VER ) ? lumaPosQ.offset( -1, 0 ) : lumaPosQ.offset( 0, -1 ); + const MotionInfo& miQ = cuQ.cs->getMotionInfo( lumaPosQ ); + const MotionInfo& miP = cuP.cs->getMotionInfo( lumaPosP ); const Slice& sliceP = *cuP.slice; if (sliceQ.isInterB() || sliceP.isInterB()) { +#if JVET_M0483_IBC + const Picture *piRefP0 = (CU::isIBC(cuP) ? sliceP.getPic() : ((0 > miP.refIdx[0]) ? NULL : sliceP.getRefPic(REF_PIC_LIST_0, miP.refIdx[0]))); + const Picture *piRefP1 = (CU::isIBC(cuP) ? NULL : ((0 > miP.refIdx[1]) ? NULL : sliceP.getRefPic(REF_PIC_LIST_1, miP.refIdx[1]))); + const Picture *piRefQ0 = (CU::isIBC(cuQ) ? sliceQ.getPic() : ((0 > miQ.refIdx[0]) ? NULL : sliceQ.getRefPic(REF_PIC_LIST_0, miQ.refIdx[0]))); + const Picture *piRefQ1 = (CU::isIBC(cuQ) ? NULL : ((0 > miQ.refIdx[1]) ? NULL : sliceQ.getRefPic(REF_PIC_LIST_1, miQ.refIdx[1]))); +#else const Picture *piRefP0 = ( 0 > miP.refIdx[0] ) ? NULL : sliceP.getRefPic( REF_PIC_LIST_0, miP.refIdx[0] ); const Picture *piRefP1 = ( 0 > miP.refIdx[1] ) ? NULL : sliceP.getRefPic( REF_PIC_LIST_1, miP.refIdx[1] ); const Picture *piRefQ0 = ( 0 > miQ.refIdx[0] ) ? NULL : sliceQ.getRefPic( REF_PIC_LIST_0, miQ.refIdx[0] ); const Picture *piRefQ1 = ( 0 > miQ.refIdx[1] ) ? NULL : sliceQ.getRefPic( REF_PIC_LIST_1, miQ.refIdx[1] ); - +#endif Mv mvP0, mvP1, mvQ0, mvQ1; if( 0 <= miP.refIdx[0] ) { mvP0 = miP.mv[0]; } @@ -480,33 +659,51 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De { uiBs = 1; } +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + return uiBs + tmpBs; +#else return uiBs; +#endif } // pcSlice->isInterP() +#if JVET_M0483_IBC + CHECK(CU::isInter(cuP) && 0 > miP.refIdx[0], "Invalid reference picture list index"); + CHECK(CU::isInter(cuP) && 0 > miQ.refIdx[0], "Invalid reference picture list index"); + const Picture *piRefP0 = (CU::isIBC(cuP) ? sliceP.getPic() : sliceP.getRefPic(REF_PIC_LIST_0, miP.refIdx[0])); + const Picture *piRefQ0 = (CU::isIBC(cuQ) ? sliceQ.getPic() : sliceQ.getRefPic(REF_PIC_LIST_0, miQ.refIdx[0])); +#else CHECK(0 > miP.refIdx[0], "Invalid reference picture list index"); CHECK(0 > miQ.refIdx[0], "Invalid reference picture list index"); const Picture *piRefP0 = sliceP.getRefPic(REF_PIC_LIST_0, miP.refIdx[0]); const Picture *piRefQ0 = sliceQ.getRefPic(REF_PIC_LIST_0, miQ.refIdx[0]); - +#endif if (piRefP0 != piRefQ0) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + return tmpBs + 1; +#else return 1; +#endif } Mv mvP0 = miP.mv[0]; Mv mvQ0 = miQ.mv[0]; int nThreshold = 1 << MV_FRACTIONAL_BITS_INTERNAL; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + return ( ( abs( mvQ0.getHor() - mvP0.getHor() ) >= nThreshold ) || ( abs( mvQ0.getVer() - mvP0.getVer() ) >= nThreshold ) ) ? (tmpBs + 1) : tmpBs; +#else return ( ( abs( mvQ0.getHor() - mvP0.getHor() ) >= nThreshold ) || ( abs( mvQ0.getVer() - mvP0.getVer() ) >= nThreshold ) ) ? 1 : 0; +#endif } #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET void LoopFilter::deriveLADFShift( const Pel* src, const int stride, int& shift, const DeblockEdgeDir edgeDir, const SPS sps ) { uint32_t lumaLevel = 0; - shift = sps.getSpsNext().getLadfQpOffset(0); + shift = sps.getLadfQpOffset(0); if (edgeDir == EDGE_VER) { @@ -517,12 +714,12 @@ void LoopFilter::deriveLADFShift( const Pel* src, const int stride, int& shift, lumaLevel = (src[0] + src[3] + src[-stride] + src[-stride + 3]) >> 2; } - for ( int k = 1; k < sps.getSpsNext().getLadfNumIntervals(); k++ ) + for ( int k = 1; k < sps.getLadfNumIntervals(); k++ ) { - const int th = sps.getSpsNext().getLadfIntervalLowerBound( k ); + const int th = sps.getLadfIntervalLowerBound( k ); if ( lumaLevel > th ) { - shift = sps.getSpsNext().getLadfQpOffset( k ); + shift = sps.getLadfQpOffset( k ); } else { @@ -532,7 +729,11 @@ void LoopFilter::deriveLADFShift( const Pel* src, const int stride, int& shift, } #endif +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge, const int initialMaxFilterLengthP, const int initialMaxFilterLengthQ) +#else void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge) +#endif { const CompArea& lumaArea = cu.block(COMPONENT_Y); const PreCalcValues& pcv = *cu.cs->pcv; @@ -591,7 +792,11 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge pos.y += yoffset; uiBsAbsIdx = getRasterIdx( pos, pcv ); +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + uiBs = BsGet(m_aapucBS[edgeDir][uiBsAbsIdx], COMPONENT_Y); +#else uiBs = m_aapucBS[edgeDir][uiBsAbsIdx]; +#endif if( uiBs ) { @@ -618,13 +823,54 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge iQP = (cuP.qp + cuQ.qp + 1) >> 1; #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - if ( sps.getSpsNext().getLadfEnabled() ) + if ( sps.getLadfEnabled() ) { int iShift = 0; deriveLADFShift( piTmpSrc + iSrcStep * (iIdx*pelsInPart), iStride, iShift, edgeDir, sps ); iQP += iShift; } #endif + +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + bool sidePisLarge = false; + bool sideQisLarge = false; + int maxFilterLengthP = initialMaxFilterLengthP; + int maxFilterLengthQ = initialMaxFilterLengthQ; + if (maxFilterLengthP > 3) + { + sidePisLarge = (edgeDir == EDGE_VER && cuP.block(COMPONENT_Y).width >= 32) + || (edgeDir == EDGE_HOR && cuP.block(COMPONENT_Y).height >= 32); + + if (sidePisLarge && maxFilterLengthP > 5) + { + // restrict filter length if sub-blocks are used (e.g affine or ATMVP) +#if JVET_M0908_CIIP_DB + bool ciipSubBlock = false; + if (cuP.firstPU->mhIntraFlag) + { + const uint32_t dirMode = PU::getFinalIntraMode(*(cuP.firstPU), cuP.chType); + ciipSubBlock = edgeDir == EDGE_HOR ? dirMode == VER_IDX : dirMode == HOR_IDX; + } + if (cuP.affine || ciipSubBlock) +#else + if (cuP.affine) +#endif + { + maxFilterLengthP = std::min(maxFilterLengthP, 5); + } + } + } + if (maxFilterLengthQ > 3) + { + sideQisLarge = (edgeDir == EDGE_VER && cuQ.block(COMPONENT_Y).width >= 32) + || (edgeDir == EDGE_HOR && cuQ.block(COMPONENT_Y).height >= 32); + } + + if (edgeDir == EDGE_HOR && pos.y % slice.getSPS()->getCTUSize() == 0) + { + sidePisLarge = false; + } +#endif const int iIndexTC = Clip3(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, int(iQP + DEFAULT_INTRA_TC_OFFSET*(uiBs - 1) + (tcOffsetDiv2 << 1))); const int iIndexB = Clip3(0, MAX_QP, iQP + (betaOffsetDiv2 << 1)); @@ -641,6 +887,72 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge const int dq0 = xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0), iOffset); const int dp3 = xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3), iOffset); const int dq3 = xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3), iOffset); +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + int dp0L = dp0; + int dq0L = dq0; + int dp3L = dp3; + int dq3L = dq3; + + if (sidePisLarge) + { + dp0L = (dp0L + xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0) - 3 * iOffset, iOffset) + 1) >> 1; + dp3L = (dp3L + xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3) - 3 * iOffset, iOffset) + 1) >> 1; + } + if (sideQisLarge) + { + dq0L = (dq0L + xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0) + 3 * iOffset, iOffset) + 1) >> 1; + dq3L = (dq3L + xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3) + 3 * iOffset, iOffset) + 1) >> 1; + } + bool useLongtapFilter = false; + if (sidePisLarge || sideQisLarge) + { + int d0L = dp0L + dq0L; + int d3L = dp3L + dq3L; + + int dpL = dp0L + dp3L; + int dqL = dq0L + dq3L; + + int dL = d0L + d3L; + + bPartPNoFilter = bPartQNoFilter = false; + if (bPCMFilter) + { + // Check if each of PUs is I_PCM with LF disabling + bPartPNoFilter = cuP.ipcm; + bPartQNoFilter = cuQ.ipcm; + } + if (ppsTransquantBypassEnabledFlag) + { + // check if each of PUs is lossless coded + bPartPNoFilter = bPartPNoFilter || cuP.transQuantBypass; + bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass; + } + + if (dL < iBeta) + { + const bool filterP = (dpL < iSideThreshold); + const bool filterQ = (dqL < iSideThreshold); + + Pel* src0 = piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 0); + Pel* src3 = piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 3); + + // adjust decision so that it is not read beyond p5 is maxFilterLengthP is 5 and q5 if maxFilterLengthQ is 5 + const bool swL = xUseStrongFiltering(src0, iOffset, 2 * d0L, iBeta, iTc, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ) + && xUseStrongFiltering(src3, iOffset, 2 * d3L, iBeta, iTc, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ); + if (swL) + { + useLongtapFilter = true; + for (int i = 0; i < DEBLOCK_SMALLEST_BLOCK / 2; i++) + { + xPelFilterLuma(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + i), iOffset, iTc, swL, bPartPNoFilter, bPartQNoFilter, iThrCut, filterP, filterQ, clpRng, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ); + } + } + + } + } + if (!useLongtapFilter) + { +#endif const int d0 = dp0 + dq0; const int d3 = dp3 + dq3; @@ -666,15 +978,25 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge { const bool bFilterP = (dp < iSideThreshold); const bool bFilterQ = (dq < iSideThreshold); - +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + bool sw = false; + if (maxFilterLengthP > 2 && maxFilterLengthQ > 2) + { + sw = xUseStrongFiltering(piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 0), iOffset, 2 * d0, iBeta, iTc) + && xUseStrongFiltering(piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 3), iOffset, 2 * d3, iBeta, iTc); + } +#else const bool sw = xUseStrongFiltering( piTmpSrc + iSrcStep * ( iIdx*pelsInPart + iBlkIdx * 4 + 0 ), iOffset, 2 * d0, iBeta, iTc ) && xUseStrongFiltering( piTmpSrc + iSrcStep * ( iIdx*pelsInPart + iBlkIdx * 4 + 3 ), iOffset, 2 * d3, iBeta, iTc ); - +#endif for( int i = 0; i < DEBLOCK_SMALLEST_BLOCK / 2; i++ ) { xPelFilterLuma( piTmpSrc + iSrcStep*( iIdx*pelsInPart + iBlkIdx * 4 + i ), iOffset, iTc, sw, bPartPNoFilter, bPartQNoFilter, iThrCut, bFilterP, bFilterQ, clpRng ); } } +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + } +#endif } } } @@ -708,6 +1030,9 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed bool bPartPNoFilter = false; bool bPartQNoFilter = false; const int tcOffsetDiv2 = slice.getDeblockingFilterTcOffsetDiv2(); +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const int betaOffsetDiv2 = slice.getDeblockingFilterBetaOffsetDiv2(); +#endif // Vertical Position unsigned uiEdgeNumInCtuVert = rasterIdx % pcv.partsInCtuWidth + iEdge; @@ -726,7 +1051,11 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed unsigned uiNumParts = ( edgeDir == EDGE_VER ) ? lumaSize.height / pcv.minCUHeight : lumaSize.width / pcv.minCUWidth ; int uiNumPelsLuma = pcv.minCUWidth; unsigned uiBsAbsIdx; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + unsigned bS[2]; +#else unsigned ucBs; +#endif Pel* piTmpSrcCb = piSrcCb; Pel* piTmpSrcCr = piSrcCr; @@ -764,9 +1093,21 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed pos.y += yoffset; uiBsAbsIdx = getRasterIdx( pos, pcv ); +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + unsigned tmpBs = m_aapucBS[edgeDir][uiBsAbsIdx]; + + tmpBs = m_aapucBS[edgeDir][uiBsAbsIdx]; + bS[0] = BsGet(tmpBs, COMPONENT_Cb); + bS[1] = BsGet(tmpBs, COMPONENT_Cr); +#else ucBs = m_aapucBS[edgeDir][uiBsAbsIdx]; +#endif +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (bS[0] > 0 || bS[1] > 0) +#else if (ucBs > 1) +#endif { const CodingUnit& cuQ = cu; const CodingUnit& cuP = *cu.cs->getCU( recalcPosition( cu.chromaFormat, CHANNEL_TYPE_LUMA, cu.chType, pos.offset( xoffset - uiNumPelsLuma, yoffset - uiNumPelsLuma ) ), cu.chType ); @@ -802,8 +1143,26 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass; } +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const unsigned cuPWidth = cuP.block(COMPONENT_Cb).width; + const unsigned cuPHeight = cuP.block(COMPONENT_Cb).height; + const unsigned cuQWidth = cuQ.block(COMPONENT_Cb).width; + const unsigned cuQHeight = cuQ.block(COMPONENT_Cb).height; + + bool largeBoundary = ((edgeDir == EDGE_VER && cuPWidth >= 8 && cuQWidth >= 8) || (edgeDir == EDGE_HOR && cuPHeight >= 8 && cuQHeight >= 8)); + + if (edgeDir == EDGE_HOR && pos.y % cuP.slice->getSPS()->getCTUSize() == 0) + { + largeBoundary = false; + } + +#endif for( int chromaIdx = 0; chromaIdx < 2; chromaIdx++ ) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if ((bS[chromaIdx] == 2) || (largeBoundary && (bS[chromaIdx] == 1))) + { +#endif const ClpRng& clpRng( cu.cs->slice->clpRng( ComponentID( chromaIdx + 1 )) ); const int chromaQPOffset = pps.getQpOffset( ComponentID( chromaIdx + 1 ) ); Pel* piTmpSrcChroma = (chromaIdx == 0) ? piTmpSrcCb : piTmpSrcCr; @@ -825,13 +1184,57 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed iQP = getScaledChromaQP(iQP, sps.getChromaFormatIdc()); } +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const int iIndexTC = Clip3<int>(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET * (bS[chromaIdx] - 1) + (tcOffsetDiv2 << 1)); +#else const int iIndexTC = Clip3<int>( 0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET*( ucBs - 1 ) + ( tcOffsetDiv2 << 1 ) ); +#endif const int iTc = sm_tcTable[iIndexTC] * iBitdepthScale; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + bool useLongFilter = false; + if (largeBoundary) + { + const int indexB = Clip3<int>(0, MAX_QP, iQP + (betaOffsetDiv2 << 1)); + const int beta = sm_betaTable[indexB] * iBitdepthScale; + + const int dp0 = xCalcDP(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 0), iOffset); + const int dq0 = xCalcDQ(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 0), iOffset); + const int dp1 = xCalcDP(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 1), iOffset); + const int dq1 = xCalcDQ(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 1), iOffset); + + const int d0 = dp0 + dq0; + const int d1 = dp1 + dq1; + const int d = d0 + d1; + + if (d < beta) + { + useLongFilter = true; + const bool sw = xUseStrongFiltering(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 0), iOffset, 2 * d0, beta, iTc) + && xUseStrongFiltering(piTmpSrcChroma + iSrcStep*(iIdx*uiLoopLength + 1), iOffset, 2 * d1, beta, iTc); + + for (unsigned step = 0; step < uiLoopLength; step++) + { + xPelFilterChroma(piTmpSrcChroma + iSrcStep*(step + iIdx*uiLoopLength), iOffset, iTc, sw, bPartPNoFilter, bPartQNoFilter, clpRng, largeBoundary); + } + } + } + if ( !useLongFilter ) + { + for (unsigned step = 0; step < uiLoopLength; step++) + { + xPelFilterChroma(piTmpSrcChroma + iSrcStep*(step + iIdx*uiLoopLength), iOffset, iTc, false, bPartPNoFilter, bPartQNoFilter, clpRng, largeBoundary); + } + } +#else for( unsigned uiStep = 0; uiStep < uiLoopLength; uiStep++ ) { xPelFilterChroma( piTmpSrcChroma + iSrcStep*( uiStep + iIdx*uiLoopLength ), iOffset, iTc, bPartPNoFilter, bPartQNoFilter, clpRng ); } +#endif +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + } +#endif } } } @@ -853,7 +1256,106 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed \param bFilterSecondQ decision weak filter/no filter for partQ \param bitDepthLuma luma bit depth */ +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +inline void LoopFilter::xBilinearFilter(Pel* srcP, Pel* srcQ, int offset, int refMiddle, int refP, int refQ, int numberPSide, int numberQSide, const int* dbCoeffsP, const int* dbCoeffsQ, int tc) const +{ + int src; + const char tc7[7] = { 6, 5, 4, 3, 2, 1, 1}; + const char tc3[3] = { 6, 4, 2 }; + const char *tcP = (numberPSide == 3) ? tc3 : tc7; + const char *tcQ = (numberQSide == 3) ? tc3 : tc7; + for (int pos = 0; pos < numberPSide; pos++) + { + src = srcP[-offset*pos]; + int cvalue = (tc * tcP[pos]) >>1; + srcP[-offset * pos] = Clip3(src - cvalue, src + cvalue, ((refMiddle*dbCoeffsP[pos] + refP * (64 - dbCoeffsP[pos]) + 32) >> 6)); + } + for (int pos = 0; pos < numberQSide; pos++) + { + src = srcQ[offset*pos]; + int cvalue = (tc * tcQ[pos]) >> 1; + srcQ[offset*pos] = Clip3(src - cvalue, src + cvalue, ((refMiddle*dbCoeffsQ[pos] + refQ * (64 - dbCoeffsQ[pos]) + 32) >> 6)); + } +} + +inline void LoopFilter::xFilteringPandQ(Pel* src, int offset, int numberPSide, int numberQSide, int tc) const +{ + CHECK(numberPSide <= 3 && numberQSide <= 3, "Short filtering in long filtering function"); + Pel* srcP = src-offset; + Pel* srcQ = src; + + int refP = 0; + int refQ = 0; + int refMiddle = 0; + + const int dbCoeffs7[7] = { 59, 50, 41,32,23,14,5 }; + const int dbCoeffs3[3] = { 53, 32, 11 }; + const int dbCoeffs5[5] = { 58, 45, 32,19,6}; + const int* dbCoeffsP = numberPSide == 7 ? dbCoeffs7 : (numberPSide==5) ? dbCoeffs5 : dbCoeffs3; + const int* dbCoeffsQ = numberQSide == 7 ? dbCoeffs7 : (numberQSide==5) ? dbCoeffs5 : dbCoeffs3; + + switch (numberPSide) + { + case 7: refP = (srcP[-6*offset] + srcP[-7 * offset] + 1) >> 1; break; + case 3: refP = (srcP[-2 * offset] + srcP[-3 * offset] + 1) >> 1; break; + case 5: refP = (srcP[-4 * offset] + srcP[-5 * offset] + 1) >> 1; break; + } + + switch (numberQSide) + { + case 7: refQ = (srcQ[6 * offset] + srcQ[7 * offset] + 1) >> 1; break; + case 3: refQ = (srcQ[2 * offset] + srcQ[3 * offset] + 1) >> 1; break; + case 5: refQ = (srcQ[4 * offset] + srcQ[5 * offset] + 1) >> 1; break; + } + + if (numberPSide == numberQSide) + { + if (numberPSide == 5) + { + refMiddle = (2 * (srcP[0] + srcQ[0] + srcP[-offset] + srcQ[offset] + srcP[-2 * offset] + srcQ[2 * offset]) + srcP[-3 * offset] + srcQ[3 * offset] + srcP[-4 * offset] + srcQ[4 * offset] + 8) >> 4; + } + else + { + refMiddle = (2 * (srcP[0] + srcQ[0]) + srcP[-offset] + srcQ[offset] + srcP[-2 * offset] + srcQ[2 * offset] + srcP[-3 * offset] + srcQ[3 * offset] + srcP[-4 * offset] + srcQ[4 * offset] + srcP[-5 * offset] + srcQ[5 * offset] + +srcP[-6 * offset] + srcQ[6 * offset] + 8) >> 4; + } + } + else + { + Pel* srcPt = srcP; + Pel* srcQt = srcQ; + int offsetP = -offset; + int offsetQ = offset; + + int newNumberQSide = numberQSide; + int newNumberPSide = numberPSide; + if (numberQSide > numberPSide) + { + std::swap(srcPt, srcQt); + std::swap(offsetP, offsetQ); + newNumberQSide = numberPSide; + newNumberPSide = numberQSide; + } + + if (newNumberPSide == 7 && newNumberQSide == 5) + { + refMiddle = (2 * (srcP[0] + srcQ[0] + srcP[-offset] + srcQ[offset]) + srcP[-2 * offset] + srcQ[2 * offset] + srcP[-3 * offset] + srcQ[3 * offset] + srcP[-4 * offset] + srcQ[4 * offset] + srcP[-5 * offset] + srcQ[5 * offset] + 8) >> 4; + } + else if (newNumberPSide == 7 && newNumberQSide == 3) + { + refMiddle = (2 * (srcPt[0] + srcQt[0]) + srcQt[0] + 2 * (srcQt[offsetQ] + srcQt[2 * offsetQ]) + srcPt[offsetP] + srcQt[offsetQ] + srcPt[2 * offsetP] + srcPt[3 * offsetP] + srcPt[4 * offsetP] + srcPt[5 * offsetP] + srcPt[6 * offsetP] + 8) >> 4; + } + else //if (newNumberPSide == 5 && newNumberQSide == 3) + { + refMiddle = (srcP[0] + srcQ[0] + srcP[-offset] + srcQ[offset] + srcP[-2 * offset] + srcQ[2 * offset] + srcP[-3 * offset] + srcQ[3 * offset] + 4) >> 3; + } + } + xBilinearFilter(srcP,srcQ,offset,refMiddle,refP,refQ,numberPSide,numberQSide,dbCoeffsP,dbCoeffsQ,tc); +} + +inline void LoopFilter::xPelFilterLuma(Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng, bool sidePisLarge, bool sideQisLarge, int maxFilterLengthP, int maxFilterLengthQ) const +#else inline void LoopFilter::xPelFilterLuma( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng ) const +#endif { int delta; @@ -866,14 +1368,39 @@ inline void LoopFilter::xPelFilterLuma( Pel* piSrc, const int iOffset, const int const Pel m7 = piSrc[ iOffset * 3]; const Pel m0 = piSrc[-iOffset * 4]; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const Pel mP1 = piSrc[-iOffset * 5]; + const Pel mP2 = piSrc[-iOffset * 6]; + const Pel mP3 = piSrc[-iOffset * 7]; + const Pel m8 = piSrc[ iOffset * 4]; + const Pel m9 = piSrc[ iOffset * 5]; + const Pel m10 = piSrc[ iOffset * 6]; + const char tc3[3] = { 3, 2, 1}; +#endif if (sw) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (sidePisLarge || sideQisLarge) + { + xFilteringPandQ(piSrc, iOffset, sidePisLarge ? maxFilterLengthP : 3, sideQisLarge ? maxFilterLengthQ : 3, tc); + } + else + { + piSrc[-iOffset] = Clip3(m3 - tc3[0] * tc, m3 + tc3[0] * tc, ((m1 + 2 * m2 + 2 * m3 + 2 * m4 + m5 + 4) >> 3)); + piSrc[0] = Clip3(m4 - tc3[0] * tc, m4 + tc3[0] * tc, ((m2 + 2 * m3 + 2 * m4 + 2 * m5 + m6 + 4) >> 3)); + piSrc[-iOffset * 2] = Clip3(m2 - tc3[1] * tc, m2 + tc3[1] * tc, ((m1 + m2 + m3 + m4 + 2) >> 2)); + piSrc[iOffset] = Clip3(m5 - tc3[1] * tc, m5 + tc3[1] * tc, ((m3 + m4 + m5 + m6 + 2) >> 2)); + piSrc[-iOffset * 3] = Clip3(m1 - tc3[2] * tc, m1 + tc3[2] * tc, ((2 * m0 + 3 * m1 + m2 + m3 + m4 + 4) >> 3)); + piSrc[iOffset * 2] = Clip3(m6 - tc3[2] * tc, m6 + tc3[2] * tc, ((m3 + m4 + m5 + 3 * m6 + 2 * m7 + 4) >> 3)); + } +#else piSrc[-iOffset] = Clip3( m3 - 2 * tc, m3 + 2 * tc, ( ( m1 + 2 * m2 + 2 * m3 + 2 * m4 + m5 + 4 ) >> 3 ) ); piSrc[ 0] = Clip3( m4 - 2 * tc, m4 + 2 * tc, ( ( m2 + 2 * m3 + 2 * m4 + 2 * m5 + m6 + 4 ) >> 3 ) ); piSrc[-iOffset * 2] = Clip3( m2 - 2 * tc, m2 + 2 * tc, ( ( m1 + m2 + m3 + m4 + 2 ) >> 2 ) ); piSrc[ iOffset] = Clip3( m5 - 2 * tc, m5 + 2 * tc, ( ( m3 + m4 + m5 + m6 + 2 ) >> 2 ) ); piSrc[-iOffset * 3] = Clip3( m1 - 2 * tc, m1 + 2 * tc, ( ( 2 * m0 + 3 * m1 + m2 + m3 + m4 + 4 ) >> 3 ) ); piSrc[ iOffset * 2] = Clip3( m6 - 2 * tc, m6 + 2 * tc, ( ( m3 + m4 + m5 + 3 * m6 + 2 * m7 + 4 ) >> 3 ) ); +#endif } else { @@ -905,6 +1432,15 @@ inline void LoopFilter::xPelFilterLuma( Pel* piSrc, const int iOffset, const int piSrc[-iOffset ] = m3; piSrc[-iOffset * 2] = m2; piSrc[-iOffset * 3] = m1; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (sidePisLarge) + { + piSrc[-iOffset * 4] = m0; + piSrc[-iOffset * 5] = mP1; + piSrc[-iOffset * 6] = mP2; + piSrc[-iOffset * 7] = mP3; + } +#endif } if(bPartQNoFilter) @@ -912,6 +1448,15 @@ inline void LoopFilter::xPelFilterLuma( Pel* piSrc, const int iOffset, const int piSrc[ 0 ] = m4; piSrc[ iOffset ] = m5; piSrc[ iOffset * 2] = m6; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (sideQisLarge) + { + piSrc[iOffset * 3] = m7; + piSrc[iOffset * 4] = m8; + piSrc[iOffset * 5] = m9; + piSrc[iOffset * 6] = m10; + } +#endif } } @@ -925,10 +1470,41 @@ inline void LoopFilter::xPelFilterLuma( Pel* piSrc, const int iOffset, const int \param bPartQNoFilter indicator to disable filtering on partQ \param bitDepthChroma chroma bit depth */ +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +inline void LoopFilter::xPelFilterChroma( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng, const bool largeBoundary ) const +#else inline void LoopFilter::xPelFilterChroma( Pel* piSrc, const int iOffset, const int tc, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng ) const +#endif { int delta; +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + const Pel m0 = piSrc[-iOffset * 4]; + const Pel m1 = piSrc[-iOffset * 3]; + const Pel m2 = piSrc[-iOffset * 2]; + const Pel m3 = piSrc[-iOffset]; + const Pel m4 = piSrc[0]; + const Pel m5 = piSrc[iOffset]; + const Pel m6 = piSrc[iOffset * 2]; + const Pel m7 = piSrc[iOffset * 3]; + + if (sw) + { + piSrc[-iOffset * 3] = Clip3(m1 - tc, m1 + tc, ((3 * m0 + 2 * m1 + m2 + m3 + m4 + 4) >> 3)); // p2 + piSrc[-iOffset * 2] = Clip3(m2 - tc, m2 + tc, ((2 * m0 + m1 + 2 * m2 + m3 + m4 + m5 + 4) >> 3)); // p1 + piSrc[-iOffset * 1] = Clip3(m3 - tc, m3 + tc, ((m0 + m1 + m2 + 2 * m3 + m4 + m5 + m6 + 4) >> 3)); // p0 + piSrc[0] = Clip3(m4 - tc, m4 + tc, ((m1 + m2 + m3 + 2 * m4 + m5 + m6 + m7 + 4) >> 3)); // q0 + piSrc[iOffset * 1] = Clip3(m5 - tc, m5 + tc, ((m2 + m3 + m4 + 2 * m5 + m6 + 2 * m7 + 4) >> 3)); // q1 + piSrc[iOffset * 2] = Clip3(m6 - tc, m6 + tc, ((m3 + m4 + m5 + 2 * m6 + 3 * m7 + 4) >> 3)); // q2 + } + else + { + delta = Clip3(-tc, tc, ((((m4 - m3) << 2) + m2 - m5 + 4) >> 3)); + piSrc[-iOffset] = ClipPel(m3 + delta, clpRng); + piSrc[0] = ClipPel(m4 - delta, clpRng); + } + +#else const Pel m4 = piSrc[ 0 ]; const Pel m3 = piSrc[-iOffset ]; const Pel m5 = piSrc[ iOffset ]; @@ -937,13 +1513,28 @@ inline void LoopFilter::xPelFilterChroma( Pel* piSrc, const int iOffset, const i delta = Clip3( -tc, tc, ( ( ( ( m4 - m3 ) << 2 ) + m2 - m5 + 4 ) >> 3 ) ); piSrc[-iOffset] = ClipPel( m3 + delta, clpRng ); piSrc[ 0 ] = ClipPel( m4 - delta, clpRng ); +#endif if( bPartPNoFilter ) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (largeBoundary) + { + piSrc[-iOffset * 3] = m1; // p2 + piSrc[-iOffset * 2] = m2; // p1 + } +#endif piSrc[-iOffset] = m3; } if( bPartQNoFilter ) { +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (largeBoundary) + { + piSrc[iOffset * 1] = m5; // q1 + piSrc[iOffset * 2] = m6; // q2 + } +#endif piSrc[ 0 ] = m4; } } @@ -957,15 +1548,58 @@ inline void LoopFilter::xPelFilterChroma( Pel* piSrc, const int iOffset, const i \param tc tc value \param piSrc pointer to picture data */ +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +inline bool LoopFilter::xUseStrongFiltering( Pel* piSrc, const int iOffset, const int d, const int beta, const int tc, bool sidePisLarge, bool sideQisLarge, int maxFilterLengthP, int maxFilterLengthQ ) const +#else inline bool LoopFilter::xUseStrongFiltering( Pel* piSrc, const int iOffset, const int d, const int beta, const int tc ) const +#endif { const Pel m4 = piSrc[ 0 ]; const Pel m3 = piSrc[-iOffset ]; const Pel m7 = piSrc[ iOffset * 3]; const Pel m0 = piSrc[-iOffset * 4]; - +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + int sp3 = abs(m0 - m3); + int sq3 = abs(m7 - m4); + const int d_strong = sp3 + sq3; +#else const int d_strong = abs( m0 - m3 ) + abs( m7 - m4 ); +#endif + +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + if (sidePisLarge || sideQisLarge) + { + Pel mP4; + Pel m11; + if (maxFilterLengthP == 5) + { + mP4 = piSrc[-iOffset * 6]; + } + else + { + mP4 = piSrc[-iOffset * 8]; + } + if (maxFilterLengthQ == 5) + { + m11 = piSrc[iOffset * 5]; + } + else + { + m11 = piSrc[iOffset * 7]; + } + if (sidePisLarge) + { + sp3 = (sp3 + abs(m0 - mP4) + 1) >> 1; + } + if (sideQisLarge) + { + sq3 = (sq3 + abs(m11 - m7) + 1) >> 1; + } + return ((sp3 + sq3) < (beta*3 >> 5)) && (d < (beta >> 2)) && (abs(m3 - m4) < ((tc * 5 + 1) >> 1)); + } + else +#endif return ( ( d_strong < ( beta >> 3 ) ) && ( d < ( beta >> 2 ) ) && ( abs( m3 - m4 ) < ( ( tc * 5 + 1 ) >> 1 ) ) ); } @@ -979,4 +1613,9 @@ inline int LoopFilter::xCalcDQ( Pel* piSrc, const int iOffset ) const return abs( piSrc[0] - 2 * piSrc[iOffset] + piSrc[iOffset * 2] ); } +#if JVET_M0471_LONG_DEBLOCKING_FILTERS +inline unsigned LoopFilter::BsSet(unsigned val, const ComponentID compIdx) const { return (val << (compIdx << 1)); } +inline unsigned LoopFilter::BsGet(unsigned val, const ComponentID compIdx) const { return ((val >> (compIdx << 1)) & 3); } +#endif + //! \} diff --git a/source/Lib/CommonLib/LoopFilter.h b/source/Lib/CommonLib/LoopFilter.h index 0f4a71379ff89a104c7824a6fffe82103ce16ed8..5f2b0bafb0a13b0e004bed96061e9e07790e7529 100644 --- a/source/Lib/CommonLib/LoopFilter.h +++ b/source/Lib/CommonLib/LoopFilter.h @@ -62,7 +62,7 @@ private: private: /// CU-level deblocking function void xDeblockCU ( CodingUnit& cu, const DeblockEdgeDir edgeDir ); - + // set / get functions void xSetLoopfilterParam ( const CodingUnit& cu ); @@ -75,17 +75,32 @@ private: const Area& area, const bool bValue, const bool EdgeIdx = false ); - +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + void xEdgeFilterLuma ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge, const int initialMaxFilterLengthP, const int initialMaxFilterLengthQ ); +#else void xEdgeFilterLuma ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge ); - void xEdgeFilterChroma ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge ); +#endif + void xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge); #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET void deriveLADFShift( const Pel* src, const int stride, int& shift, const DeblockEdgeDir edgeDir, const SPS sps ); #endif + +#if JVET_M0471_LONG_DEBLOCKING_FILTERS + inline void xBilinearFilter ( Pel* srcP, Pel* srcQ, int offset, int refMiddle, int refP, int refQ, int numberPSide, int numberQSide, const int* dbCoeffsP, const int* dbCoeffsQ, int tc ) const; + inline void xFilteringPandQ ( Pel* src, int offset, int numberPSide, int numberQSide, int tc ) const; + inline void xPelFilterLuma ( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng, bool sidePisLarge = false, bool sideQisLarge = false, int maxFilterLengthP = 7, int maxFilterLengthQ = 7 ) const; + inline void xPelFilterChroma ( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng, const bool largeBoundary ) const; + inline bool xUseStrongFiltering ( Pel* piSrc, const int iOffset, const int d, const int beta, const int tc, bool sidePisLarge = false, bool sideQisLarge = false, int maxFilterLengthP = 7, int maxFilterLengthQ = 7 ) const;//move the computation outside the function + inline unsigned BsSet(unsigned val, const ComponentID compIdx) const; + inline unsigned BsGet(unsigned val, const ComponentID compIdx) const; +#else inline void xPelFilterLuma ( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng ) const; inline void xPelFilterChroma ( Pel* piSrc, const int iOffset, const int tc, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng ) const; inline bool xUseStrongFiltering ( Pel* piSrc, const int iOffset, const int d, const int beta, const int tc ) const; +#endif + inline int xCalcDP ( Pel* piSrc, const int iOffset ) const; inline int xCalcDQ ( Pel* piSrc, const int iOffset ) const; static const uint8_t sm_tcTable[MAX_QP + 3]; diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h index 20788929749731d6f462f7a30cf56e456680c453..2bc0f935d5e2d8bf49adb725e4c51a4092a060d7 100644 --- a/source/Lib/CommonLib/MotionInfo.h +++ b/source/Lib/CommonLib/MotionInfo.h @@ -101,19 +101,49 @@ struct MvField struct MotionInfo { bool isInter; +#if JVET_M0483_IBC + bool isIBCmot; +#endif char interDir; uint16_t sliceIdx; - Mv mv [ NUM_REF_PIC_LIST_01 ]; int16_t refIdx [ NUM_REF_PIC_LIST_01 ]; +#if JVET_M0264_HMVP_WITH_GBIIDX + uint8_t GBiIdx; +#endif Mv bv; - MotionInfo() : isInter( false ), interDir( 0 ), sliceIdx( 0 ), refIdx{ NOT_VALID, NOT_VALID } { } +#if JVET_M0483_IBC +#if JVET_M0264_HMVP_WITH_GBIIDX + MotionInfo() : isInter(false), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ NOT_VALID, NOT_VALID }, GBiIdx(0) { } +#else + MotionInfo() : isInter(false), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ NOT_VALID, NOT_VALID } { } +#endif + // ensure that MotionInfo(0) produces '\x000....' bit pattern - needed to work with AreaBuf - don't use this constructor for anything else +#if JVET_M0264_HMVP_WITH_GBIIDX + MotionInfo(int i) : isInter(i != 0), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ 0, 0 }, GBiIdx(0) { CHECKD(i != 0, "The argument for this constructor has to be '0'"); } +#else + MotionInfo(int i) : isInter(i != 0), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ 0, 0 } { CHECKD(i != 0, "The argument for this constructor has to be '0'"); } +#endif +#else +#if JVET_M0264_HMVP_WITH_GBIIDX + MotionInfo() : isInter(false), interDir(0), sliceIdx(0), refIdx{ NOT_VALID, NOT_VALID }, GBiIdx(0) { } +#else + MotionInfo() : isInter(false), interDir( 0 ), sliceIdx( 0 ), refIdx{ NOT_VALID, NOT_VALID } { } +#endif // ensure that MotionInfo(0) produces '\x000....' bit pattern - needed to work with AreaBuf - don't use this constructor for anything else +#if JVET_M0264_HMVP_WITH_GBIIDX + MotionInfo(int i) : isInter(i != 0), interDir(0), sliceIdx(0), refIdx{ 0, 0 }, GBiIdx(0) { CHECKD(i != 0, "The argument for this constructor has to be '0'"); } +#else MotionInfo( int i ) : isInter( i != 0 ), interDir( 0 ), sliceIdx( 0 ), refIdx{ 0, 0 } { CHECKD( i != 0, "The argument for this constructor has to be '0'" ); } +#endif +#endif bool operator==( const MotionInfo& mi ) const { if( isInter != mi.isInter ) return false; +#if JVET_M0483_IBC + if (isIBCmot != mi.isIBCmot) return false; +#endif if( isInter ) { if( sliceIdx != mi.sliceIdx ) return false; @@ -150,6 +180,9 @@ class GBiMotionParam bool m_readOnlyAffine[2][2][33]; Mv m_mvAffine[2][2][33][3]; Distortion m_distAffine[2][2][33]; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int m_mvpIdx[2][2][33]; +#endif public: @@ -171,6 +204,9 @@ public: memset(m_dist, -1, 2 * 33 * sizeof(Distortion)); memset(m_readOnlyAffine, false, 2 * 2 * 33 * sizeof(bool)); memset(m_distAffine, -1, 2 * 2 * 33 * sizeof(Distortion)); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + memset( m_mvpIdx, 0, 2 * 2 * 33 * sizeof( int ) ); +#endif } void setReadMode(bool b, uint32_t uiRefList, uint32_t uiRefIdx) { m_readOnly[uiRefList][uiRefIdx] = b; } @@ -195,21 +231,38 @@ public: Mv& getAffineMv(uint32_t uiRefList, uint32_t uiRefIdx, uint32_t uiAffineMvIdx, int bP4) { return m_mvAffine[bP4][uiRefList][uiRefIdx][uiAffineMvIdx]; } - void copyAffineMvFrom(Mv(&racAffineMvs)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4) + void copyAffineMvFrom(Mv(&racAffineMvs)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4 +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , const int mvpIdx +#endif + ) { memcpy(m_mvAffine[bP4][uiRefList][uiRefIdx], racAffineMvs, 3 * sizeof(Mv)); m_distAffine[bP4][uiRefList][uiRefIdx] = uiDist; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_mvpIdx[bP4][uiRefList][uiRefIdx] = mvpIdx; +#endif } - void copyAffineMvTo(Mv acAffineMvs[3], Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4) + void copyAffineMvTo(Mv acAffineMvs[3], Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4 +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx +#endif + ) { memcpy(acAffineMvs, m_mvAffine[bP4][uiRefList][uiRefIdx], 3 * sizeof(Mv)); ruiDist = m_distAffine[bP4][uiRefList][uiRefIdx]; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + mvpIdx = m_mvpIdx[bP4][uiRefList][uiRefIdx]; +#endif } }; struct LutMotionCand { MotionInfo* motionCand; int currCnt; +#if JVET_M0483_IBC + int currCntIBC; +#endif }; #endif // __MOTIONINFO__ diff --git a/source/Lib/CommonLib/Mv.cpp b/source/Lib/CommonLib/Mv.cpp index 7edfa2c56903738f79ce174ae35d224d855d16b3..732e756b5ff21ed995286ef3344c52670bdc348a 100644 --- a/source/Lib/CommonLib/Mv.cpp +++ b/source/Lib/CommonLib/Mv.cpp @@ -65,7 +65,14 @@ void clipMv( Mv& rcMv, const Position& pos, { int iHorMax = ( sps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() - size.width + iOffset - ( int ) pos.x - 1 ) << iMvShift; int iHorMin = ( -( int ) sps.getMaxCUWidth() - iOffset - ( int ) pos.x + 1 ) << iMvShift; - rcMv.setHor( std::min( iHorMax, std::max( iHorMin, rcMv.getHor() ) ) ); + int mvX = rcMv.getHor(); + while( mvX > iHorMax ) { + mvX -= ( sps.getWrapAroundOffset() << iMvShift ); + } + while( mvX < iHorMin ) { + mvX += ( sps.getWrapAroundOffset() << iMvShift ); + } + rcMv.setHor( mvX ); rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) ); return; } diff --git a/source/Lib/CommonLib/Mv.h b/source/Lib/CommonLib/Mv.h index 56287bec0b64953893c6313ce5b7d1ae3349c595..c703fe6cb16446c4bdf596dcb89e1ea0d6c79418 100644 --- a/source/Lib/CommonLib/Mv.h +++ b/source/Lib/CommonLib/Mv.h @@ -51,6 +51,9 @@ enum MvPrecision { MV_PRECISION_4PEL = 0, // 4-pel MV_PRECISION_INT = 2, // 1-pel, shift 2 bits from 4-pel +#if JVET_M0246_AFFINE_AMVR + MV_PRECISION_HALF = 3, // 1/2-pel +#endif MV_PRECISION_QUARTER = 4, // 1/4-pel (the precision of regular MV difference signaling), shift 4 bits from 4-pel MV_PRECISION_INTERNAL = 6, // 1/16-pel (the precision of internal MV), shift 6 bits from 4-pel }; @@ -213,6 +216,14 @@ public: return Mv(tarMvPred.hor - hor + curMvPred.hor, tarMvPred.ver - ver + curMvPred.ver); } #endif + +#if JVET_M0145_AFFINE_MV_CLIP + void clipToStorageBitDepth() + { + hor = Clip3( -(1 << 17), (1 << 17) - 1, hor ); + ver = Clip3( -(1 << 17), (1 << 17) - 1, ver ); + } +#endif };// END CLASS DEFINITION MV namespace std @@ -226,7 +237,7 @@ namespace std } }; }; -void clipMv ( Mv& rcMv, const struct Position& pos, +void clipMv ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps ); diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 4c96307cb2196d52f9886c1189987f91d09c69c8..2b8f46593b255789956d72dac002c75ba4d659a0 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -742,11 +742,17 @@ void Picture::create(const ChromaFormat &_chromaFormat, const Size &size, const if( !_decoder ) { M_BUFS( 0, PIC_ORIGINAL ). create( _chromaFormat, a ); +#if JVET_M0427_INLOOP_RESHAPER + M_BUFS( 0, PIC_TRUE_ORIGINAL ). create( _chromaFormat, a ); +#endif } #if !KEEP_PRED_AND_RESI_SIGNALS m_ctuArea = UnitArea( _chromaFormat, Area( Position{ 0, 0 }, Size( _maxCUSize, _maxCUSize ) ) ); #endif +#if JVET_M0253_HASH_ME + m_hashMap.clearAll(); +#endif } void Picture::destroy() @@ -762,7 +768,9 @@ void Picture::destroy() { M_BUFS( jId, t ).destroy(); } - +#if JVET_M0253_HASH_ME + m_hashMap.clearAll(); +#endif if( cs ) { cs->destroy(); @@ -846,6 +854,14 @@ const CPelUnitBuf Picture::getOrigBuf(const UnitArea &unit) const { return getBu PelUnitBuf Picture::getOrigBuf() { return M_BUFS(0, PIC_ORIGINAL); } const CPelUnitBuf Picture::getOrigBuf() const { return M_BUFS(0, PIC_ORIGINAL); } +#if JVET_M0427_INLOOP_RESHAPER + PelBuf Picture::getOrigBuf(const ComponentID compID) { return getBuf(compID, PIC_ORIGINAL); } +const CPelBuf Picture::getOrigBuf(const ComponentID compID) const { return getBuf(compID, PIC_ORIGINAL); } + PelUnitBuf Picture::getTrueOrigBuf() { return M_BUFS(0, PIC_TRUE_ORIGINAL); } +const CPelUnitBuf Picture::getTrueOrigBuf() const { return M_BUFS(0, PIC_TRUE_ORIGINAL); } + PelBuf Picture::getTrueOrigBuf(const CompArea &blk) { return getBuf(blk, PIC_TRUE_ORIGINAL); } +const CPelBuf Picture::getTrueOrigBuf(const CompArea &blk) const { return getBuf(blk, PIC_TRUE_ORIGINAL); } +#endif PelBuf Picture::getPredBuf(const CompArea &blk) { return getBuf(blk, PIC_PREDICTION); } const CPelBuf Picture::getPredBuf(const CompArea &blk) const { return getBuf(blk, PIC_PREDICTION); } PelUnitBuf Picture::getPredBuf(const UnitArea &unit) { return getBuf(unit, PIC_PREDICTION); } @@ -1011,7 +1027,7 @@ void Picture::extendPicBorder() { for (int x = 0; x < xmargin; x++ ) { - pi[ -xmargin + x ] = pi[ -xmargin + x + xoffset ]; + pi[ -x - 1 ] = pi[ -x - 1 + xoffset ]; pi[ p.width + x ] = pi[ p.width + x - xoffset ]; } pi += p.stride; @@ -1162,3 +1178,64 @@ bool Picture::getSpliceFull() return false; return true; } + +#if JVET_M0253_HASH_ME +void Picture::addPictureToHashMapForInter() +{ + int picWidth = slices[0]->getSPS()->getPicWidthInLumaSamples(); + int picHeight = slices[0]->getSPS()->getPicHeightInLumaSamples(); + uint32_t* blockHashValues[2][2]; + bool* bIsBlockSame[2][3]; + + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + blockHashValues[i][j] = new uint32_t[picWidth*picHeight]; + } + + for (int j = 0; j < 3; j++) + { + bIsBlockSame[i][j] = new bool[picWidth*picHeight]; + } + } + + m_hashMap.create(); + m_hashMap.generateBlock2x2HashValue(getOrigBuf(), picWidth, picHeight, slices[0]->getSPS()->getBitDepths(), blockHashValues[0], bIsBlockSame[0]);//2x2 + m_hashMap.generateBlockHashValue(picWidth, picHeight, 4, 4, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//4x4 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 4, 4); + + m_hashMap.generateRectangleHashValue(picWidth, picHeight, 8, 4, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//8x4 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 8, 4); + + m_hashMap.generateRectangleHashValue(picWidth, picHeight, 4, 8, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//4x8 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 4, 8); + + m_hashMap.generateBlockHashValue(picWidth, picHeight, 8, 8, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//8x8 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 8, 8); + + m_hashMap.generateBlockHashValue(picWidth, picHeight, 16, 16, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//16x16 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 16, 16); + + m_hashMap.generateBlockHashValue(picWidth, picHeight, 32, 32, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//32x32 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 32, 32); + + m_hashMap.generateBlockHashValue(picWidth, picHeight, 64, 64, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//64x64 + m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 64, 64); + + m_hashMap.setInitial(); + + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + delete[] blockHashValues[i][j]; + } + + for (int j = 0; j < 3; j++) + { + delete[] bIsBlockSame[i][j]; + } + } +} +#endif diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 55756cdbed31462ec6fae7c98e966efb9c0b34b1..d939de1ac90e6847606f4c733dcfaba38e3cd3fc 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -46,7 +46,9 @@ #include "Unit.h" #include "Slice.h" #include "CodingStructure.h" - +#if JVET_M0253_HASH_ME +#include "Hash.h" +#endif #include <deque> #if ENABLE_WPP_PARALLELISM || ENABLE_SPLIT_PARALLELISM @@ -192,6 +194,14 @@ struct Picture : public UnitArea const CPelUnitBuf getOrigBuf(const UnitArea &unit) const; PelUnitBuf getOrigBuf(); const CPelUnitBuf getOrigBuf() const; +#if JVET_M0427_INLOOP_RESHAPER + PelBuf getOrigBuf(const ComponentID compID); + const CPelBuf getOrigBuf(const ComponentID compID) const; + PelUnitBuf getTrueOrigBuf(); + const CPelUnitBuf getTrueOrigBuf() const; + PelBuf getTrueOrigBuf(const CompArea &blk); + const CPelBuf getTrueOrigBuf(const CompArea &blk) const; +#endif PelBuf getPredBuf(const CompArea &blk); const CPelBuf getPredBuf(const CompArea &blk) const; @@ -259,6 +269,13 @@ public: PelStorage m_bufs[NUM_PIC_TYPES]; #endif +#if JVET_M0253_HASH_ME + TComHash m_hashMap; + TComHash* getHashMap() { return &m_hashMap; } + const TComHash* getHashMap() const { return &m_hashMap; } + void addPictureToHashMapForInter(); +#endif + CodingStructure* cs; std::deque<Slice*> slices; SEIMessages SEIs; diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index ca477139b28c97e7342b3cae0b7c14d1494355ac..5829874da0427ff5d161ab7062b18d7b193aeabb 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -313,8 +313,13 @@ void Quant::dequant(const TransformUnit &tu, const int QP_rem = cQP.rem; #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + const bool needsScalingCorrection = TU::needsBlockSizeTrafoScale( tu, compID ); + const int NEScale = TU::needsSqrt2Scale( tu, compID ) ? 181 : 1; +#else const bool needsScalingCorrection = TU::needsBlockSizeTrafoScale( tu.block( compID ) ); const int NEScale = TU::needsSqrt2Scale( tu.blocks[compID] ) ? 181 : 1; +#endif #if HEVC_USE_SCALING_LISTS const int rightShift = (needsScalingCorrection ? 8 : 0 ) + (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0); #else @@ -767,7 +772,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf int iWHScale = 1; #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + if( TU::needsBlockSizeTrafoScale( tu, compID ) ) +#else if( TU::needsBlockSizeTrafoScale( rect ) ) +#endif { iTransformShift += ADJ_QUANT_SHIFT; iWHScale = 181; @@ -863,7 +872,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff int iWHScale = 1; #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + if( TU::needsBlockSizeTrafoScale( tu, compID ) ) +#else if( TU::needsBlockSizeTrafoScale( rect ) ) +#endif { iTransformShift += ADJ_QUANT_SHIFT; iWHScale = 181; diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index bcf25fe5fd2006cf085f2430ca6b3add0080e613..2682f558a107fa6ee7aa9a3f62208548c35a9521 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -149,7 +149,12 @@ inline uint32_t QuantRDOQ::xGetCodedLevel( double& rd64CodedCost, for( int uiAbsLevel = uiMaxAbsLevel; uiAbsLevel >= uiMinAbsLevel ; uiAbsLevel-- ) { double dErr = double( lLevelDouble - ( Intermediate_Int(uiAbsLevel) << iQBits ) ); + +#if JVET_M0470 + double dCurrCost = dErr * dErr * errorScale + xGetICost( xGetICRate( uiAbsLevel, fracBitsPar, fracBitsGt1, fracBitsGt2, remGt2Bins, remRegBins, goRiceZero, ui16AbsGoRice, true, maxLog2TrDynamicRange ) ); +#else double dCurrCost = dErr * dErr * errorScale + xGetICost( xGetICRate( uiAbsLevel, fracBitsPar, fracBitsGt1, fracBitsGt2, remGt2Bins, remRegBins, goRiceZero, ui16AbsGoRice, useLimitedPrefixLength, maxLog2TrDynamicRange ) ); +#endif dCurrCost += dCurrCostSig; if( dCurrCost < rd64CodedCost ) @@ -194,7 +199,11 @@ inline int QuantRDOQ::xGetICRate( const uint32_t uiAbsLevel, int iRate = int( xGetIEPRate() ); // cost of sign bit uint32_t symbol = ( uiAbsLevel == 0 ? goRiceZero : uiAbsLevel <= goRiceZero ? uiAbsLevel-1 : uiAbsLevel ); uint32_t length; +#if JVET_M0470 + const int threshold = COEF_REMAIN_BIN_REDUCTION; +#else const int threshold = g_auiGoRiceRange[ui16AbsGoRice]; +#endif if( symbol < ( threshold << ui16AbsGoRice ) ) { length = symbol >> ui16AbsGoRice; @@ -239,7 +248,11 @@ inline int QuantRDOQ::xGetICRate( const uint32_t uiAbsLevel, { uint32_t symbol = ( uiAbsLevel - cthres ) >> 1; uint32_t length; +#if JVET_M0470 + const int threshold = COEF_REMAIN_BIN_REDUCTION; +#else const int threshold = g_auiGoRiceRange[ui16AbsGoRice]; +#endif if( symbol < ( threshold << ui16AbsGoRice ) ) { length = symbol >> ui16AbsGoRice; @@ -395,15 +408,21 @@ void QuantRDOQ::setScalingList(ScalingList *scalingList, const int maxLog2TrDyna #endif #else +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT +double QuantRDOQ::xGetErrScaleCoeff( const bool needsSqrt2, SizeType width, SizeType height, int qp, const int maxLog2TrDynamicRange, const int channelBitDepth ) +#else double QuantRDOQ::xGetErrScaleCoeff( SizeType width, SizeType height, int qp, const int maxLog2TrDynamicRange, const int channelBitDepth ) +#endif { const int iTransformShift = getTransformShift(channelBitDepth, Size(width, height), maxLog2TrDynamicRange); #if HM_QTBT_AS_IN_JEM_QUANT double dErrScale = (double)( 1 << SCALE_BITS ); // Compensate for scaling of bitcount in Lagrange cost function - bool needsSrqt2 = TU::needsBlockSizeTrafoScale( Size(width, height) );// ( ( (sizeX+sizeY) & 1 ) !=0 ); - double dTransShift = (double)iTransformShift + ( needsSrqt2 ? -0.5 : 0.0 ); +#if !JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + bool needsSqrt2 = TU::needsBlockSizeTrafoScale( Size(width, height) );// ( ( (sizeX+sizeY) & 1 ) !=0 ); +#endif + double dTransShift = (double)iTransformShift + ( needsSqrt2 ? -0.5 : 0.0 ); dErrScale = dErrScale*pow( 2.0, ( -2.0*dTransShift ) ); // Compensate for scaling through forward transform - int QStep = ( needsSrqt2 ? ( ( g_quantScales[qp] * 181 ) >> 7 ) : g_quantScales[qp] ); + int QStep = ( needsSqrt2 ? ( ( g_quantScales[qp] * 181 ) >> 7 ) : g_quantScales[qp] ); double finalErrScale = dErrScale / QStep / QStep / (1 << (DISTORTION_PRECISION_ADJUSTMENT(channelBitDepth) << 1)); #else int errShift = SCALE_BITS - ((iTransformShift + DISTORTION_PRECISION_ADJUSTMENT(channelBitDepth)) << 1); @@ -441,8 +460,8 @@ void QuantRDOQ::xSetErrScaleCoeff( uint32_t list, uint32_t sizeX, uint32_t sizeY #if HM_QTBT_AS_IN_JEM_QUANT double dErrScale = (double)( 1 << SCALE_BITS ); // Compensate for scaling of bitcount in Lagrange cost function - bool needsSrqt2 = TU::needsBlockSizeTrafoScale( Size( g_scalingListSizeX[sizeX], g_scalingListSizeX[sizeY] ) );// ( ( (sizeX+sizeY) & 1 ) !=0 ); - double dTransShift = (double)iTransformShift + ( needsSrqt2 ? -0.5 : 0.0 ); + bool needsSqrt2 = TU::needsBlockSizeTrafoScale( Size( g_scalingListSizeX[sizeX], g_scalingListSizeX[sizeY] ) );// ( ( (sizeX+sizeY) & 1 ) !=0 ); + double dTransShift = (double)iTransformShift + ( needsSqrt2 ? -0.5 : 0.0 ); dErrScale = dErrScale*pow( 2.0, ( -2.0*dTransShift ) ); // Compensate for scaling through forward transform for( i = 0; i < uiMaxNumCoeff; i++ ) @@ -451,7 +470,7 @@ void QuantRDOQ::xSetErrScaleCoeff( uint32_t list, uint32_t sizeX, uint32_t sizeY / (1 << (DISTORTION_PRECISION_ADJUSTMENT(bitDepths.recon[channelType]) << 1)); } - int QStep = ( needsSrqt2 ? ( ( g_quantScales[qp] * 181 ) >> 7 ) : g_quantScales[qp] ); + int QStep = ( needsSqrt2 ? ( ( g_quantScales[qp] * 181 ) >> 7 ) : g_quantScales[qp] ); xGetErrScaleCoeffNoScalingList(list, sizeX, sizeY, qp) = dErrScale / QStep / QStep / (1 << (DISTORTION_PRECISION_ADJUSTMENT(bitDepths.recon[channelType]) << 1)); @@ -562,6 +581,9 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->ispMode || !isLuma(compID) ) +#endif { useRDOQ &= uiWidth > 2; useRDOQ &= uiHeight > 2; @@ -605,6 +627,9 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, const bool extendedPrecision = sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(chType); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useIntraSubPartitions = tu.cu->ispMode && isLuma(compID); +#endif /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller) @@ -669,8 +694,13 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, const bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, tu.transformSkip[compID]); #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + const int defaultQuantisationCoefficient = ( TU::needsSqrt2Scale( rect, tu.transformSkip[compID] ) ? ( g_quantScales[cQP.rem] * 181 ) >> 7 : g_quantScales[cQP.rem] ); + const double defaultErrorScale = xGetErrScaleCoeffNoScalingList(scalingListType, (uiLog2BlockWidth-1), (uiLog2BlockHeight-1), cQP.rem); +#else const int defaultQuantisationCoefficient = ( TU::needsSqrt2Scale( rect ) ? ( g_quantScales[cQP.rem] * 181 ) >> 7 : g_quantScales[cQP.rem] ); const double defaultErrorScale = xGetErrScaleCoeffNoScalingList(scalingListType, (uiLog2BlockWidth-1), (uiLog2BlockHeight-1), cQP.rem); +#endif #else const double blkErrScale = ( TU::needsQP3Offset( tu, compID ) ? 2.0 : 1.0 ); const int defaultQuantisationCoefficient = g_quantScales[cQP.rem]; @@ -678,8 +708,13 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, #endif #else //HEVC_USE_SCALING_LISTS #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + const int quantisationCoefficient = ( TU::needsSqrt2Scale( tu, compID ) ? ( g_quantScales[cQP.rem] * 181 ) >> 7 : g_quantScales[cQP.rem] ); + const double errorScale = xGetErrScaleCoeff( TU::needsSqrt2Scale( tu, compID ), uiWidth, uiHeight, cQP.rem, maxLog2TrDynamicRange, channelBitDepth ); +#else const int quantisationCoefficient = ( TU::needsSqrt2Scale( rect ) ? ( g_quantScales[cQP.rem] * 181 ) >> 7 : g_quantScales[cQP.rem] ); const double errorScale = xGetErrScaleCoeff( uiWidth, uiHeight, cQP.rem, maxLog2TrDynamicRange, channelBitDepth ); +#endif #else const double blkErrScale = ( TU::needsQP3Offset( tu, compID ) ? 2.0 : 1.0 ); const int quantisationCoefficient = g_quantScales[cQP.rem]; @@ -715,8 +750,11 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, double *pdCostCoeffGroupSig = m_pdCostCoeffGroupSig; memset( pdCostCoeffGroupSig, 0, ( uiMaxNumCoeff >> cctx.log2CGSize() ) * sizeof( double ) ); - +#if JVET_M0257 + const int iCGNum = std::min<int>(JVET_C0024_ZERO_OUT_TH, uiWidth) * std::min<int>(JVET_C0024_ZERO_OUT_TH, uiHeight) >> cctx.log2CGSize(); +#else const int iCGNum = uiWidth * uiHeight >> cctx.log2CGSize(); +#endif int iScanPos; coeffGroupRDStats rdStats; @@ -998,10 +1036,49 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = tu.cbf[COMPONENT_Cb]; + bool lastCbfIsInferred = false; + if( useIntraSubPartitions ) + { + bool rootCbfSoFar = false; + bool isLastSubPartition = CU::isISPLast(*tu.cu, tu.Y(), compID); + uint32_t nTus = tu.cu->ispMode == HOR_INTRA_SUBPARTITIONS ? tu.cu->lheight() >> g_aucLog2[tu.lheight()] : tu.cu->lwidth() >> g_aucLog2[tu.lwidth()]; + if( isLastSubPartition ) + { + TransformUnit* tuPointer = tu.cu->firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth(*tuPointer, COMPONENT_Y, tu.depth); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth(tu, compID, tu.depth); + } + } + BinFracBits fracBitsQtCbf = fracBits.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( rect.compID, tu.depth, previousCbf, useIntraSubPartitions ) ) ); + + if( !lastCbfIsInferred ) + { + d64BestCost = d64BlockUncodedCost + xGetICost(fracBitsQtCbf.intBits[0]); + d64BaseCost += xGetICost(fracBitsQtCbf.intBits[1]); + } + else + { + d64BestCost = d64BlockUncodedCost; + } +#else BinFracBits fracBitsQtCbf = fracBits.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( rect.compID, tu.depth, tu.cbf[COMPONENT_Cb] ) ) ); d64BestCost = d64BlockUncodedCost + xGetICost( fracBitsQtCbf.intBits[0] ); d64BaseCost += xGetICost( fracBitsQtCbf.intBits[1] ); +#endif } int lastBitsX[LAST_SIGNIFICANT_GROUPS] = { 0 }; @@ -1010,9 +1087,14 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, #if HEVC_USE_MDCS int dim1 = ( cctx.scanType() == SCAN_VER ? uiHeight : uiWidth ); int dim2 = ( cctx.scanType() == SCAN_VER ? uiWidth : uiHeight ); +#else +#if JVET_M0257 + int dim1 = std::min<int>(JVET_C0024_ZERO_OUT_TH, uiWidth); + int dim2 = std::min<int>(JVET_C0024_ZERO_OUT_TH, uiHeight); #else int dim1 = uiWidth; int dim2 = uiHeight; +#endif #endif int bitsX = 0; int bitsY = 0; @@ -1123,8 +1205,11 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, int lastCG = -1; int absSum = 0 ; int n ; - +#if JVET_M0257 + for (int subSet = iCGNum - 1; subSet >= 0; subSet--) +#else for( int subSet = (uiWidth*uiHeight-1) >> cctx.log2CGSize(); subSet >= 0; subSet-- ) +#endif { int subPos = subSet << cctx.log2CGSize(); int firstNZPosInCG = iCGSizeM1 + 1, lastNZPosInCG = -1; diff --git a/source/Lib/CommonLib/QuantRDOQ.h b/source/Lib/CommonLib/QuantRDOQ.h index c29ab0eca4792cd0bd3c13723977a52eb201a6b1..037fab4d7d5ec44646ebca62be1b018f5bef5bb0 100644 --- a/source/Lib/CommonLib/QuantRDOQ.h +++ b/source/Lib/CommonLib/QuantRDOQ.h @@ -75,8 +75,12 @@ private: void xInitScalingList ( const QuantRDOQ* other ); void xDestroyScalingList (); void xSetErrScaleCoeff ( uint32_t list, uint32_t sizeX, uint32_t sizeY, int qp, const int maxLog2TrDynamicRange[MAX_NUM_CHANNEL_TYPE], const BitDepths &bitDepths ); +#else +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + double xGetErrScaleCoeff ( const bool needsSqrt2, SizeType width, SizeType height, int qp, const int maxLog2TrDynamicRange, const int channelBitDepth); #else double xGetErrScaleCoeff ( SizeType width, SizeType height, int qp, const int maxLog2TrDynamicRange, const int channelBitDepth); +#endif #endif // RDOQ functions diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp index 78fbcf0f3d0550abd734db1e1347cdc3a14e8b4d..8bbf4b992a25e657ddc653132bee431cfeb63b42 100644 --- a/source/Lib/CommonLib/RdCost.cpp +++ b/source/Lib/CommonLib/RdCost.cpp @@ -152,7 +152,7 @@ void RdCost::init() m_afpDistortFunc[DF_SAD_FULL_NBIT32 ] = RdCost::xGetSAD_full; m_afpDistortFunc[DF_SAD_FULL_NBIT64 ] = RdCost::xGetSAD_full; m_afpDistortFunc[DF_SAD_FULL_NBIT16N] = RdCost::xGetSAD_full; - + #if WCG_EXT m_afpDistortFunc[DF_SSE_WTD ] = RdCost::xGetSSE_WTD; m_afpDistortFunc[DF_SSE2_WTD ] = RdCost::xGetSSE2_WTD; @@ -176,6 +176,11 @@ void RdCost::init() m_motionLambda = 0; m_iCostScale = 0; +#if JVET_M0427_INLOOP_RESHAPER + m_signalType = RESHAPE_SIGNAL_NULL; + m_chromaWeight = 1.0; + m_lumaBD = 10; +#endif } @@ -331,12 +336,16 @@ void RdCost::setDistParam( DistParam &rcDP, const Pel* pOrg, const Pel* piRefY, rcDP.cur.stride = iRefStride; rcDP.cur.width = width; rcDP.cur.height = height; - +#if JVET_M0147_DMVR + rcDP.subShift = subShiftMode; +#endif rcDP.step = step; rcDP.maximumDistortionForEarlyExit = std::numeric_limits<Distortion>::max(); - +#if JVET_M0147_DMVR + CHECK( useHadamard || rcDP.useMR, "only used in xDMVRCost with these default parameters (so far...)" ); +#else CHECK( useHadamard || rcDP.useMR || subShiftMode > 0, "only used in xDirectMCCost with these default parameters (so far...)" ); - +#endif if ( bioApplied ) { rcDP.distFunc = m_afpDistortFunc[ DF_SAD_INTERMEDIATE_BITDEPTH ]; @@ -2858,7 +2867,15 @@ Distortion RdCost::xGetHADs( const DistParam &rcDtParam ) #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER +uint32_t RdCost::m_signalType; +double RdCost::m_chromaWeight; +int RdCost::m_lumaBD; +std::vector<double> RdCost::m_reshapeLumaLevelToWeightPLUT; +std::vector<double> RdCost::m_lumaLevelToWeightPLUT; +#else double RdCost::m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +#endif void RdCost::saveUnadjustedLambda() { @@ -2883,15 +2900,97 @@ void RdCost::initLumaLevelToWeightTable() else */ { // set SDR weight table - y = 0.015*x - 1.5 - 6; // this is the Equation used to derive the luma qp LUT for HDR in MPEG HDR anchor3.2 (JCTCX-X1020) + y = 0.015*x - 1.5 - 6; // this is the Equation used to derive the luma qp LUT for HDR in MPEG HDR anchor3.2 (JCTCX-X1020) y = y<-3 ? -3 : (y>6 ? 6 : y); } - - m_lumaLevelToWeightPLUT[i] = pow(2.0, y / 3.0); // or power(10, dQp/10) they are almost equal + + m_lumaLevelToWeightPLUT[i] = pow(2.0, y / 3.0); // or power(10, dQp/10) they are almost equal + } +} + +#if JVET_M0427_INLOOP_RESHAPER +void RdCost::initLumaLevelToWeightTableReshape() +{ + int lutSize = 1 << m_lumaBD; + if (m_reshapeLumaLevelToWeightPLUT.empty()) + m_reshapeLumaLevelToWeightPLUT.resize(lutSize, 1.0); + if (m_lumaLevelToWeightPLUT.empty()) + m_lumaLevelToWeightPLUT.resize(lutSize, 1.0); + if (m_signalType == RESHAPE_SIGNAL_PQ) + { + for (int i = 0; i < (1 << m_lumaBD); i++) + { + double x = m_lumaBD < 10 ? i << (10 - m_lumaBD) : m_lumaBD > 10 ? i >> (m_lumaBD - 10) : i; + double y; + y = 0.015*x - 1.5 - 6; + y = y < -3 ? -3 : (y > 6 ? 6 : y); + m_reshapeLumaLevelToWeightPLUT[i] = pow(2.0, y / 3.0); + m_lumaLevelToWeightPLUT[i] = m_reshapeLumaLevelToWeightPLUT[i]; + } + } +} + +void RdCost::updateReshapeLumaLevelToWeightTableChromaMD(std::vector<Pel>& ILUT) +{ + for (int i = 0; i < (1 << m_lumaBD); i++) + { + m_reshapeLumaLevelToWeightPLUT[i] = m_lumaLevelToWeightPLUT[ILUT[i]]; + } +} + +void RdCost::restoreReshapeLumaLevelToWeightTable() +{ + for (int i = 0; i < (1 << m_lumaBD); i++) + { + m_reshapeLumaLevelToWeightPLUT.at(i) = m_lumaLevelToWeightPLUT.at(i); } } -Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, const uint32_t uiShift, const Pel orgLuma) +void RdCost::updateReshapeLumaLevelToWeightTable(SliceReshapeInfo &sliceReshape, Pel *wtTable, double cwt) +{ + if (m_signalType == RESHAPE_SIGNAL_SDR) + { + if (sliceReshape.getSliceReshapeModelPresentFlag()) + { + double wBin = 1.0; + double weight = 1.0; + int histLens = (1 << m_lumaBD) / PIC_CODE_CW_BINS; + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + if ((i < sliceReshape.reshaperModelMinBinIdx) || (i > sliceReshape.reshaperModelMaxBinIdx)) + weight = 1.0; + else + { + if (sliceReshape.reshaperModelBinCWDelta[i] == 1 || (sliceReshape.reshaperModelBinCWDelta[i] == -1 * histLens)) + weight = wBin; + else + { + weight = (double)wtTable[i] / (double)histLens; + weight = weight*weight; + } + } + for (int j = 0; j < histLens; j++) + { + int ii = i*histLens + j; + m_reshapeLumaLevelToWeightPLUT[ii] = weight; + } + } + m_chromaWeight = cwt; + } + else + { + THROW("updateReshapeLumaLevelToWeightTable ERROR!!"); + } + } + else + { + THROW("updateReshapeLumaLevelToWeightTable not support other signal types!!"); + } +} +#endif + +Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, const uint32_t uiShift, const Pel orgLuma) { Distortion distortionVal = 0; Intermediate_Int iTemp = org - cur; @@ -2902,8 +3001,32 @@ Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, con CHECK(org!=orgLuma, ""); } // use luma to get weight +#if JVET_M0427_INLOOP_RESHAPER + double weight = 1.0; + if (m_signalType == RESHAPE_SIGNAL_SDR) + { + if (compIdx == COMPONENT_Y) + { + weight = m_reshapeLumaLevelToWeightPLUT[orgLuma]; + } + else + { + weight = m_chromaWeight; + } + } + else + { + weight = m_reshapeLumaLevelToWeightPLUT[orgLuma]; + } +#else double weight = m_lumaLevelToWeightPLUT[orgLuma]; +#endif +#if JVET_M0427_INLOOP_RESHAPER // FIXED_PT_WD_CALCULATION + int64_t fixedPTweight = (int64_t)(weight * (double)(1 << 16)); + Intermediate_Int mse = Intermediate_Int((fixedPTweight*(iTemp*iTemp) + (1 << 15)) >> 16); +#else Intermediate_Int mse = Intermediate_Int(weight*(double)iTemp*(double)iTemp+0.5); +#endif distortionVal = Distortion( mse >> uiShift); return distortionVal; } @@ -2930,7 +3053,7 @@ Distortion RdCost::xGetSSE_WTD( const DistParam &rcDtParam ) { for (int n = 0; n < iCols; n++ ) { - uiSum += getWeightedMSE(rcDtParam.compID, piOrg[n ], piCur[n ], uiShift, piOrgLuma[n<<cShift]); + uiSum += getWeightedMSE(rcDtParam.compID, piOrg[n ], piCur[n ], uiShift, piOrgLuma[n<<cShift]); } piOrg += iStrideOrg; piCur += iStrideCur; @@ -2946,7 +3069,7 @@ Distortion RdCost::xGetSSE2_WTD( const DistParam &rcDtParam ) CHECK( rcDtParam.org.width != 2, "" ); return RdCostWeightPrediction::xGetSSEw( rcDtParam ); // ignore it for now } - + int iRows = rcDtParam.org.height; const Pel* piOrg = rcDtParam.org.buf; const Pel* piCur = rcDtParam.cur.buf; @@ -3015,7 +3138,7 @@ Distortion RdCost::xGetSSE8_WTD( const DistParam &rcDtParam ) const Pel* piOrgLuma = rcDtParam.orgLuma.buf; const size_t iStrideOrgLuma = rcDtParam.orgLuma.stride; const size_t cShift = (rcDtParam.compID==COMPONENT_Y) ? 0 : 1; // assume 420, could use getComponentScaleX, getComponentScaleY - + Distortion uiSum = 0; uint32_t uiShift = DISTORTION_PRECISION_ADJUSTMENT(rcDtParam.bitDepth) << 1; for( ; iRows != 0; iRows-- ) @@ -3050,7 +3173,7 @@ Distortion RdCost::xGetSSE16_WTD( const DistParam &rcDtParam ) const Pel* piOrgLuma = rcDtParam.orgLuma.buf; const size_t iStrideOrgLuma = rcDtParam.orgLuma.stride; const size_t cShift = (rcDtParam.compID==COMPONENT_Y) ? 0 : 1; // assume 420, could use getComponentScaleX, getComponentScaleY - + Distortion uiSum = 0; uint32_t uiShift = DISTORTION_PRECISION_ADJUSTMENT(rcDtParam.bitDepth) << 1; for( ; iRows != 0; iRows-- ) @@ -3138,7 +3261,7 @@ Distortion RdCost::xGetSSE32_WTD( const DistParam &rcDtParam ) const Pel* piOrgLuma = rcDtParam.orgLuma.buf; const size_t iStrideOrgLuma = rcDtParam.orgLuma.stride; const size_t cShift = (rcDtParam.compID==COMPONENT_Y) ? 0 : 1; // assume 420, could use getComponentScaleX, getComponentScaleY - + Distortion uiSum = 0; uint32_t uiShift = DISTORTION_PRECISION_ADJUSTMENT(rcDtParam.bitDepth) << 1; for( ; iRows != 0; iRows-- ) @@ -3197,7 +3320,7 @@ Distortion RdCost::xGetSSE64_WTD( const DistParam &rcDtParam ) const Pel* piOrgLuma = rcDtParam.orgLuma.buf; const size_t iStrideOrgLuma = rcDtParam.orgLuma.stride; const size_t cShift = (rcDtParam.compID==COMPONENT_Y) ? 0 : 1; // assume 420, could use getComponentScaleX, getComponentScaleY - + Distortion uiSum = 0; uint32_t uiShift = DISTORTION_PRECISION_ADJUSTMENT((rcDtParam.bitDepth)) << 1; for( ; iRows != 0; iRows-- ) diff --git a/source/Lib/CommonLib/RdCost.h b/source/Lib/CommonLib/RdCost.h index ead8fd5cb20aa52963c84a7c55dc6f1f34f1b880..28c75f6fa3d31700bba2fc0c5dc9828778158a37 100644 --- a/source/Lib/CommonLib/RdCost.h +++ b/source/Lib/CommonLib/RdCost.h @@ -107,7 +107,15 @@ private: #if WCG_EXT double m_dLambda_unadjusted; // TODO: check is necessary double m_DistScaleUnadjusted; +#if JVET_M0427_INLOOP_RESHAPER + static std::vector<double> m_reshapeLumaLevelToWeightPLUT; + static std::vector<double> m_lumaLevelToWeightPLUT; + static uint32_t m_signalType; + static double m_chromaWeight; + static int m_lumaBD; +#else static double m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +#endif #endif double m_DistScale; double m_dLambdaMotionSAD[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; @@ -290,6 +298,15 @@ public: void saveUnadjustedLambda (); void initLumaLevelToWeightTable (); inline double getWPSNRLumaLevelWeight (int val) { return m_lumaLevelToWeightPLUT[val]; } +#if JVET_M0427_INLOOP_RESHAPER + void initLumaLevelToWeightTableReshape(); + void updateReshapeLumaLevelToWeightTableChromaMD (std::vector<Pel>& ILUT); + void restoreReshapeLumaLevelToWeightTable (); + inline double getWPSNRReshapeLumaLevelWeight (int val) { return m_reshapeLumaLevelToWeightPLUT[val]; } + void setReshapeInfo (uint32_t type, int lumaBD) { m_signalType = type; m_lumaBD = lumaBD; } + void updateReshapeLumaLevelToWeightTable (SliceReshapeInfo &sliceReshape, Pel *wtTable, double cwt); + inline std::vector<double>& getLumaLevelWeightTable () { return m_lumaLevelToWeightPLUT; } +#endif #endif private: diff --git a/source/Lib/CommonLib/Reshape.cpp b/source/Lib/CommonLib/Reshape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31ecca8b14b72d205614072509df2d0857c204e0 --- /dev/null +++ b/source/Lib/CommonLib/Reshape.cpp @@ -0,0 +1,235 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file Reshape.cpp + \brief common reshaper class +*/ +#include "Reshape.h" +#include <stdio.h> +#include <string.h> +#include <math.h> +#if JVET_M0427_INLOOP_RESHAPER + //! \ingroup CommonLib + //! \{ + + // ==================================================================================================================== + // Constructor / destructor / create / destroy + // ==================================================================================================================== + +Reshape::Reshape() +{ + m_CTUFlag = false; + m_recReshaped = false; + m_reshape = true; +} + +Reshape::~Reshape() +{ +} + +void Reshape::createDec(int bitDepth) +{ + m_lumaBD = bitDepth; + m_reshapeLUTSize = 1 << m_lumaBD; + m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS; + if (m_fwdLUT.empty()) + m_fwdLUT.resize(m_reshapeLUTSize, 0); + if (m_invLUT.empty()) + m_invLUT.resize(m_reshapeLUTSize, 0); + if (m_binCW.empty()) + m_binCW.resize(PIC_CODE_CW_BINS, 0); + if (m_reshapePivot.empty()) + m_reshapePivot.resize(PIC_CODE_CW_BINS + 1, 0); + if (m_chromaAdjHelpLUT.empty()) + m_chromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 1<<CSCALE_FP_PREC); +} + +void Reshape::destroy() +{ +} + +/** +-Perform inverse of a one dimension LUT +\param InputLUT describing the input LUT +\retval OutputLUT describing the inversed LUT of InputLUT +\param lut_size size of LUT in number of samples +*/ +void Reshape::reverseLUT(std::vector<Pel>& inputLUT, std::vector<Pel>& outputLUT, uint16_t lutSize) +{ + int i, j; + outputLUT[m_reshapePivot[m_sliceReshapeInfo.reshaperModelMinBinIdx]] = m_sliceReshapeInfo.reshaperModelMinBinIdx*m_initCW; + for (i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) + { + int16_t X1 = m_reshapePivot[i]; + int16_t X2 = m_reshapePivot[i + 1]; + outputLUT[X2] = (i + 1)*m_initCW; + int16_t Y1 = outputLUT[X1]; + int16_t Y2 = outputLUT[X2]; + + if (X2 !=X1) + { + int32_t scale = (int32_t)(Y2 - Y1) * (1 << FP_PREC) / (int32_t)(X2 - X1); + for (j = X1 + 1; j < X2; j++) + { + outputLUT[j] = (Pel)((scale*(int32_t)(j - X1) + (1 << (FP_PREC - 1))) >> FP_PREC) + Y1; + } + } + } + + for (i = 0; i < m_reshapePivot[m_sliceReshapeInfo.reshaperModelMinBinIdx]; i++) + outputLUT[i] = outputLUT[m_reshapePivot[m_sliceReshapeInfo.reshaperModelMinBinIdx]]; + for (i = m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1]; i < m_reshapeLUTSize; i++) + outputLUT[i] = outputLUT[m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1]]; + + bool clipRange = ((m_sliceReshapeInfo.reshaperModelMinBinIdx > 0) && (m_sliceReshapeInfo.reshaperModelMaxBinIdx < (PIC_CODE_CW_BINS - 1))); + for (i = 0; i < lutSize; i++) + { + if (clipRange) outputLUT[i] = Clip3((Pel)(16<<(m_lumaBD-8)), (Pel)(235<<(m_lumaBD-8)), outputLUT[i]); + else outputLUT[i] = Clip3((Pel)0, (Pel)((1<<m_lumaBD)-1), outputLUT[i]); + } +} + + +/** compute chroma residuce scale for TU +* \param average luma pred of TU +* \return chroma residue scale +*/ +int Reshape::calculateChromaAdj(Pel avgLuma) +{ + int lumaIdx = Clip3<int>(0, (1<<m_lumaBD) - 1, avgLuma); + int iAdj = m_chromaAdjHelpLUT[getPWLIdxInv(lumaIdx)]; + return(iAdj); +} + + +/** find inx of PWL for inverse mapping +* \param average luma pred of TU +* \return idx of PWL for inverse mapping +*/ +int Reshape::getPWLIdxInv(int lumaVal) +{ + int idxS = 0; + if (lumaVal < m_reshapePivot[m_sliceReshapeInfo.reshaperModelMinBinIdx + 1]) + return m_sliceReshapeInfo.reshaperModelMinBinIdx; + else if (lumaVal >= m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx]) + return m_sliceReshapeInfo.reshaperModelMaxBinIdx; + else + { + for (idxS = m_sliceReshapeInfo.reshaperModelMinBinIdx; (idxS < m_sliceReshapeInfo.reshaperModelMaxBinIdx); idxS++) + { + if (lumaVal < m_reshapePivot[idxS + 1]) break; + } + return idxS; + } +} + +/** +-copy Slice reshaper info structure +\param tInfo describing the target Slice reshaper info structure +\param sInfo describing the source Slice reshaper info structure +*/ +void Reshape::copySliceReshaperInfo(SliceReshapeInfo& tInfo, SliceReshapeInfo& sInfo) +{ + tInfo.sliceReshaperModelPresentFlag = sInfo.sliceReshaperModelPresentFlag; + if (sInfo.sliceReshaperModelPresentFlag) + { + tInfo.reshaperModelMaxBinIdx = sInfo.reshaperModelMaxBinIdx; + tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx; + memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS)); + tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW; + } + tInfo.sliceReshaperEnableFlag = sInfo.sliceReshaperEnableFlag; + if (sInfo.sliceReshaperEnableFlag) + tInfo.enableChromaAdj = sInfo.enableChromaAdj; + else + tInfo.enableChromaAdj = 0; +} + +/** Construct reshaper from syntax +* \param void +* \return void +*/ +void Reshape::constructReshaper() +{ + int pwlFwdLUTsize = PIC_CODE_CW_BINS; + int pwlFwdBinLen = m_reshapeLUTSize / PIC_CODE_CW_BINS; + + for (int i = 0; i < m_sliceReshapeInfo.reshaperModelMinBinIdx; i++) + m_binCW[i] = 0; + for (int i = m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1; i < PIC_CODE_CW_BINS; i++) + m_binCW[i] = 0; + for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) + m_binCW[i] = (uint16_t)(m_sliceReshapeInfo.reshaperModelBinCWDelta[i] + (int)m_initCW); + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i]; + int16_t Y1 = m_reshapePivot[i]; + int16_t Y2 = m_reshapePivot[i + 1]; + + m_fwdLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y1); + + int log2PwlFwdBinLen = g_aucLog2[pwlFwdBinLen]; + + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2PwlFwdBinLen - 1))) >> (log2PwlFwdBinLen); + for (int j = 1; j < pwlFwdBinLen; j++) + { + int tempVal = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + m_fwdLUT[i*pwlFwdBinLen + j] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)tempVal); + } + } + reverseLUT(m_fwdLUT, m_invLUT, m_reshapeLUTSize); + updateChromaScaleLUT(); +} + +/** generate chroma residue scaling LUT +* \param void +* \return void +*/ +void Reshape::updateChromaScaleLUT() +{ + const int16_t CW_bin_SC_LUT[2 * PIC_ANALYZE_CW_BINS] = { 16384, 16384, 16384, 16384, 16384, 16384, 16384, 8192, 8192, 8192, 8192, 5461, 5461, 5461, 5461, 4096, 4096, 4096, 4096, 3277, 3277, 3277, 3277, 2731, 2731, 2731, 2731, 2341, 2341, 2341, 2048, 2048, 2048, 1820, 1820, 1820, 1638, 1638, 1638, 1638, 1489, 1489, 1489, 1489, 1365, 1365, 1365, 1365, 1260, 1260, 1260, 1260, 1170, 1170, 1170, 1170, 1092, 1092, 1092, 1092, 1024, 1024, 1024, 1024 }; //p=11 + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + uint16_t binCW = m_lumaBD > 10 ? (m_binCW[i] >> (m_lumaBD - 10)) : m_lumaBD < 10 ? (m_binCW[i] << (10 -m_lumaBD)): m_binCW[i]; + if ((i < m_sliceReshapeInfo.reshaperModelMinBinIdx) || (i > m_sliceReshapeInfo.reshaperModelMaxBinIdx)) + m_chromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC; + else + m_chromaAdjHelpLUT[i] = CW_bin_SC_LUT[Clip3((uint16_t)1, (uint16_t)64, (uint16_t)(binCW >> 1)) - 1]; + } +} +#endif + + +// +//! \} diff --git a/source/Lib/CommonLib/Reshape.h b/source/Lib/CommonLib/Reshape.h new file mode 100644 index 0000000000000000000000000000000000000000..64aa62f391ff3e385860c0809d1b125351681086 --- /dev/null +++ b/source/Lib/CommonLib/Reshape.h @@ -0,0 +1,102 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + + /** \file Reshape.h + \brief reshaping header and class (header) + */ + +#ifndef __RESHAPE__ +#define __RESHAPE__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "CommonDef.h" +#include "Rom.h" +#include "CommonLib/Picture.h" +#if JVET_M0427_INLOOP_RESHAPER +//! \ingroup CommonLib +//! \{ +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +class Reshape +{ +protected: + SliceReshapeInfo m_sliceReshapeInfo; + bool m_CTUFlag; + bool m_recReshaped; + std::vector<Pel> m_invLUT; + std::vector<Pel> m_fwdLUT; + std::vector<int> m_chromaAdjHelpLUT; + std::vector<uint16_t> m_binCW; + uint16_t m_initCW; + bool m_reshape; + std::vector<Pel> m_reshapePivot; + int m_lumaBD; + int m_reshapeLUTSize; +public: + Reshape(); + ~Reshape(); + + void createDec(int bitDepth); + void destroy(); + + void reverseLUT(std::vector<Pel>& inputLUT, std::vector<Pel>& outputLUT, uint16_t lutSize); + std::vector<Pel>& getFwdLUT() { return m_fwdLUT; } + std::vector<Pel>& getInvLUT() { return m_invLUT; } + std::vector<int>& getChromaAdjHelpLUT() { return m_chromaAdjHelpLUT; } + + bool getCTUFlag() { return m_CTUFlag; } + void setCTUFlag(bool b ) { m_CTUFlag = b; } + + bool getRecReshaped() { return m_recReshaped; } + void setRecReshaped(bool b) { m_recReshaped = b; } + int calculateChromaAdj(Pel avgLuma); + int getPWLIdxInv(int lumaVal); + SliceReshapeInfo& getSliceReshaperInfo() { return m_sliceReshapeInfo; } + void copySliceReshaperInfo(SliceReshapeInfo& tInfo, SliceReshapeInfo& sInfo); + + void constructReshaper(); + void updateChromaScaleLUT(); + bool getReshapeFlag() { return m_reshape; } + void setReshapeFlag(bool b) { m_reshape = b; } +};// END CLASS DEFINITION Reshape + +//! \} +#endif // +#endif // __RESHAPE__ + + diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index a485d9fadf0a04f6d7a1aa3e0a9cc7ae868502a9..d2e45089664850f87bf095c792926f52eb326c4b 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -310,6 +310,33 @@ uint32_t deriveWeightIdxBits(uint8_t gbiIdx) // Note: align this with TEncSbac:: return numBits; } +#if JVET_M0102_INTRA_SUBPARTITIONS // define the sbb sizes +uint32_t g_log2SbbSize[2][MAX_CU_DEPTH+1][MAX_CU_DEPTH+1][2] = +{ + //===== luma ===== + { + { {0,0}, {0,1}, {0,2}, {0,3}, {0,4}, {0,4}, {0,4}, {0,4} }, + { {1,0}, {1,1}, {1,2}, {1,3}, {1,3}, {1,3}, {1,3}, {1,3} }, + { {2,0}, {2,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {3,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} } + }, + //===== chroma ===== + { + { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} }, + { {0,0}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} } + }, +}; +#endif // initialize ROM variables void initROM() { @@ -341,10 +368,6 @@ void initROM() } #endif - - - - // g_aucConvertToBit[ x ]: log2(x/4), if x=4 -> 0, x=8 -> 1, x=16 -> 2, ... // g_aucLog2[ x ]: log2(x), if x=1 -> 0, x=2 -> 1, x=4 -> 2, x=8 -> 3, x=16 -> 4, ... ::memset(g_aucLog2, 0, sizeof(g_aucLog2)); @@ -373,6 +396,10 @@ void initROM() SizeIndexInfoLog2 sizeInfo; sizeInfo.init(MAX_CU_SIZE); +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { +#endif // initialize scan orders for (uint32_t blockHeightIdx = 0; blockHeightIdx < sizeInfo.numAllHeights(); blockHeightIdx++) { @@ -389,10 +416,23 @@ void initROM() for (uint32_t scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++) { const CoeffScanType scanType = CoeffScanType(scanTypeIndex); + ScanElement * scan = nullptr; + + if (blockWidthIdx < sizeInfo.numWidths() && blockHeightIdx < sizeInfo.numHeights()) + { + scan = new ScanElement[totalValues]; + } - g_scanOrder [SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; - g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; - g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder[ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = scan; +#else + g_scanOrder[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = scan; +#endif + + if (scan == nullptr) + { + continue; + } ScanGenerator fullBlockScan(blockWidth, blockHeight, blockWidth, scanType); @@ -401,36 +441,34 @@ void initROM() const int rasterPos = fullBlockScan.GetNextIndex( 0, 0 ); const int posY = rasterPos / blockWidth; const int posX = rasterPos - ( posY * blockWidth ); - g_scanOrder [SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] [scanPosition] = rasterPos; - g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0][scanPosition] = posX; - g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1][scanPosition] = posY; - } - } - - if( blockWidthIdx >= sizeInfo.numWidths() || blockHeightIdx >= sizeInfo.numHeights() ) - { - // size indizes greater than numIdxs are sizes than are only used when grouping - they will never come up as a block size - thus they can be skipped at this point - for( uint32_t scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++ ) - { - g_scanOrder [SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx] = nullptr; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][0] = nullptr; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][1] = nullptr; + scan[scanPosition].idx = rasterPos; + scan[scanPosition].x = posX; + scan[scanPosition].y = posY; } - - continue; } //-------------------------------------------------------------------------------------------------- //grouped scan orders +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t* log2Sbb = g_log2SbbSize[ch][ g_aucLog2[blockWidth] ][ g_aucLog2[blockHeight] ]; + const uint32_t log2CGWidth = log2Sbb[0]; + const uint32_t log2CGHeight = log2Sbb[1]; +#else const uint32_t log2CGWidth = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; const uint32_t log2CGHeight = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; +#endif const uint32_t groupWidth = 1 << log2CGWidth; const uint32_t groupHeight = 1 << log2CGHeight; +#if JVET_M0257 + const uint32_t widthInGroups = std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, blockWidth) >> log2CGWidth; + const uint32_t heightInGroups = std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, blockHeight) >> log2CGHeight; +#else const uint32_t widthInGroups = blockWidth >> log2CGWidth; const uint32_t heightInGroups = blockHeight >> log2CGHeight; +#endif const uint32_t groupSize = groupWidth * groupHeight; const uint32_t totalGroups = widthInGroups * heightInGroups; @@ -439,10 +477,25 @@ void initROM() { const CoeffScanType scanType = CoeffScanType(scanTypeIndex); - g_scanOrder [SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; + ScanElement *scan = new ScanElement[totalValues]; +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = scan; +#else + g_scanOrder[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = scan; +#endif + +#if JVET_M0257 + if ( blockWidth > JVET_C0024_ZERO_OUT_TH || blockHeight > JVET_C0024_ZERO_OUT_TH ) + { + for (uint32_t i = 0; i < totalValues; i++) + { + scan[i].idx = totalValues - 1; + scan[i].x = blockWidth - 1; + scan[i].y = blockHeight - 1; + } + } +#endif ScanGenerator fullBlockScan(widthInGroups, heightInGroups, groupWidth, scanType); @@ -462,9 +515,9 @@ void initROM() const int posY = rasterPos / blockWidth; const int posX = rasterPos - ( posY * blockWidth ); - g_scanOrder [SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] [groupOffsetScan + scanPosition] = rasterPos; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0][groupOffsetScan + scanPosition] = posX; - g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1][groupOffsetScan + scanPosition] = posY; + scan[groupOffsetScan + scanPosition].idx = rasterPos; + scan[groupOffsetScan + scanPosition].x = posX; + scan[groupOffsetScan + scanPosition].y = posY; } fullBlockScan.GetNextIndex(0, 0); @@ -474,6 +527,9 @@ void initROM() //-------------------------------------------------------------------------------------------------- } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif for( int idxH = MAX_CU_DEPTH - MIN_CU_LOG2; idxH >= 0; --idxH ) { @@ -503,6 +559,25 @@ void destroyROM() unsigned numWidths = gp_sizeIdxInfo->numAllWidths(); unsigned numHeights = gp_sizeIdxInfo->numAllHeights(); +#if JVET_M0102_INTRA_SUBPARTITIONS + for( uint32_t ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { + for( uint32_t groupTypeIndex = 0; groupTypeIndex < SCAN_NUMBER_OF_GROUP_TYPES; groupTypeIndex++ ) + { + for( uint32_t scanOrderIndex = 0; scanOrderIndex < SCAN_NUMBER_OF_TYPES; scanOrderIndex++ ) + { + for( uint32_t blockWidthIdx = 0; blockWidthIdx <= numWidths; blockWidthIdx++ ) + { + for( uint32_t blockHeightIdx = 0; blockHeightIdx <= numHeights; blockHeightIdx++ ) + { + delete[] g_scanOrder[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx]; + g_scanOrder[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx] = nullptr; + } + } + } + } + } +#else for (uint32_t groupTypeIndex = 0; groupTypeIndex < SCAN_NUMBER_OF_GROUP_TYPES; groupTypeIndex++) { for (uint32_t scanOrderIndex = 0; scanOrderIndex < SCAN_NUMBER_OF_TYPES; scanOrderIndex++) @@ -513,17 +588,11 @@ void destroyROM() { delete[] g_scanOrder[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx]; g_scanOrder[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx] = nullptr; - - delete[] g_scanOrderPosXY[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][0]; - g_scanOrderPosXY[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][0] = nullptr; - - delete[] g_scanOrderPosXY[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][1]; - g_scanOrderPosXY[groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][1] = nullptr; - } } } } +#endif delete gp_sizeIdxInfo; gp_sizeIdxInfo = nullptr; @@ -563,10 +632,6 @@ const int g_invQuantScales[SCALING_LIST_REM_NUM] = //-------------------------------------------------------------------------------------------------- //structures - -//EMT threshold - - //-------------------------------------------------------------------------------------------------- //coefficients //-------------------------------------------------------------------------------------------------- @@ -657,17 +722,11 @@ UnitScale g_miScaling( MIN_CU_LOG2, MIN_CU_LOG2 ); // ==================================================================================================================== // scanning order table -uint32_t* g_scanOrder [SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; -uint32_t* g_scanOrderPosXY[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; - -const uint32_t ctxIndMap4x4[4 * 4] = -{ - 0, 1, 4, 5, - 2, 3, 4, 5, - 6, 6, 8, 8, - 7, 7, 8, 8 -}; - +#if JVET_M0102_INTRA_SUBPARTITIONS +ScanElement *g_scanOrder[2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +#else +ScanElement *g_scanOrder[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +#endif const uint32_t g_uiMinInGroup[LAST_SIGNIFICANT_GROUPS] = { 0,1,2,3,4,6,8,12,16,24,32,48,64,96 }; const uint32_t g_uiGroupIdx[MAX_TU_SIZE] = { 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 @@ -683,10 +742,12 @@ const uint32_t g_auiGoRicePosCoeff0[3][32] = {1, 1, 1, 1, 2, 3, 4, 4, 4, 6, 6, 6, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16}, {1, 1, 2, 2, 2, 3, 4, 4, 4, 6, 6, 6, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16} }; +#if !JVET_M0470 const uint32_t g_auiGoRiceRange[MAX_GR_ORDER_RESIDUAL] = { 6, 5, 6, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION, COEF_REMAIN_BIN_REDUCTION }; +#endif #if HEVC_USE_SCALING_LISTS const char *MatrixType[SCALING_LIST_SIZE_NUM][SCALING_LIST_NUM] = @@ -795,19 +856,9 @@ const uint32_t g_scalingListSize [SCALING_LIST_SIZE_NUM] = { 4, 16, 64, 256, 102 const uint32_t g_scalingListSizeX[SCALING_LIST_SIZE_NUM] = { 2, 4, 8, 16, 32, 64, 128 }; #endif -const uint8_t g_NonMPM[257] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, -7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8 }; - +#if !JVET_M0328_KEEP_ONE_WEIGHT_GROUP const Pel g_trianglePelWeightedLuma[TRIANGLE_DIR_NUM][2][7] = -{ +{ { // TRIANGLE_DIR_135 { 1, 2, 4, 6, 7, 0, 0 }, { 1, 2, 3, 4, 5, 6, 7 } @@ -843,19 +894,21 @@ const Pel g_trianglePelWeightedChroma[2][TRIANGLE_DIR_NUM][2][7] = const uint8_t g_triangleWeightLengthLuma[2] = { 5, 7 }; const uint8_t g_triangleWeightLengthChroma[2][2] = { { 5, 7 }, { 3, 3 } }; +#endif - uint8_t g_triangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; +uint8_t g_triangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; +#if !JVET_M0883_TRIANGLE_SIGNALING const uint8_t g_triangleCombination[TRIANGLE_MAX_NUM_CANDS][3] = { - { 0, 1, 0 }, { 1, 0, 1 }, { 1, 0, 2 }, { 0, 0, 1 }, { 0, 2, 0 }, - { 1, 0, 3 }, { 1, 0, 4 }, { 1, 1, 0 }, { 0, 3, 0 }, { 0, 4, 0 }, - { 0, 0, 2 }, { 0, 1, 2 }, { 1, 1, 2 }, { 0, 0, 4 }, { 0, 0, 3 }, - { 0, 1, 3 }, { 0, 1, 4 }, { 1, 1, 4 }, { 1, 1, 3 }, { 1, 2, 1 }, - { 1, 2, 0 }, { 0, 2, 1 }, { 0, 4, 3 }, { 1, 3, 0 }, { 1, 3, 2 }, - { 1, 3, 4 }, { 1, 4, 0 }, { 1, 3, 1 }, { 1, 2, 3 }, { 1, 4, 1 }, - { 0, 4, 1 }, { 0, 2, 3 }, { 1, 4, 2 }, { 0, 3, 2 }, { 1, 4, 3 }, - { 0, 3, 1 }, { 0, 2, 4 }, { 1, 2, 4 }, { 0, 4, 2 }, { 0, 3, 4 }, + { 0, 1, 0 }, { 1, 0, 1 }, { 1, 0, 2 }, { 0, 0, 1 }, { 0, 2, 0 }, + { 1, 0, 3 }, { 1, 0, 4 }, { 1, 1, 0 }, { 0, 3, 0 }, { 0, 4, 0 }, + { 0, 0, 2 }, { 0, 1, 2 }, { 1, 1, 2 }, { 0, 0, 4 }, { 0, 0, 3 }, + { 0, 1, 3 }, { 0, 1, 4 }, { 1, 1, 4 }, { 1, 1, 3 }, { 1, 2, 1 }, + { 1, 2, 0 }, { 0, 2, 1 }, { 0, 4, 3 }, { 1, 3, 0 }, { 1, 3, 2 }, + { 1, 3, 4 }, { 1, 4, 0 }, { 1, 3, 1 }, { 1, 2, 3 }, { 1, 4, 1 }, + { 0, 4, 1 }, { 0, 2, 3 }, { 1, 4, 2 }, { 0, 3, 2 }, { 1, 4, 3 }, + { 0, 3, 1 }, { 0, 2, 4 }, { 1, 2, 4 }, { 0, 4, 2 }, { 0, 3, 4 }, }; const uint8_t g_triangleIdxBins[TRIANGLE_MAX_NUM_CANDS] = @@ -865,4 +918,5 @@ const uint8_t g_triangleIdxBins[TRIANGLE_MAX_NUM_CANDS] = 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; +#endif //! \} diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 2a856a448d8bd7b4f06454e42cbf9806a8022191..f7b795621be0edde887cd2700663a8f2a8a2a60b 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -64,8 +64,21 @@ void generateTrafoBlockSizeScaling( SizeIndexInfo& sizeIdxInfo ); // ==================================================================================================================== // flexible conversion from relative to absolute index -extern uint32_t* g_scanOrder [SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; -extern uint32_t* g_scanOrderPosXY[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; +struct ScanElement +{ + uint32_t idx; + uint16_t x; + uint16_t y; +}; + +#if JVET_M0102_INTRA_SUBPARTITIONS +extern uint32_t g_log2SbbSize [2][MAX_CU_DEPTH+1][MAX_CU_DEPTH+1][2]; +extern ScanElement + *g_scanOrder[2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +#else +extern ScanElement + *g_scanOrder[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +#endif extern const int g_quantScales [SCALING_LIST_REM_NUM]; // Q(QP%6) extern const int g_invQuantScales[SCALING_LIST_REM_NUM]; // IQ(QP%6) @@ -86,8 +99,6 @@ extern const uint8_t g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSi // Scanning order & context mapping table // ==================================================================================================================== -extern const uint32_t ctxIndMap4x4[4*4]; - extern const uint32_t g_uiGroupIdx[ MAX_TU_SIZE ]; extern const uint32_t g_uiMinInGroup[ LAST_SIGNIFICANT_GROUPS ]; extern const uint32_t g_auiGoRiceParsCoeff [ 32 ]; @@ -109,10 +120,6 @@ extern const uint8_t g_chroma422IntraAngleMappingTable[NUM_INTRA_MODE]; // Mode-Dependent DST Matrices // ==================================================================================================================== -#if HEVC_USE_4x4_DSTVII -extern const TMatrixCoeff g_as_DST_MAT_4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4]; -#endif - #if !JVET_M0464_UNI_MTS extern const uint32_t g_EmtSigNumThr; #endif @@ -168,7 +175,6 @@ extern int g_BlockSizeTrafoScale [MAX_CU_SIZE + 1][MAX_CU_S extern int8_t g_aucLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucNextLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucPrevLog2 [MAX_CU_SIZE + 1]; -extern const int8_t i2Log2Tab[257]; inline bool is34( const SizeType& size ) { @@ -219,8 +225,6 @@ extern int g_aiLMDivTableLow[]; extern int g_aiLMDivTableHigh[]; #endif -extern const int g_aiNonLMPosThrs[]; - extern const int8_t g_GbiLog2WeightBase; extern const int8_t g_GbiWeightBase; extern const int8_t g_GbiWeights[GBI_NUM]; @@ -246,13 +250,17 @@ constexpr uint8_t g_tbMax[257] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, //! \} +#if !JVET_M0328_KEEP_ONE_WEIGHT_GROUP extern const Pel g_trianglePelWeightedLuma[TRIANGLE_DIR_NUM][2][7]; extern const Pel g_trianglePelWeightedChroma[2][TRIANGLE_DIR_NUM][2][7]; extern const uint8_t g_triangleWeightLengthLuma[2]; extern const uint8_t g_triangleWeightLengthChroma[2][2]; +#endif extern uint8_t g_triangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; +#if !JVET_M0883_TRIANGLE_SIGNALING extern const uint8_t g_triangleCombination[TRIANGLE_MAX_NUM_CANDS][3]; extern const uint8_t g_triangleIdxBins[TRIANGLE_MAX_NUM_CANDS]; +#endif #endif //__TCOMROM__ diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 00f16676bcbef8eece7b89a92ad3b667df5a08cc..8c14b97ab9edeb273605390eed1177e4571dbf6e 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -92,6 +92,9 @@ Slice::Slice() , m_colRefIdx ( 0 ) , m_maxNumMergeCand ( 0 ) , m_maxNumAffineMergeCand ( 0 ) +#if JVET_M0255_FRACMMVD_SWITCH +, m_disFracMMVD ( false ) +#endif , m_uiTLayer ( 0 ) , m_bTLayerSwitchingFlag ( false ) , m_sliceMode ( NO_SLICES ) @@ -177,6 +180,15 @@ Slice::Slice() } initMotionLUTs(); + +#if JVET_M0427_INLOOP_RESHAPER + m_sliceReshapeInfo.setUseSliceReshaper(false); + m_sliceReshapeInfo.setSliceReshapeModelPresentFlag(false); + m_sliceReshapeInfo.setSliceReshapeChromaAdj(0); + m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; + memset(m_sliceReshapeInfo.reshaperModelBinCWDelta, 0, PIC_CODE_CW_BINS * sizeof(int)); +#endif } Slice::~Slice() @@ -214,6 +226,9 @@ void Slice::initSlice() m_bFinalized=false; +#if JVET_M0255_FRACMMVD_SWITCH + m_disFracMMVD = false; +#endif m_substreamSizes.clear(); m_cabacInitFlag = false; m_cabacWinUpdateMode = 0; @@ -435,13 +450,15 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b pcRefPic = xGetLongTermRefPic(rcListPic, m_pRPS->getPOC(i), m_pRPS->getCheckLTMSBPresent(i)); } } - if (getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (getSPS()->getIBCMode()) { RefPicSetLtCurr[NumPicLtCurr] = getPic(); //getPic()->setIsLongTerm(true); getPic()->longTerm = true; NumPicLtCurr++; } +#endif // ref_pic_list_init Picture* rpsCurrList0[MAX_NUM_REF+1]; Picture* rpsCurrList1[MAX_NUM_REF+1]; @@ -454,11 +471,13 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b // - Otherwise, when the current picture contains a P or B slice, the value of NumPocTotalCurr shall not be equal to 0. if (getRapPicFlag()) { - if (getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (getSPS()->getIBCMode()) { CHECK(numPicTotalCurr != 1, "Invalid state"); } else +#endif CHECK(numPicTotalCurr != 0, "Invalid state"); } @@ -529,11 +548,13 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b m_bIsUsedAsLongTerm[REF_PIC_LIST_1][rIdx] = ( cIdx >= NumPicStCurr0 + NumPicStCurr1 ); } } - if (getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (getSPS()->getIBCMode()) { m_apcRefPicList[REF_PIC_LIST_0][m_aiNumRefIdx[REF_PIC_LIST_0] - 1] = getPic(); m_bIsUsedAsLongTerm[REF_PIC_LIST_0][m_aiNumRefIdx[REF_PIC_LIST_0] - 1] = true; } +#endif // For generalized B // note: maybe not existed case (always L0 is copied to L1 if L1 is empty) if( bCopyL0toL1ErrorCase && isInterB() && getNumRefIdx(REF_PIC_LIST_1) == 0) @@ -564,11 +585,13 @@ int Slice::getNumRpsCurrTempList() const numRpsCurrTempList++; } } - if (getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (getSPS()->getIBCMode()) { return numRpsCurrTempList + 1; } else +#endif return numRpsCurrTempList; } @@ -689,6 +712,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList& if (rpcPic->getPOC() != pocCurr) { rpcPic->referenced = false; +#if JVET_M0253_HASH_ME + rpcPic->getHashMap()->clearAll(); +#endif } iterPic++; } @@ -716,6 +742,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList& if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != m_iLastIDR) { rpcPic->referenced = false; +#if JVET_M0253_HASH_ME + rpcPic->getHashMap()->clearAll(); +#endif } iterPic++; } @@ -733,6 +762,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList& if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != pocCRA) { rpcPic->referenced = false; +#if JVET_M0253_HASH_ME + rpcPic->getHashMap()->clearAll(); +#endif } iterPic++; } @@ -864,6 +896,9 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) m_enableTMVPFlag = pSrc->m_enableTMVPFlag; m_maxNumMergeCand = pSrc->m_maxNumMergeCand; m_maxNumAffineMergeCand = pSrc->m_maxNumAffineMergeCand; +#if JVET_M0255_FRACMMVD_SWITCH + m_disFracMMVD = pSrc->m_disFracMMVD; +#endif if( cpyAlmostAll ) m_encCABACTableIdx = pSrc->m_encCABACTableIdx; m_splitConsOverrideFlag = pSrc->m_splitConsOverrideFlag; m_uiMinQTSize = pSrc->m_uiMinQTSize; @@ -1141,6 +1176,9 @@ void Slice::applyReferencePictureSet( PicList& rcListPic, const ReferencePicture pcPic->referenced = false; pcPic->usedByCurr = false; pcPic->longTerm = false; +#if JVET_M0253_HASH_ME + pcPic->getHashMap()->clearAll(); +#endif } // sanity checks @@ -1612,14 +1650,28 @@ void Slice::initMotionLUTs() { m_MotionCandLut = new LutMotionCand; m_MotionCandLut->currCnt = 0; +#if JVET_M0483_IBC + m_MotionCandLut->currCntIBC = 0; +#endif m_MotionCandLut->motionCand = nullptr; +#if JVET_M0483_IBC + m_MotionCandLut->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2]; +#else m_MotionCandLut->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; +#endif #if JVET_M0170_MRG_SHARELIST m_MotionCandLuTsBkup = new LutMotionCand; m_MotionCandLuTsBkup->currCnt = 0; +#if JVET_M0483_IBC + m_MotionCandLuTsBkup->currCntIBC = 0; +#endif m_MotionCandLuTsBkup->motionCand = nullptr; +#if JVET_M0483_IBC + m_MotionCandLuTsBkup->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2]; +#else m_MotionCandLuTsBkup->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; #endif +#endif } void Slice::destroyMotionLUTs() { @@ -1637,8 +1689,14 @@ void Slice::destroyMotionLUTs() void Slice::resetMotionLUTs() { m_MotionCandLut->currCnt = 0; +#if JVET_M0483_IBC + m_MotionCandLut->currCntIBC = 0; +#endif #if JVET_M0170_MRG_SHARELIST m_MotionCandLuTsBkup->currCnt = 0; +#if JVET_M0483_IBC + m_MotionCandLuTsBkup->currCntIBC = 0; +#endif #endif } @@ -1653,8 +1711,46 @@ MotionInfo Slice::getMotionInfoFromLUTBkup(int MotCandIdx) const } #endif +#if JVET_M0483_IBC +void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi, bool ibcflag) +#else void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi) +#endif { +#if JVET_M0483_IBC + int currCntIBC = ibcflag ? lutMC->currCntIBC : lutMC->currCnt; + int offset = ibcflag ? MAX_NUM_HMVP_CANDS : 0; + bool pruned = false; + int sameCandIdx = 0; + for (int idx = 0; idx < currCntIBC; idx++) + { + if (lutMC->motionCand[idx + offset] == newMi) + { + sameCandIdx = idx; + pruned = true; + break; + } + } + if (pruned || currCntIBC == MAX_NUM_HMVP_CANDS) + { + memmove(&lutMC->motionCand[sameCandIdx + offset], &lutMC->motionCand[sameCandIdx + offset + 1], + sizeof(MotionInfo) * (currCntIBC - sameCandIdx - 1)); + memcpy(&lutMC->motionCand[currCntIBC + offset - 1], &newMi, sizeof(MotionInfo)); + } + else + { + if (ibcflag) + { + memcpy(&lutMC->motionCand[currCntIBC + offset], &newMi, sizeof(MotionInfo)); + lutMC->currCntIBC++; + } + else + { + memcpy(&lutMC->motionCand[currCntIBC], &newMi, sizeof(MotionInfo)); + lutMC->currCnt++; + } + } +#else int currCnt = lutMC->currCnt ; bool pruned = false; @@ -1678,6 +1774,7 @@ void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi) { memcpy(&lutMC->motionCand[lutMC->currCnt++], &newMi, sizeof(MotionInfo)); } +#endif } void Slice::updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu) @@ -1686,19 +1783,37 @@ void Slice::updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu) if (cu.affine) { return; } if (cu.triangle) { return; } - MotionInfo newMi = selectedPU->getMotionInfo(); + MotionInfo newMi = selectedPU->getMotionInfo(); +#if JVET_M0264_HMVP_WITH_GBIIDX + newMi.GBiIdx = (newMi.interDir == 3) ? cu.GBiIdx : GBI_DEFAULT; +#endif +#if JVET_M0483_IBC + addMotionInfoToLUTs(lutMC, newMi, CU::isIBC(cu)); +#else addMotionInfoToLUTs(lutMC, newMi); +#endif } void Slice::copyMotionLUTs(LutMotionCand* Src, LutMotionCand* Dst) { memcpy(Dst->motionCand, Src->motionCand, sizeof(MotionInfo)*(std::min(Src->currCnt, MAX_NUM_HMVP_CANDS))); Dst->currCnt = Src->currCnt; +#if JVET_M0483_IBC + memcpy(Dst->motionCand + MAX_NUM_HMVP_CANDS, Src->motionCand + MAX_NUM_HMVP_CANDS, sizeof(MotionInfo)*(std::min(Src->currCntIBC, MAX_NUM_HMVP_CANDS))); + Dst->currCntIBC = Src->currCntIBC; +#endif } unsigned Slice::getMinPictureDistance() const { int minPicDist = MAX_INT; +#if JVET_M0483_IBC + if (getSPS()->getIBCFlag()) + { + minPicDist = 0; + } + else +#endif if( ! isIntra() ) { const int currPOC = getPOC(); @@ -1766,49 +1881,6 @@ SPSRExt::SPSRExt() } -SPSNext::SPSNext( SPS& sps ) - : m_SPS ( sps ) - , m_NextEnabled ( false ) - // disable all tool enabling flags by default - , m_LargeCTU ( false ) - , m_IMV ( false ) - , m_DisableMotionCompression ( false ) - , m_LMChroma ( false ) -#if JVET_M0142_CCLM_COLLOCATED_CHROMA - , m_cclmCollocatedChromaFlag ( false ) -#endif -#if JVET_M0464_UNI_MTS - , m_IntraMTS ( false ) - , m_InterMTS ( false ) -#else - , m_IntraEMT ( false ) - , m_InterEMT ( false ) -#endif - , m_Affine ( false ) - , m_AffineType ( false ) - , m_MTTEnabled ( false ) - , m_MHIntra ( false ) - , m_Triangle ( false ) -#if ENABLE_WPP_PARALLELISM - , m_NextDQP ( false ) -#endif -#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - , m_LadfEnabled ( false ) - , m_LadfNumIntervals ( 0 ) - , m_LadfQpOffset { 0 } - , m_LadfIntervalLowerBound { 0 } -#endif - - // default values for additional parameters - , m_ImvMode ( IMV_OFF ) - , m_MTTMode ( 0 ) - , m_compositeRefEnabled ( false ) - , m_IBCMode ( 0 ) - // ADD_NEW_TOOL : (sps extension) add tool enabling flags here (with "false" as default values) -{ -} - - SPS::SPS() : m_SPSId ( 0) , m_bIntraOnlyConstraintFlag (false) @@ -1828,6 +1900,16 @@ SPS::SPS() , m_bNoLadfConstraintFlag (false) , m_bNoDepQuantConstraintFlag (false) , m_bNoSignDataHidingConstraintFlag(false) +#if JVET_M0246_AFFINE_AMVR +, m_affineAmvrEnabledFlag ( false ) +#endif +#if JVET_M0147_DMVR +, m_DMVR ( false ) +#endif +#if JVET_M0140_SBT +, m_SBT ( false ) +, m_MaxSbtSize ( 32 ) +#endif #if HEVC_VPS , m_VPSId ( 0) #endif @@ -1858,6 +1940,9 @@ SPS::SPS() , m_bPCMFilterDisableFlag (false) , m_sbtmvpEnabledFlag (false) , m_bdofEnabledFlag (false) +#if JVET_M0255_FRACMMVD_SWITCH +, m_disFracMmvdEnabledFlag ( false ) +#endif , m_uiBitsForPOC ( 8) , m_numLongTermRefPicSPS ( 0) , m_uiMaxTrSize ( 32) @@ -1871,9 +1956,42 @@ SPS::SPS() #endif , m_vuiParametersPresentFlag (false) , m_vuiParameters () -, m_spsNextExtension (*this) , m_wrapAroundEnabledFlag (false) , m_wrapAroundOffset ( 0) +#if JVET_M0483_IBC +, m_IBCFlag ( 0) +#endif +#if JVET_M0427_INLOOP_RESHAPER +, m_lumaReshapeEnable (false) +#endif +// KJS: BEGIN former SPSNext parameters +, m_AMVREnabledFlag ( false ) +, m_LMChroma ( false ) +#if JVET_M0142_CCLM_COLLOCATED_CHROMA +, m_cclmCollocatedChromaFlag ( false ) +#endif +#if JVET_M0464_UNI_MTS +, m_IntraMTS ( false ) +, m_InterMTS ( false ) +#else +, m_IntraEMT ( false ) +, m_InterEMT ( false ) +#endif +, m_Affine ( false ) +, m_AffineType ( false ) +, m_MHIntra ( false ) +, m_Triangle ( false ) +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET +, m_LadfEnabled ( false ) +, m_LadfNumIntervals ( 0 ) +, m_LadfQpOffset { 0 } +, m_LadfIntervalLowerBound { 0 } +#endif +, m_compositeRefEnabled ( false ) +#if !JVET_M0483_IBC +, m_IBCMode ( 0 ) +#endif +// KJS: END former SPSNext parameters { for(int ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++) { diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 05b8ea8f046b66ed3bc1e72b0d4288b506ea31dd..11a7d8728f542e0e5b1610eaa89673dcbca242b9 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -291,6 +291,38 @@ struct HrdSubLayerInfo uint32_t duBitRateValue [MAX_CPB_CNT][2]; }; +#if JVET_M0427_INLOOP_RESHAPER +class SliceReshapeInfo +{ +public: + bool sliceReshaperEnableFlag; + bool sliceReshaperModelPresentFlag; + unsigned enableChromaAdj; + uint32_t reshaperModelMinBinIdx; + uint32_t reshaperModelMaxBinIdx; + int reshaperModelBinCWDelta[PIC_CODE_CW_BINS]; + int maxNbitsNeededDeltaCW; + void setUseSliceReshaper(bool b) { sliceReshaperEnableFlag = b; } + bool getUseSliceReshaper() const { return sliceReshaperEnableFlag; } + void setSliceReshapeModelPresentFlag(bool b) { sliceReshaperModelPresentFlag = b; } + bool getSliceReshapeModelPresentFlag() const { return sliceReshaperModelPresentFlag; } + void setSliceReshapeChromaAdj(unsigned adj) { enableChromaAdj = adj; } + unsigned getSliceReshapeChromaAdj() const { return enableChromaAdj; } +}; + +struct ReshapeCW +{ + std::vector<uint32_t> binCW; + int rspPicSize; + int rspIntraPeriod; + int rspFps; + int rspBaseQP; + int rspTid; + int rspSliceQP; + int rspFpsToIp; +}; +#endif + class HRD { private: @@ -790,135 +822,6 @@ public: }; -class SPS; - -// Deprecated: SPSNext is going to be removed! Do not add any parameters to SPSNext -class SPSNext -{ -private: - SPS& m_SPS; - - bool m_NextEnabled; - //===== tool enabling flags (4 bytes - NOTE: last flag must be used for new extensions) ===== - bool m_LargeCTU; // 5 - bool m_IMV; // 9 - bool m_DisableMotionCompression; // 13 - bool m_LMChroma; // 17 -#if JVET_M0142_CCLM_COLLOCATED_CHROMA - bool m_cclmCollocatedChromaFlag; -#endif -#if JVET_M0464_UNI_MTS - bool m_IntraMTS; // 18 - bool m_InterMTS; // 19 -#else - bool m_IntraEMT; // 18 - bool m_InterEMT; // 19 -#endif - bool m_Affine; - bool m_AffineType; - bool m_GBi; // - bool m_MTTEnabled; // - bool m_MHIntra; - bool m_Triangle; -#if ENABLE_WPP_PARALLELISM - bool m_NextDQP; -#endif -#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - bool m_LadfEnabled; - int m_LadfNumIntervals; - int m_LadfQpOffset[MAX_LADF_INTERVALS]; - int m_LadfIntervalLowerBound[MAX_LADF_INTERVALS]; -#endif - -public: - const static int NumReservedFlags = 32 - 27; /* current number of tool enabling flags */ - -private: - //===== additional parameters ===== - // qtbt - //imv - ImvMode m_ImvMode; - // multi type tree (QTBT + triple split) - unsigned m_MTTMode; - - bool m_compositeRefEnabled; //composite longterm reference - unsigned m_IBCMode; - -public: - SPSNext( SPS& sps ); - - const SPS& getSPS () const { return m_SPS; } - SPS& getSPS () { return m_SPS; } - bool nextToolsEnabled () const { return m_NextEnabled; } - void setNextToolsEnabled ( bool next ) { m_NextEnabled = next; } - - //===== tool enabling flags and extension bit ===== - void setUseLargeCTU ( bool b ) { m_LargeCTU = b; } - bool getUseLargeCTU () const { return m_LargeCTU; } - void setUseIMV ( bool b ) { m_IMV = b; } - bool getUseIMV () const { return m_IMV; } - void setUseAffine ( bool b ) { m_Affine = b; } - bool getUseAffine () const { return m_Affine; } - void setUseAffineType ( bool b ) { m_AffineType = b; } - bool getUseAffineType () const { return m_AffineType; } - void setDisableMotCompress ( bool b ) { m_DisableMotionCompression = b; } - bool getDisableMotCompress () const { return m_DisableMotionCompression; } - bool getMTTEnabled () const { return m_MTTEnabled; } -#if ENABLE_WPP_PARALLELISM - void setUseNextDQP ( bool b ) { m_NextDQP = b; } - bool getUseNextDQP () const { return m_NextDQP; } -#endif - void setUseLMChroma ( bool b ) { m_LMChroma = b; } - bool getUseLMChroma () const { return m_LMChroma; } -#if JVET_M0142_CCLM_COLLOCATED_CHROMA - void setCclmCollocatedChromaFlag( bool b ) { m_cclmCollocatedChromaFlag = b; } - bool getCclmCollocatedChromaFlag() const { return m_cclmCollocatedChromaFlag; } -#endif -#if JVET_M0464_UNI_MTS - void setUseIntraMTS ( bool b ) { m_IntraMTS = b; } - bool getUseIntraMTS () const { return m_IntraMTS; } - void setUseInterMTS ( bool b ) { m_InterMTS = b; } - bool getUseInterMTS () const { return m_InterMTS; } -#else - void setUseIntraEMT ( bool b ) { m_IntraEMT = b; } - bool getUseIntraEMT () const { return m_IntraEMT; } - void setUseInterEMT ( bool b ) { m_InterEMT = b; } - bool getUseInterEMT () const { return m_InterEMT; } -#endif - void setUseGBi ( bool b ) { m_GBi = b; } - bool getUseGBi () const { return m_GBi; } -#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - void setLadfEnabled ( bool b ) { m_LadfEnabled = b; } - bool getLadfEnabled () const { return m_LadfEnabled; } - void setLadfNumIntervals ( int i ) { m_LadfNumIntervals = i; } - int getLadfNumIntervals () const { return m_LadfNumIntervals; } - void setLadfQpOffset ( int value, int idx ) { m_LadfQpOffset[ idx ] = value; } - int getLadfQpOffset ( int idx ) const { return m_LadfQpOffset[ idx ]; } - void setLadfIntervalLowerBound( int value, int idx ) { m_LadfIntervalLowerBound[ idx ] = value; } - int getLadfIntervalLowerBound( int idx ) const { return m_LadfIntervalLowerBound[ idx ]; } -#endif - //===== additional parameters ===== - // qtbt - // sub pu tmvp - void setImvMode(ImvMode m) { m_ImvMode = m; m_IMV = m != 0; } - ImvMode getImvMode () const { return m_ImvMode; } - - // multi type tree - unsigned getMTTMode () const { return m_MTTMode; } - void setMTTMode ( unsigned mode ) { m_MTTMode = mode; m_MTTEnabled = ( m_MTTMode != 0 ); } - - void setUseCompositeRef(bool b) { m_compositeRefEnabled = b; } - bool getUseCompositeRef() const { return m_compositeRefEnabled; } - - void setUseMHIntra ( bool b ) { m_MHIntra = b; } - bool getUseMHIntra () const { return m_MHIntra; } - void setUseTriangle ( bool b ) { m_Triangle = b; } - bool getUseTriangle () const { return m_Triangle; } - void setIBCMode (unsigned IBCMode) { m_IBCMode = IBCMode; } - unsigned getIBCMode () const { return m_IBCMode; } -}; - - /// SPS class class SPS { @@ -942,6 +845,16 @@ private: bool m_bNoDepQuantConstraintFlag; bool m_bNoSignDataHidingConstraintFlag; +#if JVET_M0246_AFFINE_AMVR + bool m_affineAmvrEnabledFlag; +#endif +#if JVET_M0147_DMVR + bool m_DMVR; +#endif +#if JVET_M0140_SBT + bool m_SBT; + uint8_t m_MaxSbtSize; +#endif #if HEVC_VPS int m_VPSId; #endif @@ -990,7 +903,9 @@ private: bool m_sbtmvpEnabledFlag; bool m_bdofEnabledFlag; - +#if JVET_M0255_FRACMMVD_SWITCH + bool m_disFracMmvdEnabledFlag; +#endif uint32_t m_uiBitsForPOC; uint32_t m_numLongTermRefPicSPS; uint32_t m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS]; @@ -1018,7 +933,6 @@ private: VUI m_vuiParameters; SPSRExt m_spsRangeExtension; - SPSNext m_spsNextExtension; static const int m_winUnitX[NUM_CHROMA_FORMAT]; static const int m_winUnitY[NUM_CHROMA_FORMAT]; @@ -1028,6 +942,47 @@ private: bool m_wrapAroundEnabledFlag; unsigned m_wrapAroundOffset; +#if JVET_M0483_IBC + unsigned m_IBCFlag; +#endif + +#if JVET_M0427_INLOOP_RESHAPER + bool m_lumaReshapeEnable; +#endif + // KJS: BEGIN former SPSNext parameters + bool m_AMVREnabledFlag; + bool m_LMChroma; // 17 +#if JVET_M0142_CCLM_COLLOCATED_CHROMA + bool m_cclmCollocatedChromaFlag; +#endif +#if JVET_M0303_IMPLICIT_MTS + bool m_MTS; +#endif +#if JVET_M0464_UNI_MTS + bool m_IntraMTS; // 18 + bool m_InterMTS; // 19 +#else + bool m_IntraEMT; // 18 + bool m_InterEMT; // 19 +#endif + bool m_Affine; + bool m_AffineType; + bool m_GBi; // + bool m_MHIntra; + bool m_Triangle; +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + bool m_LadfEnabled; + int m_LadfNumIntervals; + int m_LadfQpOffset[MAX_LADF_INTERVALS]; + int m_LadfIntervalLowerBound[MAX_LADF_INTERVALS]; +#endif + + bool m_compositeRefEnabled; //composite longterm reference +#if !JVET_M0483_IBC + unsigned m_IBCMode; +#endif + // KJS: END former SPSNext parameters + public: @@ -1120,7 +1075,7 @@ public: unsigned getMaxBTDepthIChroma() const { return m_maxBTDepth[2]; } void setMaxBTSize(unsigned maxBTSize, unsigned maxBTSizeI, - unsigned maxBTSizeC) + unsigned maxBTSizeC) { m_maxBTSize[1] = maxBTSize; m_maxBTSize[0] = maxBTSizeI; m_maxBTSize[2] = maxBTSizeC; } unsigned getMaxBTSize() const { return m_maxBTSize[1]; } unsigned getMaxBTSizeI() const { return m_maxBTSize[0]; } @@ -1189,10 +1144,18 @@ public: bool getSBTMVPEnabledFlag() const { return m_sbtmvpEnabledFlag; } void setSBTMVPEnabledFlag(bool b) { m_sbtmvpEnabledFlag = b; } - + void setBDOFEnabledFlag(bool b) { m_bdofEnabledFlag = b; } bool getBDOFEnabledFlag() const { return m_bdofEnabledFlag; } +#if JVET_M0255_FRACMMVD_SWITCH + bool getDisFracMmvdEnabledFlag() const { return m_disFracMmvdEnabledFlag; } + void setDisFracMmvdEnabledFlag( bool b ) { m_disFracMmvdEnabledFlag = b; } +#endif +#if JVET_M0147_DMVR + bool getUseDMVR()const { return m_DMVR; } + void setUseDMVR(bool b) { m_DMVR = b; } +#endif uint32_t getMaxTLayers() const { return m_uiMaxTLayers; } void setMaxTLayers( uint32_t uiMaxTLayers ) { CHECK( uiMaxTLayers > MAX_TLAYER, "Invalid number T-layers" ); m_uiMaxTLayers = uiMaxTLayers; } @@ -1220,6 +1183,10 @@ public: void setUseStrongIntraSmoothing(bool bVal) { m_useStrongIntraSmoothing = bVal; } bool getUseStrongIntraSmoothing() const { return m_useStrongIntraSmoothing; } +#endif +#if JVET_M0246_AFFINE_AMVR + void setAffineAmvrEnabledFlag( bool val ) { m_affineAmvrEnabledFlag = val; } + bool getAffineAmvrEnabledFlag() const { return m_affineAmvrEnabledFlag; } #endif bool getVuiParametersPresentFlag() const { return m_vuiParametersPresentFlag; } void setVuiParametersPresentFlag(bool b) { m_vuiParametersPresentFlag = b; } @@ -1231,13 +1198,83 @@ public: const SPSRExt& getSpsRangeExtension() const { return m_spsRangeExtension; } SPSRExt& getSpsRangeExtension() { return m_spsRangeExtension; } - const SPSNext& getSpsNext() const { return m_spsNextExtension; } - SPSNext& getSpsNext() { return m_spsNextExtension; } - void setWrapAroundEnabledFlag(bool b) { m_wrapAroundEnabledFlag = b; } bool getWrapAroundEnabledFlag() const { return m_wrapAroundEnabledFlag; } void setWrapAroundOffset(unsigned offset) { m_wrapAroundOffset = offset; } unsigned getWrapAroundOffset() const { return m_wrapAroundOffset; } +#if JVET_M0427_INLOOP_RESHAPER + void setUseReshaper(bool b) { m_lumaReshapeEnable = b; } + bool getUseReshaper() const { return m_lumaReshapeEnable; } +#endif +#if JVET_M0483_IBC + void setIBCFlag(unsigned IBCFlag) { m_IBCFlag = IBCFlag; } + unsigned getIBCFlag() const { return m_IBCFlag; } +#endif +#if JVET_M0140_SBT + void setUseSBT( bool b ) { m_SBT = b; } + bool getUseSBT() const { return m_SBT; } + void setMaxSbtSize( uint8_t val ) { m_MaxSbtSize = val; } + uint8_t getMaxSbtSize() const { return m_MaxSbtSize; } +#endif + + // KJS: BEGIN former SPSNext parameters + void setAMVREnabledFlag ( bool b ) { m_AMVREnabledFlag = b; } + bool getAMVREnabledFlag () const { return m_AMVREnabledFlag; } + void setUseAffine ( bool b ) { m_Affine = b; } + bool getUseAffine () const { return m_Affine; } + void setUseAffineType ( bool b ) { m_AffineType = b; } + bool getUseAffineType () const { return m_AffineType; } + void setUseLMChroma ( bool b ) { m_LMChroma = b; } + bool getUseLMChroma () const { return m_LMChroma; } +#if JVET_M0142_CCLM_COLLOCATED_CHROMA + void setCclmCollocatedChromaFlag( bool b ) { m_cclmCollocatedChromaFlag = b; } + bool getCclmCollocatedChromaFlag() const { return m_cclmCollocatedChromaFlag; } +#endif +#if JVET_M0303_IMPLICIT_MTS + void setUseMTS ( bool b ) { m_MTS = b; } + bool getUseMTS () const { return m_MTS; } +#if JVET_M0464_UNI_MTS + bool getUseImplicitMTS () const { return m_MTS && !m_IntraMTS && !m_InterMTS; } +#else + bool getUseImplicitMTS () const { return m_MTS && !m_IntraEMT && !m_InterEMT; } +#endif +#endif +#if JVET_M0464_UNI_MTS + void setUseIntraMTS ( bool b ) { m_IntraMTS = b; } + bool getUseIntraMTS () const { return m_IntraMTS; } + void setUseInterMTS ( bool b ) { m_InterMTS = b; } + bool getUseInterMTS () const { return m_InterMTS; } +#else + void setUseIntraEMT ( bool b ) { m_IntraEMT = b; } + bool getUseIntraEMT () const { return m_IntraEMT; } + void setUseInterEMT ( bool b ) { m_InterEMT = b; } + bool getUseInterEMT () const { return m_InterEMT; } +#endif + void setUseGBi ( bool b ) { m_GBi = b; } + bool getUseGBi () const { return m_GBi; } +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + void setLadfEnabled ( bool b ) { m_LadfEnabled = b; } + bool getLadfEnabled () const { return m_LadfEnabled; } + void setLadfNumIntervals ( int i ) { m_LadfNumIntervals = i; } + int getLadfNumIntervals () const { return m_LadfNumIntervals; } + void setLadfQpOffset ( int value, int idx ) { m_LadfQpOffset[ idx ] = value; } + int getLadfQpOffset ( int idx ) const { return m_LadfQpOffset[ idx ]; } + void setLadfIntervalLowerBound( int value, int idx ) { m_LadfIntervalLowerBound[ idx ] = value; } + int getLadfIntervalLowerBound( int idx ) const { return m_LadfIntervalLowerBound[ idx ]; } +#endif + // KJS: this is encoder only, right? + void setUseCompositeRef(bool b) { m_compositeRefEnabled = b; } + bool getUseCompositeRef() const { return m_compositeRefEnabled; } + + void setUseMHIntra ( bool b ) { m_MHIntra = b; } + bool getUseMHIntra () const { return m_MHIntra; } + void setUseTriangle ( bool b ) { m_Triangle = b; } + bool getUseTriangle () const { return m_Triangle; } +#if !JVET_M0483_IBC + void setIBCMode (unsigned IBCMode) { m_IBCMode = IBCMode; } + unsigned getIBCMode () const { return m_IBCMode; } +#endif + // KJS: END former SPSNext parameters }; @@ -1602,7 +1639,9 @@ private: uint32_t m_colRefIdx; uint32_t m_maxNumMergeCand; uint32_t m_maxNumAffineMergeCand; - +#if JVET_M0255_FRACMMVD_SWITCH + bool m_disFracMMVD; +#endif double m_lambdas[MAX_NUM_COMPONENT]; bool m_abEqualRef [NUM_REF_PIC_LIST_01][MAX_NUM_REF][MAX_NUM_REF]; @@ -1665,6 +1704,9 @@ private: AlfSliceParam m_alfSliceParam; LutMotionCand* m_MotionCandLut; +#if JVET_M0427_INLOOP_RESHAPER + SliceReshapeInfo m_sliceReshapeInfo; +#endif #if JVET_M0170_MRG_SHARELIST public: LutMotionCand* m_MotionCandLuTsBkup; @@ -1846,7 +1888,10 @@ public: uint32_t getMaxNumMergeCand() const { return m_maxNumMergeCand; } void setMaxNumAffineMergeCand( uint32_t val ) { m_maxNumAffineMergeCand = val; } uint32_t getMaxNumAffineMergeCand() const { return m_maxNumAffineMergeCand; } - +#if JVET_M0255_FRACMMVD_SWITCH + void setDisFracMMVD( bool val ) { m_disFracMMVD = val; } + bool getDisFracMMVD() const { return m_disFracMMVD; } +#endif void setNoOutputPriorPicsFlag( bool val ) { m_noOutputPriorPicsFlag = val; } bool getNoOutputPriorPicsFlag() const { return m_noOutputPriorPicsFlag; } @@ -1949,6 +1994,9 @@ public: void initMotionLUTs (); void destroyMotionLUTs (); void resetMotionLUTs(); +#if JVET_M0483_IBC + int getAvailableLUTIBCMrgNum() const { return m_MotionCandLut->currCntIBC; } +#endif int getAvailableLUTMrgNum() const { return m_MotionCandLut->currCnt; } #if JVET_M0170_MRG_SHARELIST int getAvailableLUTBkupMrgNum() const { return m_MotionCandLuTsBkup->currCnt; } @@ -1957,12 +2005,18 @@ public: MotionInfo getMotionInfoFromLUTs(int MotCandIdx) const; LutMotionCand* getMotionLUTs() { return m_MotionCandLut; } - +#if JVET_M0483_IBC + void addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi, bool ibcflag); +#else void addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi); +#endif void updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu); void copyMotionLUTs(LutMotionCand* Src, LutMotionCand* Dst); - +#if JVET_M0427_INLOOP_RESHAPER + const SliceReshapeInfo& getReshapeInfo() const { return m_sliceReshapeInfo; } + SliceReshapeInfo& getReshapeInfo() { return m_sliceReshapeInfo; } +#endif protected: Picture* xGetRefPic (PicList& rcListPic, int poc); Picture* xGetLongTermRefPic(PicList& rcListPic, int poc, bool pocHasMsb); @@ -2178,7 +2232,6 @@ public: PreCalcValues( const SPS& sps, const PPS& pps, bool _isEncoder ) : chrFormat ( sps.getChromaFormatIdc() ) , multiBlock422 ( false ) - , noMotComp ( sps.getSpsNext().getDisableMotCompress() ) , maxCUWidth ( sps.getMaxCUWidth() ) , maxCUHeight ( sps.getMaxCUHeight() ) , maxCUWidthMask ( maxCUWidth - 1 ) @@ -2211,7 +2264,6 @@ public: const ChromaFormat chrFormat; const bool multiBlock422; - const bool noMotComp; const unsigned maxCUWidth; const unsigned maxCUHeight; // to get CTU position, use (x & maxCUWidthMask) rather than (x % maxCUWidth) diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index f2afd109dbc34b8db435b25fb24882642c21634b..44ed81e06ca1d2ef668e3ea296060cecbf6328a4 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -122,6 +122,7 @@ TrQuant::~TrQuant() xFree( m_mtsCoeffs[i] ); m_mtsCoeffs[i] = nullptr; } + delete[] m_mtsCoeffs; m_mtsCoeffs = nullptr; } #endif @@ -205,7 +206,7 @@ void TrQuant::invTransformNxN( TransformUnit &tu, const ComponentID &compID, Pel DTRACE_COEFF_BUF( D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID ); #if JVET_M0464_UNI_MTS - if( tu.mtsIdx == 1 ) + if( isLuma(compID) && tu.mtsIdx == 1 ) #else if( tu.transformSkip[compID] ) #endif @@ -292,14 +293,61 @@ void TrQuant::invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf & void TrQuant::getTrTypes ( TransformUnit tu, const ComponentID compID, int &trTypeHor, int &trTypeVer ) { #if JVET_M0464_UNI_MTS - bool mtsActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraMTS() : tu.cs->sps->getSpsNext().getUseInterMTS(); + bool mtsActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getUseIntraMTS() : tu.cs->sps->getUseInterMTS(); #else - bool emtActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraEMT() : tu.cs->sps->getSpsNext().getUseInterEMT(); + bool emtActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getUseIntraEMT() : tu.cs->sps->getUseInterEMT(); #endif - + +#if JVET_M0303_IMPLICIT_MTS + bool mtsImplicit = CU::isIntra( *tu.cu ) && tu.cs->sps->getUseImplicitMTS() && compID == COMPONENT_Y; +#endif + trTypeHor = DCT2; trTypeVer = DCT2; - + +#if JVET_M0102_INTRA_SUBPARTITIONS + if (tu.cu->ispMode && isLuma(compID)) + { + TU::getTransformTypeISP(tu, compID, trTypeHor, trTypeVer); + return; +} +#endif +#if JVET_M0140_SBT + if( tu.cu->sbtInfo && compID == COMPONENT_Y ) + { + uint8_t sbtIdx = tu.cu->getSbtIdx(); + uint8_t sbtPos = tu.cu->getSbtPos(); + + if( sbtIdx == SBT_VER_HALF || sbtIdx == SBT_VER_QUAD ) + { + assert( tu.lwidth() <= MTS_INTER_MAX_CU_SIZE ); + if( tu.lheight() > MTS_INTER_MAX_CU_SIZE ) + { + trTypeHor = trTypeVer = DCT2; + } + else + { + if( sbtPos == SBT_POS0 ) { trTypeHor = DCT8; trTypeVer = DST7; } + else { trTypeHor = DST7; trTypeVer = DST7; } + } + } + else + { + assert( tu.lheight() <= MTS_INTER_MAX_CU_SIZE ); + if( tu.lwidth() > MTS_INTER_MAX_CU_SIZE ) + { + trTypeHor = trTypeVer = DCT2; + } + else + { + if( sbtPos == SBT_POS0 ) { trTypeHor = DST7; trTypeVer = DCT8; } + else { trTypeHor = DST7; trTypeVer = DST7; } + } + } + return; + } +#endif + #if JVET_M0464_UNI_MTS if ( mtsActivated ) #else @@ -319,12 +367,28 @@ void TrQuant::getTrTypes ( TransformUnit tu, const ComponentID compID, int &trTy int indHor = tu.emtIdx & 1; int indVer = tu.emtIdx >> 1; #endif - + trTypeHor = indHor ? DCT8 : DST7; trTypeVer = indVer ? DCT8 : DST7; } } } +#if JVET_M0303_IMPLICIT_MTS + else if ( mtsImplicit ) + { + int width = tu.blocks[compID].width; + int height = tu.blocks[compID].height; + bool widthDstOk = width >= 4 && width <= 16; + bool heightDstOk = height >= 4 && height <= 16; + + if ( width < height && widthDstOk ) + trTypeHor = DST7; + else if ( height < width && heightDstOk ) + trTypeVer = DST7; + else if ( width == height && widthDstOk ) + trTypeHor = trTypeVer = DST7; + } +#endif } void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPelBuf &resi, CoeffBuf &dstCoeff, const int width, const int height ) @@ -332,33 +396,44 @@ void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPel const unsigned maxLog2TrDynamicRange = tu.cs->sps->getMaxLog2TrDynamicRange( toChannelType( compID ) ); const unsigned bitDepth = tu.cs->sps->getBitDepth( toChannelType( compID ) ); const int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_FORWARD]; +#if !JVET_M0102_INTRA_SUBPARTITIONS const int shift_1st = ((g_aucLog2[width ]) + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxLog2TrDynamicRange + COM16_C806_TRANS_PREC; const int shift_2nd = (g_aucLog2[height]) + TRANSFORM_MATRIX_SHIFT + COM16_C806_TRANS_PREC; +#endif const uint32_t transformWidthIndex = g_aucLog2[width ] - 1; // nLog2WidthMinus1, since transform start from 2-point const uint32_t transformHeightIndex = g_aucLog2[height] - 1; // nLog2HeightMinus1, since transform start from 2-point +#if !JVET_M0297_32PT_MTS_ZERO_OUT const int skipWidth = width > JVET_C0024_ZERO_OUT_TH ? width - JVET_C0024_ZERO_OUT_TH : 0; const int skipHeight = height > JVET_C0024_ZERO_OUT_TH ? height - JVET_C0024_ZERO_OUT_TH : 0; - +#endif + +#if !JVET_M0102_INTRA_SUBPARTITIONS CHECK( shift_1st < 0, "Negative shift" ); CHECK( shift_2nd < 0, "Negative shift" ); - +#endif + int trTypeHor = DCT2; int trTypeVer = DCT2; - + getTrTypes ( tu, compID, trTypeHor, trTypeVer ); - + +#if JVET_M0297_32PT_MTS_ZERO_OUT + const int skipWidth = ( trTypeHor != DCT2 && width == 32 ) ? 16 : width > JVET_C0024_ZERO_OUT_TH ? width - JVET_C0024_ZERO_OUT_TH : 0; + const int skipHeight = ( trTypeVer != DCT2 && height == 32 ) ? 16 : height > JVET_C0024_ZERO_OUT_TH ? height - JVET_C0024_ZERO_OUT_TH : 0; +#endif + #if RExt__DECODER_DEBUG_TOOL_STATISTICS if ( trTypeHor != DCT2 ) { CodingStatistics::IncrementStatisticTool( CodingStatisticsClassType{ STATS__TOOL_EMT, uint32_t( width ), uint32_t( height ), compID } ); } #endif - + ALIGN_DATA( MEMORY_ALIGN_DEF_SIZE, TCoeff block[MAX_TU_SIZE * MAX_TU_SIZE] ); - + const Pel *resiBuf = resi.buf; const int resiStride = resi.stride; - + for( int y = 0; y < height; y++ ) { for( int x = 0; x < width; x++ ) @@ -366,11 +441,36 @@ void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPel block[( y * width ) + x] = resiBuf[( y * resiStride ) + x]; } } - + +#if JVET_M0102_INTRA_SUBPARTITIONS + if( width > 1 && height > 1 ) // 2-D transform + { + const int shift_1st = ((g_aucLog2[width ]) + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxLog2TrDynamicRange + COM16_C806_TRANS_PREC; + const int shift_2nd = (g_aucLog2[height]) + TRANSFORM_MATRIX_SHIFT + COM16_C806_TRANS_PREC; + CHECK( shift_1st < 0, "Negative shift" ); + CHECK( shift_2nd < 0, "Negative shift" ); +#endif TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); - + fastFwdTrans[trTypeHor][transformWidthIndex ](block, tmp, shift_1st, height, 0, skipWidth); fastFwdTrans[trTypeVer][transformHeightIndex](tmp, dstCoeff.buf, shift_2nd, width, skipWidth, skipHeight); +#if JVET_M0102_INTRA_SUBPARTITIONS + } + else if( height == 1 ) //1-D horizontal transform + { + const int shift = ((g_aucLog2[width ]) + bitDepth + TRANSFORM_MATRIX_SHIFT) - maxLog2TrDynamicRange + COM16_C806_TRANS_PREC; + CHECK( shift < 0, "Negative shift" ); + CHECKD( ( transformWidthIndex < 0 ), "There is a problem with the width." ); + fastFwdTrans[trTypeHor][transformWidthIndex]( block, dstCoeff.buf, shift, 1, 0, skipWidth ); + } + else //if (iWidth == 1) //1-D vertical transform + { + int shift = ( ( g_aucLog2[height] ) + bitDepth + TRANSFORM_MATRIX_SHIFT ) - maxLog2TrDynamicRange + COM16_C806_TRANS_PREC; + CHECK( shift < 0, "Negative shift" ); + CHECKD( ( transformHeightIndex < 0 ), "There is a problem with the height." ); + fastFwdTrans[trTypeVer][transformHeightIndex]( block, dstCoeff.buf, shift, 1, 0, skipHeight ); + } +#endif } void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pCoeff, PelBuf &pResidual ) @@ -382,30 +482,69 @@ void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCo const int TRANSFORM_MATRIX_SHIFT = g_transformMatrixShift[TRANSFORM_INVERSE]; const TCoeff clipMinimum = -( 1 << maxLog2TrDynamicRange ); const TCoeff clipMaximum = ( 1 << maxLog2TrDynamicRange ) - 1; +#if !JVET_M0102_INTRA_SUBPARTITIONS const int shift_1st = TRANSFORM_MATRIX_SHIFT + 1 + COM16_C806_TRANS_PREC; // 1 has been added to shift_1st at the expense of shift_2nd const int shift_2nd = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC; +#endif const uint32_t transformWidthIndex = g_aucLog2[width ] - 1; // nLog2WidthMinus1, since transform start from 2-point const uint32_t transformHeightIndex = g_aucLog2[height] - 1; // nLog2HeightMinus1, since transform start from 2-point +#if !JVET_M0297_32PT_MTS_ZERO_OUT const int skipWidth = width > JVET_C0024_ZERO_OUT_TH ? width - JVET_C0024_ZERO_OUT_TH : 0; const int skipHeight = height > JVET_C0024_ZERO_OUT_TH ? height - JVET_C0024_ZERO_OUT_TH : 0; - +#endif + +#if !JVET_M0102_INTRA_SUBPARTITIONS CHECK( shift_1st < 0, "Negative shift" ); CHECK( shift_2nd < 0, "Negative shift" ); - +#endif + int trTypeHor = DCT2; int trTypeVer = DCT2; - + getTrTypes ( tu, compID, trTypeHor, trTypeVer ); - + +#if JVET_M0297_32PT_MTS_ZERO_OUT + const int skipWidth = ( trTypeHor != DCT2 && width == 32 ) ? 16 : width > JVET_C0024_ZERO_OUT_TH ? width - JVET_C0024_ZERO_OUT_TH : 0; + const int skipHeight = ( trTypeVer != DCT2 && height == 32 ) ? 16 : height > JVET_C0024_ZERO_OUT_TH ? height - JVET_C0024_ZERO_OUT_TH : 0; +#endif + +#if !JVET_M0102_INTRA_SUBPARTITIONS TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); +#endif TCoeff *block = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); - + +#if JVET_M0102_INTRA_SUBPARTITIONS + if( width > 1 && height > 1 ) //2-D transform + { + const int shift_1st = TRANSFORM_MATRIX_SHIFT + 1 + COM16_C806_TRANS_PREC; // 1 has been added to shift_1st at the expense of shift_2nd + const int shift_2nd = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC; + CHECK( shift_1st < 0, "Negative shift" ); + CHECK( shift_2nd < 0, "Negative shift" ); + TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); +#endif fastInvTrans[trTypeVer][transformHeightIndex](pCoeff.buf, tmp, shift_1st, width, skipWidth, skipHeight, clipMinimum, clipMaximum); fastInvTrans[trTypeHor][transformWidthIndex] (tmp, block, shift_2nd, height, 0, skipWidth, clipMinimum, clipMaximum); - +#if JVET_M0102_INTRA_SUBPARTITIONS + } + else if( width == 1 ) //1-D vertical transform + { + int shift = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC; + CHECK( shift < 0, "Negative shift" ); + CHECK( ( transformHeightIndex < 0 ), "There is a problem with the height." ); + fastInvTrans[trTypeVer][transformHeightIndex]( pCoeff.buf, block, shift + 1, 1, 0, skipHeight, clipMinimum, clipMaximum ); + } + else //if(iHeight == 1) //1-D horizontal transform + { + const int shift = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC; + CHECK( shift < 0, "Negative shift" ); + CHECK( ( transformWidthIndex < 0 ), "There is a problem with the width." ); + fastInvTrans[trTypeHor][transformWidthIndex]( pCoeff.buf, block, shift + 1, 1, 0, skipWidth, clipMinimum, clipMaximum ); + } +#endif + Pel *resiBuf = pResidual.buf; int resiStride = pResidual.stride; - + for( int y = 0; y < height; y++ ) { for( int x = 0; x < width; x++ ) @@ -435,7 +574,7 @@ void TrQuant::xITransformSkip(const CCoeffBuf &pCoeff, } int iWHScale = 1; -#if HM_QTBT_AS_IN_JEM_QUANT +#if HM_QTBT_AS_IN_JEM_QUANT && !JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT if( TU::needsBlockSizeTrafoScale( area ) ) { iTransformShift += ADJ_QUANT_SHIFT; @@ -477,7 +616,11 @@ void TrQuant::xQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffB } #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio, double* horVerRatio ) +#else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand) +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -497,8 +640,17 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q { tu.mtsIdx = it->first; CoeffBuf tempCoeff( m_mtsCoeffs[tu.mtsIdx], rect ); +#if JVET_M0140_SBT + if( tu.noResidual ) + { + int sumAbs = 0; + trCosts.push_back( TrCost( sumAbs, pos++ ) ); + it++; + continue; + } +#endif - if( tu.mtsIdx == 1 ) + if( isLuma(compID) && tu.mtsIdx == 1 ) { xTransformSkip( tu, compID, resiBuf, tempCoeff.buf ); } @@ -513,10 +665,24 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q sumAbs += abs( tempCoeff.buf[pos] ); } +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + double scaleSAD=1.0; + if (isLuma(compID) && tu.mtsIdx==1 && ((g_aucLog2[width] + g_aucLog2[height]) & 1) == 1 ) + { + scaleSAD=1.0/1.414213562; // compensate for not scaling transform skip coefficients by 1/sqrt(2) + } + trCosts.push_back( TrCost( int(sumAbs*scaleSAD), pos++ ) ); +#else trCosts.push_back( TrCost( sumAbs, pos++ ) ); +#endif it++; } +#if JVET_M0102_INTRA_SUBPARTITIONS + // it gets the distribution of the DCT-II coefficients energy, which will be useful to discard ISP tests + CoeffBuf coeffsDCT( m_mtsCoeffs[0], rect ); + xGetCoeffEnergy( tu, compID, coeffsDCT, diagRatio, horVerRatio ); +#endif int numTests = 0; std::vector<TrCost>::iterator itC = trCosts.begin(); const double fac = facBB[g_aucLog2[std::max(width, height)]-2]; @@ -533,10 +699,18 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q #endif #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr, double* diagRatio, double* horVerRatio ) +#else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr) +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, double* diagRatio, double* horVerRatio) #else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx) #endif +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -547,6 +721,15 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q const CPelBuf resiBuf = cs.getResiBuf(rect); CoeffBuf rpcCoeff = tu.getCoeffs(compID); +#if JVET_M0140_SBT + if( tu.noResidual ) + { + uiAbsSum = 0; + TU::setCbfAtDepth( tu, compID, tu.depth, uiAbsSum > 0 ); + return; + } +#endif + RDPCMMode rdpcmMode = RDPCM_OFF; rdpcmNxN(tu, compID, cQP, uiAbsSum, rdpcmMode); @@ -593,7 +776,7 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q #if JVET_M0464_UNI_MTS if( !loadTr ) { - if( tu.mtsIdx == 1 ) + if( isLuma(compID) && tu.mtsIdx == 1 ) #else if( tu.transformSkip[compID] ) #endif @@ -608,6 +791,20 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + //we do this only with the DCT-II coefficients + if( isLuma(compID) && +#if JVET_M0464_UNI_MTS + !loadTr && tu.mtsIdx == 0 +#else + !tu.cu->emtFlag +#endif + ) + { + //it gets the distribution of the coefficients energy, which will be useful to discard ISP tests + xGetCoeffEnergy( tu, compID, tempCoeff, diagRatio, horVerRatio ); + } +#endif DTRACE_COEFF_BUF( D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID ); xQuant( tu, compID, tempCoeff, uiAbsSum, cQP, ctx ); @@ -620,6 +817,43 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q TU::setCbfAtDepth (tu, compID, tu.depth, uiAbsSum > 0); } +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, const CoeffBuf& coeffs, double* diagRatio, double* horVerRatio ) +{ + if( nullptr == diagRatio || nullptr == horVerRatio ) return; + + if( tu.cu->predMode == MODE_INTRA && !tu.cu->ispMode && isLuma( compID ) && CU::canUseISPSplit( *tu.cu, compID ) != NOT_INTRA_SUBPARTITIONS ) + { + const int width = tu.cu->blocks[compID].width; + const int height = tu.cu->blocks[compID].height; + const int log2Sl = width <= height ? g_aucLog2[height >> g_aucLog2[width]] : g_aucLog2[width >> g_aucLog2[height]]; + const int diPos1 = width <= height ? width : height; + const int diPos2 = width <= height ? height : width; + const int ofsPos1 = width <= height ? 1 : coeffs.stride; + const int ofsPos2 = width <= height ? coeffs.stride : 1; + + int wdtE = 0, hgtE = 0, diaE = 0; + int* gtE = width <= height ? &wdtE : &hgtE; + int* stE = width <= height ? &hgtE : &wdtE; + + for( int pos1 = 0; pos1 < diPos1; pos1++ ) + { + const int posN = pos1 << log2Sl; + for( int pos2 = 0; pos2 < diPos2; pos2++ ) + { + const int blkP = pos1 * ofsPos1 + pos2 * ofsPos2; + if( posN > pos2 ) *gtE += abs( coeffs.buf[ blkP ] ); + if( posN < pos2 ) *stE += abs( coeffs.buf[ blkP ] ); + if( posN == pos2 ) diaE += abs( coeffs.buf[ blkP ] ); + } + } + + *horVerRatio = 0 == wdtE && 0 == hgtE ? 1 : double( wdtE ) / double( hgtE ); + *diagRatio = 0 == wdtE && 0 == hgtE && 0 == diaE ? 1 : double( diaE ) / double( wdtE + hgtE ); + } +} +#endif + void TrQuant::applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &mode) { const bool bLossless = tu.cu->transQuantBypass; @@ -762,7 +996,7 @@ void TrQuant::xTransformSkip(const TransformUnit &tu, const ComponentID &compID, } int iWHScale = 1; -#if HM_QTBT_AS_IN_JEM_QUANT +#if HM_QTBT_AS_IN_JEM_QUANT && !JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT if( TU::needsBlockSizeTrafoScale( rect ) ) { iTransformShift -= ADJ_DEQUANT_SHIFT; diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h index aa58a29981b7f6a8ac09601972a487a8811cc6f5..9f477ea9f9d853e531634673a3396d6054008b6d 100644 --- a/source/Lib/CommonLib/TrQuant.h +++ b/source/Lib/CommonLib/TrQuant.h @@ -88,10 +88,19 @@ public: void invTransformNxN (TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQPs); #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio = nullptr, double* horVerRatio = nullptr ); + void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr = false, double* diagRatio = nullptr, double* horVerRatio = nullptr ); +#else void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand); void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr=false); +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, double* diagRatio = nullptr, double* horVerRatio = nullptr); #else void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx); +#endif #endif void rdpcmNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, RDPCMMode &rdpcmMode); void applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &rdpcmMode); @@ -157,6 +166,14 @@ private: const TransformUnit &tu, const ComponentID &component); +#if JVET_M0102_INTRA_SUBPARTITIONS + void xGetCoeffEnergy( + TransformUnit &tu, + const ComponentID &compID, + const CoeffBuf &coeffs, + double* diagRatio, + double* horVerRatio ); +#endif #ifdef TARGET_SIMD_X86 template<X86_VEXT vext> diff --git a/source/Lib/CommonLib/TrQuant_EMT.cpp b/source/Lib/CommonLib/TrQuant_EMT.cpp index 3ea8ce7306e663478e28f20dfac2a5251e1b70ba..d12b5c39221667729b53ddf14ff502b3ded960d9 100644 --- a/source/Lib/CommonLib/TrQuant_EMT.cpp +++ b/source/Lib/CommonLib/TrQuant_EMT.cpp @@ -1018,7 +1018,7 @@ void fastInverseDST7_B16(const TCoeff *src, TCoeff *dst, int shift, int line, in #if JVET_M0497_FAST_DST7 && !JVET_M0497_MATRIX_MULT int j, k; TCoeff a[5], b[5], c[5], d[5], t; - + TCoeff add = (shift > 0) ? (1 << (shift - 1)) : 0; const TMatrixCoeff *iT = g_trCoreDST7P16[TRANSFORM_INVERSE][0]; @@ -1208,7 +1208,7 @@ void fastInverseDST7_B32(const TCoeff *src, TCoeff *dst, int shift, int line, in t[0] = iT[12] * src[6*line] + iT[25] * src[19*line]; t[1] = iT[25] * src[6*line] - iT[12] * src[19*line]; - + dst[ 0] = Clip3(outputMinimum, outputMaximum, (int)( iT[0] * a[1][0] - iT[11] * a[8][0] + iT[13] * a[7][0] + iT[24] * a[4][5] - iT[1] * a[8][5] + iT[10] * a[1][5] + iT[14] * a[4][0] + iT[23] * a[7][5] + iT[2] * a[1][1] - iT[9] * a[8][1] + iT[15] * a[7][1] + iT[22] * a[4][4] - iT[3] * a[8][4] + iT[8] * a[1][4] + iT[16] * a[4][1] + iT[21] * a[7][4] + iT[4] * a[1][2] - iT[7] * a[8][2] + iT[17] * a[7][2] + iT[20] * a[4][3] - iT[5] * a[8][3] + iT[6] * a[1][3] + iT[18] * a[4][2] + iT[19] * a[7][3] + t[0] + add) >> shift); dst[ 1] = Clip3(outputMinimum, outputMaximum, (int)(-iT[0] * a[4][2] - iT[11] * a[6][2] + iT[13] * a[0][3] + iT[24] * a[5][2] + iT[1] * a[2][0] + iT[10] * a[7][0] + iT[14] * a[5][5] - iT[23] * a[9][5] + iT[2] * a[7][2] + iT[9] * a[2][2] - iT[15] * a[9][3] + iT[22] * a[5][3] - iT[3] * a[6][0] - iT[8] * a[4][0] + iT[16] * a[5][0] + iT[21] * a[0][5] - iT[4] * a[4][1] - iT[7] * a[6][1] + iT[17] * a[0][4] + iT[20] * a[5][1] + iT[5] * a[2][1] + iT[6] * a[7][1] + iT[18] * a[5][4] - iT[19] * a[9][4] + t[1] + add) >> shift); dst[ 2] = Clip3(outputMinimum, outputMaximum, (int)(-iT[0] * a[2][4] - iT[11] * a[3][4] + iT[13] * a[0][4] + iT[24] * a[1][4] + iT[1] * a[4][3] + iT[10] * a[7][2] + iT[14] * a[1][2] - iT[23] * a[8][2] + iT[2] * a[3][0] - iT[9] * a[6][5] - iT[15] * a[8][0] + iT[22] * a[9][5] - iT[3] * a[6][4] + iT[8] * a[3][1] + iT[16] * a[9][4] - iT[21] * a[8][1] + iT[4] * a[7][3] + iT[7] * a[4][2] - iT[17] * a[8][3] + iT[20] * a[1][3] - iT[5] * a[3][5] - iT[6] * a[2][5] + iT[18] * a[1][5] + iT[19] * a[0][5] + t[1] + add) >> shift); @@ -1240,7 +1240,7 @@ void fastInverseDST7_B32(const TCoeff *src, TCoeff *dst, int shift, int line, in dst[19] = Clip3(outputMinimum, outputMaximum, (int)(iT[19] * b[0] + iT[ 4] * b[1] - iT[29] * b[2] + iT[ 9] * b[3] + iT[14] * b[4] - iT[24] * b[5] + add) >> shift); dst[24] = Clip3(outputMinimum, outputMaximum, (int)(iT[24] * b[0] - iT[ 9] * b[1] - iT[ 4] * b[2] + iT[19] * b[3] - iT[29] * b[4] + iT[14] * b[5] + add) >> shift); dst[29] = Clip3(outputMinimum, outputMaximum, (int)(iT[29] * b[0] - iT[24] * b[1] + iT[19] * b[2] - iT[14] * b[3] + iT[ 9] * b[4] - iT[ 4] * b[5] + add) >> shift); - + dst[12] = Clip3(outputMinimum, outputMaximum, (int)(iT[12]*c[0] + iT[25]*c[1] + add) >> shift); dst[25] = Clip3(outputMinimum, outputMaximum, (int)(iT[25]*c[0] - iT[12]*c[1] + add) >> shift); @@ -1411,7 +1411,7 @@ void fastInverseDCT8_B16(const TCoeff *src, TCoeff *dst, int shift, int line, in #if JVET_M0497_FAST_DST7 && !JVET_M0497_MATRIX_MULT int j, k; TCoeff a[5], b[5], c[5], d[5], t; - + TCoeff add = (shift > 0) ? (1 << (shift - 1)) : 0; const TMatrixCoeff *iT = g_trCoreDST7P16[TRANSFORM_INVERSE][0]; @@ -1495,14 +1495,14 @@ void fastForwardDCT8_B32(const TCoeff *src, TCoeff *dst, int shift, int line, in b[k] = src[31-k] + src[20+k] - src[18-k] - src[7+k] + src[5-k]; } - + for (k = 0; k < 2; k++) { c[k] = src[31-k] + src[28+k] - src[26-k] - src[23+k] + src[21-k] + src[18+k] - src[16-k] - src[13+k] + src[11-k] + src[8+k] - src[6-k] - src[3+k] + src[1-k]; } - - t[0] = iT[12] * src[19] + iT[25] * src[6]; - t[1] = iT[12] * src[6] - iT[25] * src[19]; + + t[0] = iT[12] * src[19] + iT[25] * src[6]; + t[1] = iT[12] * src[6] - iT[25] * src[19]; dst[ 0 * line] = ( iT[0] * a[3][0] + iT[11] * a[6][5] + iT[13] * a[8][0] + iT[24] * a[9][5] + iT[1] * a[3][1] + iT[10] * a[6][4] + iT[14] * a[8][1] + iT[23] * a[9][4] + iT[2] * a[3][2] + iT[9] * a[6][3] + iT[15] * a[8][2] + iT[22] * a[9][3] + iT[3] * a[3][3] + iT[8] * a[6][2] + iT[16] * a[8][3] + iT[21] * a[9][2] + iT[4] * a[3][4] + iT[7] * a[6][1] + iT[17] * a[8][4] + iT[20] * a[9][1] + iT[5] * a[3][5] + iT[6] * a[6][0] + iT[18] * a[8][5] + iT[19] * a[9][0] + t[0] + add) >> shift; dst[ 1 * line] = ( iT[0] * a[5][2] - iT[11] * a[0][3] - iT[13] * a[4][2] - iT[24] * a[6][2] - iT[1] * a[9][1] - iT[10] * a[8][4] - iT[14] * a[3][4] - iT[23] * a[6][1] - iT[2] * a[0][0] + iT[9] * a[5][5] - iT[15] * a[6][5] - iT[22] * a[4][5] + iT[3] * a[5][3] - iT[8] * a[0][2] - iT[16] * a[4][3] - iT[21] * a[6][3] - iT[4] * a[9][0] - iT[7] * a[8][5] - iT[17] * a[3][5] - iT[20] * a[6][0] - iT[5] * a[0][1] + iT[6] * a[5][4] - iT[18] * a[6][4] - iT[19] * a[4][4] + t[1] + add) >> shift; @@ -1535,7 +1535,7 @@ void fastForwardDCT8_B32(const TCoeff *src, TCoeff *dst, int shift, int line, in dst[17 * line] = ( - iT[29] * b[0] + iT[ 4] * b[1] + iT[24] * b[2] - iT[ 9] * b[3] - iT[19] * b[4] + iT[14] * b[5] + add) >> shift; dst[22 * line] = ( iT[19] * b[0] - iT[24] * b[1] + iT[ 4] * b[2] + iT[14] * b[3] - iT[29] * b[4] + iT[ 9] * b[5] + add) >> shift; dst[27 * line] = ( - iT[ 9] * b[0] + iT[19] * b[1] - iT[29] * b[2] + iT[24] * b[3] - iT[14] * b[4] + iT[ 4] * b[5] + add) >> shift; - + dst[ 6 * line] = ( iT[12] * c[0] + iT[25] * c[1] + add) >> shift; dst[19 * line] = ( - iT[25] * c[0] + iT[12] * c[1] + add) >> shift; @@ -1600,8 +1600,8 @@ void fastInverseDCT8_B32(const TCoeff *src, TCoeff *dst, int shift, int line, in c[k] = src[(31 - k)*line] + src[(28 + k)*line] - src[(26 - k)*line] - src[(23 + k)*line] + src[(21 - k)*line] + src[(18 + k)*line] - src[(16 - k)*line] - src[(13 + k)*line] + src[(11 - k)*line] + src[(8 + k)*line] - src[(6 - k)*line] - src[(3 + k)*line] + src[(1 - k)*line]; } - t[0] = iT[12] * src[19 * line] + iT[25] * src[ 6 * line]; - t[1] = iT[12] * src[ 6 * line] - iT[25] * src[19 * line]; + t[0] = iT[12] * src[19 * line] + iT[25] * src[ 6 * line]; + t[1] = iT[12] * src[ 6 * line] - iT[25] * src[19 * line]; dst[ 0] = Clip3(outputMinimum, outputMaximum, (int)( iT[0] * a[3][0] + iT[11] * a[6][5] + iT[13] * a[8][0] + iT[24] * a[9][5] + iT[1] * a[3][1] + iT[10] * a[6][4] + iT[14] * a[8][1] + iT[23] * a[9][4] + iT[2] * a[3][2] + iT[9] * a[6][3] + iT[15] * a[8][2] + iT[22] * a[9][3] + iT[3] * a[3][3] + iT[8] * a[6][2] + iT[16] * a[8][3] + iT[21] * a[9][2] + iT[4] * a[3][4] + iT[7] * a[6][1] + iT[17] * a[8][4] + iT[20] * a[9][1] + iT[5] * a[3][5] + iT[6] * a[6][0] + iT[18] * a[8][5] + iT[19] * a[9][0] + t[0] + add) >> shift); dst[ 1] = Clip3(outputMinimum, outputMaximum, (int)( iT[0] * a[5][2] - iT[11] * a[0][3] - iT[13] * a[4][2] - iT[24] * a[6][2] - iT[1] * a[9][1] - iT[10] * a[8][4] - iT[14] * a[3][4] - iT[23] * a[6][1] - iT[2] * a[0][0] + iT[9] * a[5][5] - iT[15] * a[6][5] - iT[22] * a[4][5] + iT[3] * a[5][3] - iT[8] * a[0][2] - iT[16] * a[4][3] - iT[21] * a[6][3] - iT[4] * a[9][0] - iT[7] * a[8][5] - iT[17] * a[3][5] - iT[20] * a[6][0] - iT[5] * a[0][1] + iT[6] * a[5][4] - iT[18] * a[6][4] - iT[19] * a[4][4] + t[1] + add) >> shift); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 7e15e14992f67adeb9ea2d1d6e8c0f46e1cda2e2..46832b51cc8356467ff4f5d2cf55fff7a812dee3 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,50 @@ #include <assert.h> #include <cassert> +#define JVET_M0055_DEBUG_CTU 1 // DebugCTU encoder debug option + +#define JVET_M0297_32PT_MTS_ZERO_OUT 1 // 32 point MTS based on skipping high frequency coefficients + +#define JVET_M0126_HMVP_MRG_PRUNING 1 // HMVP merge candidates pruning simplification + +#define JVET_M0483_IBC 1 // Block level flag signaling and independent IBC mode + +#define JVET_M0102_INTRA_SUBPARTITIONS 1 + +#define JVET_M0303_IMPLICIT_MTS 1 // Implicit transform selection (can be enabled with MTSImplicit encoder config parameter) + +#define FIX_DB_MAX_TRANSFORM_SIZE 1 +#define JVET_M0908_CIIP_DB 1 +#define JVET_M0471_LONG_DEBLOCKING_FILTERS 1 +#define JVET_M0427_INLOOP_RESHAPER 1 +#define JVET_M0470 1 // Fixed GR/TU+EG-k transition point, use limited prefix length for escape codes + +#define JVET_M0253_HASH_ME 1 + +#define JVET_M0257 1 // Scan only non zero-out regions of large TUs +#define JVET_M0193_PAIR_AVG_REDUCTION 1 //Use only one pairwise average candidate + +#define JVET_M0281_AMVP_ROUNDING 1 // Perform all AMVP rounding before pruning even AMVR is off + +#define JVET_M0117_AMVP_LIST_GEN 1 // AMVP candidate list generation simplification + +#define JVET_M0192_AFF_CHROMA_SIMPL 1 // Affine chroma MV derivation simplification and rounding unification + +#define JVET_M0116_ATMVP_LEFT_NB_FOR_OFFSET 1 // Only use left neighbor for ATMVP offset derivation, from M0273, M0240, M0116, M0338, M0204 + +#define JVET_M0063_BDOF_FIX 1 // BDOF bitdepth bugfix + +#define JVET_M0265_MV_ROUNDING_CLEANUP 1 // Unify MV roundings and make SW/WD allignment +#define JVET_M0883_TRIANGLE_SIGNALING 1 // Using regular merge index signaling for triangle mode + +#define JVET_M0228_REMOVE_CPMV_COMPARE 1 // Remove CPMV comparisons for construnted affine merge candidates from JVET-M0228, M0166, M0477 + +#define JVET_M0145_AFFINE_MV_CLIP 1 // Missing clipping for MV storage in affine + +#define JVET_M0264_HMVP_WITH_GBIIDX 1 // Harmonization between HMVP and GBi + +#define JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX 1 // CE2.2.2 a: one context for subblock Merge index + #define JVET_M0118_M0185_TRIANGLE_FLAG_FIX 1 // Avoid signaling triangle flag if a CU uses MMVD or CIIP #define JVET_M0487_INT_EXTEND 1 // CE9.1.1 b: integer reference samples as 1 extended samples @@ -65,6 +109,7 @@ #define JVET_M0142_CCLM_COLLOCATED_CHROMA 1 // Adding support for chroma sample location type 2 in CCLM +#define JVET_M0328_KEEP_ONE_WEIGHT_GROUP 1 #define JVET_M0479_18BITS_MV_CLIP 1 @@ -74,31 +119,52 @@ #endif #define JVET_M0502_PRED_MODE_CTX 1 +#define JVET_M0140_SBT 1 // Sub-Block transform for Inter blocks +#if JVET_M0140_SBT +#define APPLY_SBT_SL_ON_MTS 1 // apply save & load fast algorithm on inter MTS when SBT is on +#endif + #define JVET_M0407_IBC_RANGE 1 // extend IBC search range to some part of left CTU #define JVET_M0464_UNI_MTS 1 #define JVET_M0068_M0171_MMVD_CLEANUP 1 // MMVD cleanup with 1) flip removal, 2) L1 zero vector fix, 3) bi-pred restriction after merge/MMVD +#define JVET_M0255_FRACMMVD_SWITCH 1 // disable fractional MVD in MMVD adaptively +#define JVET_M0854_FRACMMVD_SWITCH_FOR_UHD 1 // disable fractional MVD for UHD pictures +#define JVET_M0823_MMVD_ENCOPT 1 // encoder optimization for MMVD + +#define JVET_M0147_DMVR 1 //Decoder side Motion Vector Refinement #if JVET_M0464_UNI_MTS typedef std::pair<int, bool> TrMode; typedef std::pair<int, int> TrCost; #endif +#define JVET_M0246_AFFINE_AMVR 1 +#if JVET_M0246_AFFINE_AMVR +#define JVET_M0247_AFFINE_AMVR_ENCOPT 1 +#endif #define JVET_M0421_SPLIT_SIG 1 #define JVET_M0173_MOVE_GT2_TO_FIRST_PASS 1 // Moving the gtr2 flag to the first coding pass #define REMOVE_BIN_DECISION_TREE 1 -#define JVET_M0446_M0888_M0905_VPDU_AT_PIC_BOUNDARY 1 +#define JVET_M0446_M0888_M0905_VPDU_AT_PIC_BOUNDARY 1 // clang-format off #define JVET_M0453_CABAC_ENGINE 1 +#define JVET_M0512_MOTION_BUFFER_COMPRESSION 1 +#define JVET_M0238_PDPC_NO_INTERPOLATION 1 #define JVET_M0409_ATMVP_FIX 1 +#define ENABLE_JVET_L0283_MRL 1 // 1: Enable MRL, 0: Disable MRL #define JVET_L0090_PAIR_AVG 1 // Add pairwise average candidates, replace HEVC combined candidates #define REUSE_CU_RESULTS 1 +#if REUSE_CU_RESULTS && JVET_M0102_INTRA_SUBPARTITIONS +#define REUSE_CU_RESULTS_WITH_MULTIPLE_TUS 1 +#define MAX_NUM_TUS 4 +#endif // clang-format on #ifndef JVET_B0051_NON_MPM_MODE @@ -148,24 +214,27 @@ typedef std::pair<int, int> TrCost; #ifndef ENABLE_TRACING #define ENABLE_TRACING 0 // DISABLE by default (enable only when debugging, requires 15% run-time in decoding) -- see documentation in 'doc/DTrace for NextSoftware.pdf' +#endif + #if ENABLE_TRACING #define K0149_BLOCK_STATISTICS 1 // enables block statistics, which can be analysed with YUView (https://github.com/IENT/YUView) #if K0149_BLOCK_STATISTICS #define BLOCK_STATS_AS_CSV 0 // statistics will be written in a comma separated value format. this is not supported by YUView #endif #endif -#endif // ! ENABLE_TRACING +#if JVET_M0427_INLOOP_RESHAPER +#define WCG_EXT 1 +#else #define WCG_EXT 0 // part of JEM sharp Luma qp +#endif #define WCG_WPSNR WCG_EXT #if HEVC_TOOLS #define HEVC_USE_INTRA_SMOOTHING_T32 1 #define HEVC_USE_INTRA_SMOOTHING_T64 1 -#define JEM_USE_INTRA_BOUNDARY 1 #define HEVC_USE_DC_PREDFILTERING 1 #define HEVC_USE_HOR_VER_PREDFILTERING 1 -#define HEVC_USE_4x4_DSTVII 1 #define HEVC_USE_MDCS 1 #define HEVC_USE_SIGN_HIDING 1 #define HEVC_USE_SCALING_LISTS 1 @@ -192,6 +261,8 @@ typedef std::pair<int, int> TrCost; #define HM_JEM_CLIP_PEL 1 // *** #define HM_JEM_MERGE_CANDS 0 // *** +#define JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT 1 ///< When 1, do not scale transform skip blocks by sqrt(2) between (I)Transform and (I)Quantizer + #endif//JEM_COMP // ==================================================================================================================== @@ -248,7 +319,7 @@ typedef std::pair<int, int> TrCost; #define ENABLE_SIMD_OPT_AFFINE_ME ( 1 && ENABLE_SIMD_OPT ) ///< SIMD optimization for affine ME, no impact on RD performance #define ENABLE_SIMD_OPT_ALF ( 1 && ENABLE_SIMD_OPT ) ///< SIMD optimization for ALF #if ENABLE_SIMD_OPT_BUFFER -#define ENABLE_SIMD_OPT_GBI 1 ///< SIMD optimization for GBi +#define ENABLE_SIMD_OPT_GBI 1 ///< SIMD optimization for GBi #endif // End of SIMD optimizations @@ -348,6 +419,50 @@ enum TransType DCT2_EMT = 4 }; +#if JVET_M0102_INTRA_SUBPARTITIONS +enum ISPType +{ + NOT_INTRA_SUBPARTITIONS = 0, + HOR_INTRA_SUBPARTITIONS = 1, + VER_INTRA_SUBPARTITIONS = 2, + NUM_INTRA_SUBPARTITIONS_MODES = 3, + CAN_USE_VER_AND_HORL_SPLITS = 4 +}; +#endif + +#if JVET_M0140_SBT +enum SbtIdx +{ + SBT_OFF_DCT = 0, + SBT_VER_HALF = 1, + SBT_HOR_HALF = 2, + SBT_VER_QUAD = 3, + SBT_HOR_QUAD = 4, + NUMBER_SBT_IDX, + SBT_OFF_MTS, //note: must be after all SBT modes, only used in fast algorithm to discern the best mode is inter EMT +}; + +enum SbtPos +{ + SBT_POS0 = 0, + SBT_POS1 = 1, + NUMBER_SBT_POS +}; + +enum SbtMode +{ + SBT_VER_H0 = 0, + SBT_VER_H1 = 1, + SBT_HOR_H0 = 2, + SBT_HOR_H1 = 3, + SBT_VER_Q0 = 4, + SBT_VER_Q1 = 5, + SBT_HOR_Q0 = 6, + SBT_HOR_Q1 = 7, + NUMBER_SBT_MODE +}; +#endif + enum RDPCMMode { RDPCM_OFF = 0, @@ -439,7 +554,12 @@ enum PredMode { MODE_INTER = 0, ///< inter-prediction mode MODE_INTRA = 1, ///< intra-prediction mode +#if JVET_M0483_IBC + MODE_IBC = 2, ///< ibc-prediction mode + NUMBER_OF_PREDICTION_MODES = 3, +#else NUMBER_OF_PREDICTION_MODES = 2, +#endif }; /// reference list index @@ -883,7 +1003,7 @@ enum MergeType { MRG_TYPE_DEFAULT_N = 0, // 0 MRG_TYPE_SUBPU_ATMVP, - MRG_TYPE_IBC, + MRG_TYPE_IBC, NUM_MRG_TYPE // 5 }; @@ -1116,6 +1236,15 @@ enum MsgLevel VERBOSE = 5, DETAILS = 6 }; +#if JVET_M0427_INLOOP_RESHAPER +enum RESHAPE_SIGNAL_TYPE +{ + RESHAPE_SIGNAL_SDR = 0, + RESHAPE_SIGNAL_PQ = 1, + RESHAPE_SIGNAL_HLG = 2, + RESHAPE_SIGNAL_NULL = 100, +}; +#endif // --------------------------------------------------------------------------- @@ -1458,10 +1587,10 @@ struct AlfSliceParam short lumaCoeff[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_coeff_luma_delta[i][j] short chromaCoeff[MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i] short filterCoeffDeltaIdx[MAX_NUM_ALF_CLASSES]; // filter_coeff_delta[i] - bool filterCoeffFlag[MAX_NUM_ALF_CLASSES]; // filter_coefficient_flag[i] + bool alfLumaCoeffFlag[MAX_NUM_ALF_CLASSES]; // alf_luma_coeff_flag[i] int numLumaFilters; // number_of_filters_minus1 + 1 - bool coeffDeltaFlag; // alf_coefficients_delta_flag - bool coeffDeltaPredModeFlag; // coeff_delta_pred_mode_flag + bool alfLumaCoeffDeltaFlag; // alf_luma_coeff_delta_flag + bool alfLumaCoeffDeltaPredictionFlag; // alf_luma_coeff_delta_prediction_flag std::vector<AlfFilterShape>* filterShapes; void reset() @@ -1470,10 +1599,10 @@ struct AlfSliceParam std::memset( lumaCoeff, 0, sizeof( lumaCoeff ) ); std::memset( chromaCoeff, 0, sizeof( chromaCoeff ) ); std::memset( filterCoeffDeltaIdx, 0, sizeof( filterCoeffDeltaIdx ) ); - std::memset( filterCoeffFlag, true, sizeof( filterCoeffFlag ) ); + std::memset( alfLumaCoeffFlag, true, sizeof( alfLumaCoeffFlag ) ); numLumaFilters = 1; - coeffDeltaFlag = false; - coeffDeltaPredModeFlag = false; + alfLumaCoeffDeltaFlag = false; + alfLumaCoeffDeltaPredictionFlag = false; } const AlfSliceParam& operator = ( const AlfSliceParam& src ) @@ -1482,10 +1611,10 @@ struct AlfSliceParam std::memcpy( lumaCoeff, src.lumaCoeff, sizeof( lumaCoeff ) ); std::memcpy( chromaCoeff, src.chromaCoeff, sizeof( chromaCoeff ) ); std::memcpy( filterCoeffDeltaIdx, src.filterCoeffDeltaIdx, sizeof( filterCoeffDeltaIdx ) ); - std::memcpy( filterCoeffFlag, src.filterCoeffFlag, sizeof( filterCoeffFlag ) ); + std::memcpy( alfLumaCoeffFlag, src.alfLumaCoeffFlag, sizeof( alfLumaCoeffFlag ) ); numLumaFilters = src.numLumaFilters; - coeffDeltaFlag = src.coeffDeltaFlag; - coeffDeltaPredModeFlag = src.coeffDeltaPredModeFlag; + alfLumaCoeffDeltaFlag = src.alfLumaCoeffDeltaFlag; + alfLumaCoeffDeltaPredictionFlag = src.alfLumaCoeffDeltaPredictionFlag; filterShapes = src.filterShapes; return *this; } diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index ecaf89ca16990d33b31fcee0e1c6c86d1e0c0d15..aed894214e8ef54511e2fa2b3df9679bff5ae53e 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -189,6 +189,16 @@ bool UnitArea::contains( const UnitArea& other, const ChannelType chType ) const return any && ret; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS +void UnitArea::resizeTo( const UnitArea& unitArea ) +{ + for( uint32_t i = 0; i < blocks.size(); i++ ) + { + blocks[i].resizeTo( unitArea.blocks[i] ); + } +} +#endif + void UnitArea::repositionTo(const UnitArea& unitArea) { for(uint32_t i = 0; i < blocks.size(); i++) @@ -261,6 +271,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) qp = other.qp; chromaQpAdj = other.chromaQpAdj; rootCbf = other.rootCbf; +#if JVET_M0140_SBT + sbtInfo = other.sbtInfo; +#endif #if !JVET_M0464_UNI_MTS emtFlag = other.emtFlag; #endif @@ -277,11 +290,15 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) shareParentPos = other.shareParentPos; shareParentSize = other.shareParentSize; #endif +#if JVET_M0483_IBC==0 ibc = other.ibc; +#endif #if JVET_M0444_SMVD smvdMode = other.smvdMode; #endif - +#if JVET_M0102_INTRA_SUBPARTITIONS + ispMode = other.ispMode; +#endif return *this; } @@ -303,6 +320,9 @@ void CodingUnit::initData() qp = 0; chromaQpAdj = 0; rootCbf = true; +#if JVET_M0140_SBT + sbtInfo = 0; +#endif #if !JVET_M0464_UNI_MTS emtFlag = 0; #endif @@ -319,12 +339,85 @@ void CodingUnit::initData() shareParentSize.width = -1; shareParentSize.height = -1; #endif +#if JVET_M0483_IBC==0 ibc = false; +#endif #if JVET_M0444_SMVD smvdMode = 0; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + ispMode = 0; +#endif +} + +#if JVET_M0140_SBT +const uint8_t CodingUnit::checkAllowedSbt() const +{ + if( !slice->getSPS()->getUseSBT() ) + { + return 0; + } + + //check on prediction mode +#if JVET_M0483_IBC + if( predMode == MODE_INTRA || predMode == MODE_IBC ) //intra or IBC +#else + if( predMode == MODE_INTRA || ibc ) //intra or IBC +#endif + { + return 0; + } + if( firstPU->mhIntraFlag ) + { + return 0; + } + + uint8_t sbtAllowed = 0; + int cuWidth = lwidth(); + int cuHeight = lheight(); + bool allow_type[NUMBER_SBT_IDX]; + memset( allow_type, false, NUMBER_SBT_IDX * sizeof( bool ) ); + + //parameter + int maxSbtCUSize = cs->sps->getMaxSbtSize(); + int minSbtCUSize = 1 << ( MIN_CU_LOG2 + 1 ); + + //check on size + if( cuWidth > maxSbtCUSize || cuHeight > maxSbtCUSize ) + { + return 0; + } + + allow_type[SBT_VER_HALF] = cuWidth >= minSbtCUSize; + allow_type[SBT_HOR_HALF] = cuHeight >= minSbtCUSize; + allow_type[SBT_VER_QUAD] = cuWidth >= ( minSbtCUSize << 1 ); + allow_type[SBT_HOR_QUAD] = cuHeight >= ( minSbtCUSize << 1 ); + + for( int i = 0; i < NUMBER_SBT_IDX; i++ ) + { + sbtAllowed += (uint8_t)allow_type[i] << i; + } + + return sbtAllowed; } +uint8_t CodingUnit::getSbtTuSplit() const +{ + uint8_t sbtTuSplitType = 0; + + switch( getSbtIdx() ) + { + case SBT_VER_HALF: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_VER_HALF_POS0_SPLIT; break; + case SBT_HOR_HALF: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_HOR_HALF_POS0_SPLIT; break; + case SBT_VER_QUAD: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_VER_QUAD_POS0_SPLIT; break; + case SBT_HOR_QUAD: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_HOR_QUAD_POS0_SPLIT; break; + default: assert( 0 ); break; + } + + assert( sbtTuSplitType <= SBT_HOR_QUAD_POS1_SPLIT && sbtTuSplitType >= SBT_VER_HALF_POS0_SPLIT ); + return sbtTuSplitType; +} +#endif // --------------------------------------------------------------------------- // prediction unit method definitions @@ -343,12 +436,24 @@ void PredictionUnit::initData() // inter data mergeFlag = false; mergeIdx = MAX_UCHAR; +#if JVET_M0883_TRIANGLE_SIGNALING + triangleSplitDir = MAX_UCHAR; + triangleMergeIdx0 = MAX_UCHAR; + triangleMergeIdx1 = MAX_UCHAR; +#endif mmvdMergeFlag = false; mmvdMergeIdx = MAX_UINT; interDir = MAX_UCHAR; mergeType = MRG_TYPE_DEFAULT_N; bv.setZero(); bvd.setZero(); +#if JVET_M0147_DMVR + mvRefine = false; + for (uint32_t i = 0; i < MAX_NUM_SUBCU_DMVR; i++) + { + mvdL0SubPu[i].setZero(); + } +#endif for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) { mvpIdx[i] = MAX_UCHAR; @@ -371,6 +476,9 @@ void PredictionUnit::initData() shareParentSize.width = -1; shareParentSize.height = -1; #endif +#if JVET_M0823_MMVD_ENCOPT + mmvdEncOptMode = 0; +#endif } PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) @@ -388,12 +496,24 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData) { mergeFlag = predData.mergeFlag; mergeIdx = predData.mergeIdx; +#if JVET_M0883_TRIANGLE_SIGNALING + triangleSplitDir = predData.triangleSplitDir ; + triangleMergeIdx0 = predData.triangleMergeIdx0 ; + triangleMergeIdx1 = predData.triangleMergeIdx1 ; +#endif mmvdMergeFlag = predData.mmvdMergeFlag; mmvdMergeIdx = predData.mmvdMergeIdx; interDir = predData.interDir; mergeType = predData.mergeType; bv = predData.bv; bvd = predData.bvd; +#if JVET_M0147_DMVR + mvRefine = predData.mvRefine; + for (uint32_t i = 0; i < MAX_NUM_SUBCU_DMVR; i++) + { + mvdL0SubPu[i] = predData.mvdL0SubPu[i]; + } +#endif for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) { mvpIdx[i] = predData.mvpIdx[i]; @@ -428,12 +548,24 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) mergeFlag = other.mergeFlag; mergeIdx = other.mergeIdx; +#if JVET_M0883_TRIANGLE_SIGNALING + triangleSplitDir = other.triangleSplitDir ; + triangleMergeIdx0 = other.triangleMergeIdx0 ; + triangleMergeIdx1 = other.triangleMergeIdx1 ; +#endif mmvdMergeFlag = other.mmvdMergeFlag; mmvdMergeIdx = other.mmvdMergeIdx; interDir = other.interDir; mergeType = other.mergeType; bv = other.bv; bvd = other.bvd; +#if JVET_M0147_DMVR + mvRefine = other.mvRefine; + for (uint32_t i = 0; i < MAX_NUM_SUBCU_DMVR; i++) + { + mvdL0SubPu[i] = other.mvdL0SubPu[i]; + } +#endif for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) { mvpIdx[i] = other.mvpIdx[i]; @@ -536,6 +668,12 @@ void TransformUnit::initData() #else emtIdx = 0; #endif +#if JVET_M0140_SBT + noResidual = false; +#endif +#if JVET_M0427_INLOOP_RESHAPER + m_chromaResScaleInv = 0; +#endif } void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf) @@ -575,6 +713,9 @@ TransformUnit& TransformUnit::operator=(const TransformUnit& other) mtsIdx = other.mtsIdx; #else emtIdx = other.emtIdx; +#endif +#if JVET_M0140_SBT + noResidual = other.noResidual; #endif return *this; } @@ -606,6 +747,9 @@ void TransformUnit::copyComponentFrom(const TransformUnit& other, const Componen emtIdx = other.emtIdx; } #endif +#if JVET_M0140_SBT + noResidual = other.noResidual; +#endif } CoeffBuf TransformUnit::getCoeffs(const ComponentID id) { return CoeffBuf(m_coeffs[id], blocks[id]); } @@ -613,3 +757,22 @@ const CCoeffBuf TransformUnit::getCoeffs(const ComponentID id) const { return CC PelBuf TransformUnit::getPcmbuf(const ComponentID id) { return PelBuf (m_pcmbuf[id], blocks[id]); } const CPelBuf TransformUnit::getPcmbuf(const ComponentID id) const { return CPelBuf (m_pcmbuf[id], blocks[id]); } + +#if JVET_M0140_SBT +void TransformUnit::checkTuNoResidual( unsigned idx ) +{ + if( CU::getSbtIdx( cu->sbtInfo ) == SBT_OFF_DCT ) + { + return; + } + + if( ( CU::getSbtPos( cu->sbtInfo ) == SBT_POS0 && idx == 1 ) || ( CU::getSbtPos( cu->sbtInfo ) == SBT_POS1 && idx == 0 ) ) + { + noResidual = true; + } +} +#endif +#if JVET_M0427_INLOOP_RESHAPER +int TransformUnit::getChromaAdj() const { return m_chromaResScaleInv; } +void TransformUnit::setChromaAdj(int i) { m_chromaResScaleInv = i; } +#endif \ No newline at end of file diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 4eb057dde4a9cfe99bc1f4970d4f1e29e9f9613d..ad4eee3b5e29daff548f36e0869ff58db1341cb7 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -153,6 +153,9 @@ struct CompArea : public Area const bool operator!=(const CompArea &other) const { return !(operator==(other)); } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo (const Size& newSize) { Size::resizeTo(newSize); } +#endif void repositionTo (const Position& newPos) { Position::repositionTo(newPos); } void positionRelativeTo(const CompArea& origCompArea) { Position::relativeTo(origCompArea); } @@ -214,6 +217,9 @@ struct UnitArea return true; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo (const UnitArea& unit); +#endif void repositionTo(const UnitArea& unit); const bool operator!=(const UnitArea &other) const { return !(*this == other); } @@ -302,6 +308,9 @@ struct CodingUnit : public UnitArea bool ipcm; uint8_t imv; bool rootCbf; +#if JVET_M0140_SBT + uint8_t sbtInfo; +#endif #if HEVC_TILES_WPP uint32_t tileIdx; #endif @@ -316,10 +325,15 @@ struct CodingUnit : public UnitArea Position shareParentPos; Size shareParentSize; #endif +#if JVET_M0483_IBC ==0 bool ibc; +#endif #if JVET_M0444_SMVD uint8_t smvdMode; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + uint8_t ispMode; +#endif CodingUnit() : chType( CH_L ) { } CodingUnit(const UnitArea &unit); @@ -342,6 +356,14 @@ struct CodingUnit : public UnitArea int64_t cacheId; bool cacheUsed; #endif +#if JVET_M0140_SBT + const uint8_t getSbtIdx() const { assert( ( ( sbtInfo >> 0 ) & 0xf ) < NUMBER_SBT_IDX ); return ( sbtInfo >> 0 ) & 0xf; } + const uint8_t getSbtPos() const { return ( sbtInfo >> 4 ) & 0x3; } + void setSbtIdx( uint8_t idx ) { CHECK( idx >= NUMBER_SBT_IDX, "sbt_idx wrong" ); sbtInfo = ( idx << 0 ) + ( sbtInfo & 0xf0 ); } + void setSbtPos( uint8_t pos ) { CHECK( pos >= 4, "sbt_pos wrong" ); sbtInfo = ( pos << 4 ) + ( sbtInfo & 0xcf ); } + uint8_t getSbtTuSplit() const; + const uint8_t checkAllowedSbt() const; +#endif }; // --------------------------------------------------------------------------- @@ -358,6 +380,11 @@ struct InterPredictionData { bool mergeFlag; uint8_t mergeIdx; +#if JVET_M0883_TRIANGLE_SIGNALING + uint8_t triangleSplitDir; + uint8_t triangleMergeIdx0; + uint8_t triangleMergeIdx1; +#endif bool mmvdMergeFlag; uint32_t mmvdMergeIdx; uint8_t interDir; @@ -367,6 +394,10 @@ struct InterPredictionData Mv mv [NUM_REF_PIC_LIST_01]; int16_t refIdx [NUM_REF_PIC_LIST_01]; MergeType mergeType; +#if JVET_M0147_DMVR + bool mvRefine; + Mv mvdL0SubPu[MAX_NUM_SUBCU_DMVR]; +#endif Mv mvdAffi [NUM_REF_PIC_LIST_01][3]; Mv mvAffi[NUM_REF_PIC_LIST_01][3]; bool mhIntraFlag; @@ -377,6 +408,9 @@ struct InterPredictionData #endif Mv bv; // block vector for IBC Mv bvd; // block vector difference for IBC +#if JVET_M0823_MMVD_ENCOPT + uint8_t mmvdEncOptMode; // 0: no action 1: skip chroma MC for MMVD candidate pre-selection 2: skip chroma MC and BIO for MMVD candidate pre-selection +#endif }; struct PredictionUnit : public UnitArea, public IntraPredictionData, public InterPredictionData @@ -427,12 +461,18 @@ struct TransformUnit : public UnitArea CodingUnit *cu; CodingStructure *cs; ChannelType chType; + #if JVET_M0427_INLOOP_RESHAPER + int m_chromaResScaleInv; +#endif uint8_t depth; #if JVET_M0464_UNI_MTS uint8_t mtsIdx; #else uint8_t emtIdx; +#endif +#if JVET_M0140_SBT + bool noResidual; #endif uint8_t cbf [ MAX_NUM_TBLOCKS ]; RDPCMMode rdpcm [ MAX_NUM_TBLOCKS ]; @@ -449,16 +489,26 @@ struct TransformUnit : public UnitArea unsigned idx; TransformUnit *next; +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit *prev; +#endif void init(TCoeff **coeffs, Pel **pcmbuf); TransformUnit& operator=(const TransformUnit& other); void copyComponentFrom (const TransformUnit& other, const ComponentID compID); +#if JVET_M0140_SBT + void checkTuNoResidual( unsigned idx ); +#endif CoeffBuf getCoeffs(const ComponentID id); const CCoeffBuf getCoeffs(const ComponentID id) const; PelBuf getPcmbuf(const ComponentID id); const CPelBuf getPcmbuf(const ComponentID id) const; +#if JVET_M0427_INLOOP_RESHAPER + int getChromaAdj( ) const; + void setChromaAdj(int i); +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM int64_t cacheId; diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index dae0769736f028afa368c3d303d82047aeb09b0b..af9fce47a613a805cb6ec83779f7cc0f7811ab7c 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -139,14 +139,14 @@ void AdaptiveDepthPartitioner::setMaxMinDepth( unsigned& minDepth, unsigned& max const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( currArea().lumaPos() ); const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, curTileIdx, chType ); - const CodingUnit* cuBelowLeft = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, curTileIdx, chType ); + const CodingUnit* cuBelowLeft = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, curTileIdx, chType ); const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), curSliceIdx, curTileIdx, chType ); - const CodingUnit* cuAboveRight = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, curTileIdx, chType ); + const CodingUnit* cuAboveRight = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, curTileIdx, chType ); #else const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, chType ); const CodingUnit* cuBelowLeft = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, chType ); const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), curSliceIdx, chType ); - const CodingUnit* cuAboveRight = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, chType ); + const CodingUnit* cuAboveRight = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), curSliceIdx, chType ); #endif minDepth = stdMaxDepth; @@ -249,12 +249,23 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur break; case CU_TRIH_SPLIT: case CU_TRIV_SPLIT: - CHECK( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1, "Triple splits are not allowed" ); m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) ); break; case TU_MAX_TR_SPLIT: m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) ); break; +#if JVET_M0140_SBT + case SBT_VER_HALF_POS0_SPLIT: + case SBT_VER_HALF_POS1_SPLIT: + case SBT_HOR_HALF_POS0_SPLIT: + case SBT_HOR_HALF_POS1_SPLIT: + case SBT_VER_QUAD_POS0_SPLIT: + case SBT_VER_QUAD_POS1_SPLIT: + case SBT_HOR_QUAD_POS0_SPLIT: + case SBT_HOR_QUAD_POS1_SPLIT: + m_partStack.push_back( PartLevel( split, PartitionerImpl::getSbtTuTiling( currArea(), cs, split ) ) ); + break; +#endif default: THROW( "Unknown split mode" ); break; @@ -269,6 +280,12 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur { currTrDepth++; } +#if JVET_M0140_SBT + else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT ) + { + currTrDepth++; + } +#endif else { currTrDepth = 0; @@ -301,7 +318,7 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ) { const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs ); - + const unsigned maxBTD = cs.pcv->getMaxBtDepth( *cs.slice, chType ) + currImplicitBtDepth; const unsigned maxBtSize = cs.pcv->getMaxBtSize ( *cs.slice, chType ); const unsigned minBtSize = cs.pcv->getMinBtSize ( *cs.slice, chType ); @@ -340,14 +357,12 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca } if( canBtt && ( area.width <= minBtSize && area.height <= minBtSize ) - && ( ( area.width <= minTtSize && area.height <= minTtSize ) - || cs.sps->getSpsNext().getMTTMode() == 0 ) ) + && ( ( area.width <= minTtSize && area.height <= minTtSize ) ) ) { canBtt = false; } if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize ) - && ( ( area.width > maxTtSize || area.height > maxTtSize ) - || cs.sps->getSpsNext().getMTTMode() == 0 ) ) + && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) ) { canBtt = false; } @@ -366,12 +381,10 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca if( area.width <= minBtSize || area.width > maxBtSize ) canBv = false; if( area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height > MAX_TU_SIZE_FOR_PROFILE ) canBv = false; - if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) canTh = false; - if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize ) + if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize ) canTh = false; if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) canTh = false; - if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) canTv = false; if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize ) canTv = false; if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) canTv = false; @@ -418,6 +431,18 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs case TU_MAX_TR_SPLIT: return area.width > maxTrSize || area.height > maxTrSize; break; +#if JVET_M0140_SBT + case SBT_VER_HALF_POS0_SPLIT: + case SBT_VER_HALF_POS1_SPLIT: + case SBT_HOR_HALF_POS0_SPLIT: + case SBT_HOR_HALF_POS1_SPLIT: + case SBT_VER_QUAD_POS0_SPLIT: + case SBT_VER_QUAD_POS1_SPLIT: + case SBT_HOR_QUAD_POS0_SPLIT: + case SBT_HOR_QUAD_POS1_SPLIT: + return currTrDepth == 0; + break; +#endif #if JVET_M0421_SPLIT_SIG case CU_QUAD_SPLIT: return canQt; @@ -485,9 +510,9 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs { if( currMtDepth >= maxBTD ) return false; if( ( area.width <= minBtSize && area.height <= minBtSize ) - && ( ( area.width <= minTtSize && area.height <= minTtSize ) || cs.sps->getSpsNext().getMTTMode() == 0 ) ) return false; + && ( ( area.width <= minTtSize && area.height <= minTtSize ) ) ) return false; if( ( area.width > maxBtSize || area.height > maxBtSize ) - && ( ( area.width > maxTtSize || area.height > maxTtSize ) || cs.sps->getSpsNext().getMTTMode() == 0 ) ) return false; + && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) ) return false; if (CS::isDualITree(cs) && (area.width > 64 || area.height > 64)) { return false; @@ -513,12 +538,10 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs if( area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height > MAX_TU_SIZE_FOR_PROFILE ) return false; break; case CU_TRIH_SPLIT: - if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) return false; if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize) return false; if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) return false; break; case CU_TRIV_SPLIT: - if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) return false; if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize) return false; if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) return false; break; @@ -622,6 +645,13 @@ void QTBTPartitioner::exitCurrSplit() CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" ); currTrDepth--; } +#if JVET_M0140_SBT + else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT ) + { + CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" ); + currTrDepth--; + } +#endif else { CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" ); @@ -671,6 +701,106 @@ bool QTBTPartitioner::hasNextPart() return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() ); } +#if JVET_M0102_INTRA_SUBPARTITIONS +void TUIntraSubPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs ) +{ + switch( split ) + { + case TU_1D_HORZ_SPLIT: + case TU_1D_VERT_SPLIT: + { + const UnitArea &area = currArea(); + m_partStack.push_back( PartLevel() ); + m_partStack.back().split = split; + PartitionerImpl::getTUIntraSubPartitions( m_partStack.back().parts, area, cs, split ); + break; + } + case TU_MAX_TR_SPLIT: //we need this non ISP split because of the maxTrSize limitation + m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) ); + break; + default: + THROW( "Unknown ISP split mode" ); + break; + } + + currDepth++; + currTrDepth++; // we need this to identify the level. since the 1d partitions are forbidden if the RQT is on, there area no compatibility issues + +#if _DEBUG + m_currArea = m_partStack.back().parts.front(); +#endif +} + +void TUIntraSubPartitioner::exitCurrSplit() +{ + PartSplit currSplit = m_partStack.back().split; + + m_partStack.pop_back(); + + CHECK( currDepth == 0, "depth is '0', although a split was performed" ); + + currDepth--; + currTrDepth--; + +#if _DEBUG + m_currArea = m_partStack.back().parts[m_partStack.back().idx]; +#endif + + CHECK( !( currSplit == TU_1D_HORZ_SPLIT || currSplit == TU_1D_VERT_SPLIT || currSplit == TU_MAX_TR_SPLIT ), "Unknown 1D partition split type!" ); +} + +bool TUIntraSubPartitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ ) +{ + unsigned currIdx = ++m_partStack.back().idx; + + m_partStack.back().checkdIfImplicit = false; + m_partStack.back().isImplicit = false; + + if( currIdx < m_partStack.back().parts.size() ) + { +#if _DEBUG + m_currArea = m_partStack.back().parts[m_partStack.back().idx]; +#endif + return true; + } + else + { + if( autoPop ) exitCurrSplit(); + return false; + } +} + +bool TUIntraSubPartitioner::hasNextPart() +{ + return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() ); +} + +bool TUIntraSubPartitioner::canSplit( const PartSplit split, const CodingStructure &cs ) +{ + //const PartSplit implicitSplit = getImplicitSplit(cs); + const UnitArea &area = currArea(); + + switch( split ) + { + case TU_1D_HORZ_SPLIT: + { + return area.lheight() == m_partStack[0].parts[0].lheight(); + } + case TU_1D_VERT_SPLIT: + { + return area.lwidth() == m_partStack[0].parts[0].lwidth(); + } + case TU_MAX_TR_SPLIT: + { + //this split is performed implicitly with the other splits + return false; + } + default: + THROW( "Unknown 1-D split mode" ); + break; + } +} +#endif ////////////////////////////////////////////////////////////////////////// @@ -879,6 +1009,63 @@ Partitioning PartitionerImpl::getCUSubPartitions( const UnitArea &cuArea, const } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void PartitionerImpl::getTUIntraSubPartitions( Partitioning &sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType ) +{ + uint32_t nPartitions; + uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType ); + + bool isDualTree = CS::isDualITree( cs ); + + if( splitType == TU_1D_HORZ_SPLIT ) + { + nPartitions = tuArea.lumaSize().height >> g_aucLog2[splitDimensionSize]; + + sub.resize( nPartitions ); + + for( uint32_t i = 0; i < nPartitions; i++ ) + { + sub[i] = tuArea; + CompArea& blkY = sub[i].blocks[COMPONENT_Y]; + + blkY.height = splitDimensionSize; + blkY.y = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].y + splitDimensionSize : blkY.y; + + CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" ); + } + } + else if( splitType == TU_1D_VERT_SPLIT ) + { + nPartitions = tuArea.lumaSize().width >> g_aucLog2[splitDimensionSize]; + + sub.resize( nPartitions ); + + for( uint32_t i = 0; i < nPartitions; i++ ) + { + sub[i] = tuArea; + CompArea& blkY = sub[i].blocks[COMPONENT_Y]; + + blkY.width = splitDimensionSize; + blkY.x = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].x + splitDimensionSize : blkY.x; + CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" ); + } + } + else + { + THROW( "Unknown TU sub-partitioning" ); + } + //we only partition luma, so there is going to be only one chroma tu at the end (unless it is dual tree, in which case there won't be any chroma components) + uint32_t partitionsWithoutChroma = isDualTree ? nPartitions : nPartitions - 1; + for( uint32_t i = 0; i < partitionsWithoutChroma; i++ ) + { + CompArea& blkCb = sub[i].blocks[COMPONENT_Cb]; + CompArea& blkCr = sub[i].blocks[COMPONENT_Cr]; + blkCb = CompArea(); + blkCr = CompArea(); + } +} +#endif + static const int g_maxRtGridSize = 3; static const int g_zScanToX[1 << ( g_maxRtGridSize << 1 )] = @@ -954,3 +1141,64 @@ Partitioning PartitionerImpl::getMaxTuTiling( const UnitArea &cuArea, const Codi return ret; } + +#if JVET_M0140_SBT +Partitioning PartitionerImpl::getSbtTuTiling( const UnitArea& cuArea, const CodingStructure &cs, const PartSplit splitType ) +{ + Partitioning ret; + int numTiles = 2; + int widthFactor, heightFactor, xOffsetFactor, yOffsetFactor; // y = (x * factor) >> 2; + assert( splitType >= SBT_VER_HALF_POS0_SPLIT && splitType <= SBT_HOR_QUAD_POS1_SPLIT ); + + ret.resize( numTiles, cuArea ); + for( int i = 0; i < numTiles; i++ ) + { + if( splitType >= SBT_VER_QUAD_POS0_SPLIT ) + { + if( splitType == SBT_HOR_QUAD_POS0_SPLIT || splitType == SBT_HOR_QUAD_POS1_SPLIT ) + { + widthFactor = 4; + xOffsetFactor = 0; + heightFactor = ( ( i == 0 && splitType == SBT_HOR_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_HOR_QUAD_POS1_SPLIT ) ) ? 1 : 3; + yOffsetFactor = ( i == 0 ) ? 0 : ( splitType == SBT_HOR_QUAD_POS0_SPLIT ? 1 : 3 ); + } + else + { + widthFactor = ( ( i == 0 && splitType == SBT_VER_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_VER_QUAD_POS1_SPLIT ) ) ? 1 : 3; + xOffsetFactor = ( i == 0 ) ? 0 : ( splitType == SBT_VER_QUAD_POS0_SPLIT ? 1 : 3 ); + heightFactor = 4; + yOffsetFactor = 0; + } + } + else + { + if( splitType == SBT_HOR_HALF_POS0_SPLIT || splitType == SBT_HOR_HALF_POS1_SPLIT ) + { + widthFactor = 4; + xOffsetFactor = 0; + heightFactor = 2; + yOffsetFactor = ( i == 0 ) ? 0 : 2; + } + else + { + widthFactor = 2; + xOffsetFactor = ( i == 0 ) ? 0 : 2; + heightFactor = 4; + yOffsetFactor = 0; + } + } + + UnitArea& tile = ret[i]; + for( CompArea &comp : tile.blocks ) + { + if( !comp.valid() ) continue; + comp.x += ( comp.width * xOffsetFactor ) >> 2; + comp.y += ( comp.height * yOffsetFactor ) >> 2; + comp.width = ( comp.width * widthFactor ) >> 2; + comp.height = ( comp.height * heightFactor ) >> 2; + } + } + + return ret; +} +#endif diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 222fe99edeb0a83f5ef5ab5462a25f63d1bb1eb5..3060e8459eaea49de2550f987fea8a468b7806aa 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -43,7 +43,11 @@ #include "CommonDef.h" static_assert( MAX_CU_TILING_PARTITIONS >= 4, "Minimum required number of partitions for the Partitioning type is 4!" ); +#if JVET_M0102_INTRA_SUBPARTITIONS +typedef std::vector <UnitArea> Partitioning; +#else typedef static_vector<UnitArea, MAX_CU_TILING_PARTITIONS> Partitioning; +#endif ////////////////////////////////////////////////////////////////////////// // PartManager class - manages the partitioning tree @@ -63,6 +67,21 @@ enum PartSplit CU_TRIH_SPLIT, CU_TRIV_SPLIT, TU_MAX_TR_SPLIT, +#if JVET_M0102_INTRA_SUBPARTITIONS + TU_NO_ISP, + TU_1D_HORZ_SPLIT, + TU_1D_VERT_SPLIT, +#endif +#if JVET_M0140_SBT + SBT_VER_HALF_POS0_SPLIT, + SBT_VER_HALF_POS1_SPLIT, + SBT_HOR_HALF_POS0_SPLIT, + SBT_HOR_HALF_POS1_SPLIT, + SBT_VER_QUAD_POS0_SPLIT, + SBT_VER_QUAD_POS1_SPLIT, + SBT_HOR_QUAD_POS0_SPLIT, + SBT_HOR_QUAD_POS1_SPLIT, +#endif NUM_PART_SPLIT, CU_MT_SPLIT = 1000, ///< dummy element to indicate the MT (multi-type-tree) split CU_BT_SPLIT = 1001, ///< dummy element to indicate the BT split @@ -150,7 +169,7 @@ public: void exitCurrSplit (); bool nextPart ( const CodingStructure &cs, bool autoPop = false ); bool hasNextPart (); - + #if JVET_M0421_SPLIT_SIG void canSplit ( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ); #endif @@ -159,6 +178,37 @@ public: PartSplit getImplicitSplit ( const CodingStructure &cs ); }; +#if JVET_M0102_INTRA_SUBPARTITIONS +class TUIntraSubPartitioner : public Partitioner +{ +public: + TUIntraSubPartitioner(Partitioner& _initialState) + { + //we copy the input partitioner data + m_partStack.push_back(PartLevel(TU_NO_ISP, { _initialState.currArea() })); + + currDepth = _initialState.currDepth; + currQtDepth = _initialState.currQtDepth; + currTrDepth = _initialState.currTrDepth; + currBtDepth = _initialState.currBtDepth; + currMtDepth = _initialState.currMtDepth; + chType = _initialState.chType; +#if _DEBUG + m_currArea = _initialState.currArea(); +#endif + } + + void initCtu (const UnitArea& ctuArea, const ChannelType chType, const Slice& slice) {}; // not needed + void splitCurrArea (const PartSplit split, const CodingStructure &cs); + void exitCurrSplit (); + bool nextPart (const CodingStructure &cs, bool autoPop = false); + bool hasNextPart (); + void canSplit (const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv) {}; + bool canSplit (const PartSplit split, const CodingStructure &cs); + bool isSplitImplicit (const PartSplit split, const CodingStructure &cs) { return false; }; //not needed + PartSplit getImplicitSplit (const CodingStructure &cs) { return CU_DONT_SPLIT; }; //not needed +}; +#endif @@ -176,6 +226,12 @@ namespace PartitionerImpl { Partitioning getCUSubPartitions( const UnitArea &cuArea, const CodingStructure &cs, const PartSplit splitType = CU_QUAD_SPLIT ); Partitioning getMaxTuTiling ( const UnitArea& curArea, const CodingStructure &cs ); +#if JVET_M0102_INTRA_SUBPARTITIONS + void getTUIntraSubPartitions( Partitioning &sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType ); +#endif +#if JVET_M0140_SBT + Partitioning getSbtTuTiling ( const UnitArea& curArea, const CodingStructure &cs, const PartSplit splitType ); +#endif }; #endif diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 5bb6c03629e76d5b62c5bab6d180f5f04acbd58e..5a7dc7bf71254686b8669a3ae89ca16b8c3d39fb 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -65,7 +65,39 @@ UnitArea CS::getArea( const CodingStructure &cs, const UnitArea &area, const Cha { return isDualITree( cs ) ? area.singleChan( chType ) : area; } - +#if JVET_M0147_DMVR +void CS::setRefinedMotionField(CodingStructure &cs) +{ + for (CodingUnit *cu : cs.cus) + { + for (auto &pu : CU::traversePUs(*cu)) + { + PredictionUnit subPu = pu; + int dx, dy, x, y, num = 0; + dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT); + dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH); + Position puPos = pu.lumaPos(); + if (PU::checkDMVRCondition(pu)) + { + for (y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy) + { + for (x = puPos.x; x < (puPos.x + pu.lumaSize().width); x = x + dx) + { + subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy))); + subPu.mv[0] = pu.mv[0]; + subPu.mv[1] = pu.mv[1]; + subPu.mv[REF_PIC_LIST_0] += pu.mvdL0SubPu[num]; + subPu.mv[REF_PIC_LIST_1] -= pu.mvdL0SubPu[num]; + pu.mvdL0SubPu[num].setZero(); + num++; + PU::spanMotionInfo(subPu); + } + } + } + } + } +} +#endif // CU tools bool CU::isIntra(const CodingUnit &cu) @@ -78,6 +110,13 @@ bool CU::isInter(const CodingUnit &cu) return cu.predMode == MODE_INTER; } +#if JVET_M0483_IBC +bool CU::isIBC(const CodingUnit &cu) +{ + return cu.predMode == MODE_IBC; +} +#endif + bool CU::isRDPCMEnabled(const CodingUnit& cu) { return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT); @@ -150,25 +189,6 @@ int CU::predictQP( const CodingUnit& cu, const int prevQP ) { const CodingStructure &cs = *cu.cs; -#if ENABLE_WPP_PARALLELISM - if( cs.sps->getSpsNext().getUseNextDQP() ) - { - // Inter-CTU 2D "planar" c(orner) a(bove) - // predictor arrangement: b(efore) p(rediction) - - // restrict the lookup, as it might cross CTU/slice/tile boundaries - const CodingUnit *cuA = cs.getCURestricted( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu, cu.chType ); - const CodingUnit *cuB = cs.getCURestricted( cu.blocks[cu.chType].pos().offset( -1, 0 ), cu, cu.chType ); - const CodingUnit *cuC = cs.getCURestricted( cu.blocks[cu.chType].pos().offset( -1, -1 ), cu, cu.chType ); - - const int a = cuA ? cuA->qp : cs.slice->getSliceQpBase(); - const int b = cuB ? cuB->qp : cs.slice->getSliceQpBase(); - const int c = cuC ? cuC->qp : cs.slice->getSliceQpBase(); - - return Clip3( ( a < b ? a : b ), ( a > b ? a : b ), a + b - c ); // derived from Martucci's Median Adaptive Prediction, 1990 - } - -#endif // only predict within the same CTU, use HEVC's above+left prediction const int a = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUHeightMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType ) )->qp : prevQP; const int b = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU( cu.blocks[cu.chType].pos().offset( -1, 0 ), cu.chType ) )->qp : prevQP; @@ -181,7 +201,7 @@ bool CU::isQGStart( const CodingUnit& cu, Partitioner& partitioner ) int maxDqpDepth = cu.slice->getPPS()->getMaxCuDQPDepth(); if( partitioner.currDepth >= maxDqpDepth ) { - PartLevel splitAtMaxDepth = partitioner.getPartStack().at( maxDqpDepth ); + PartLevel splitAtMaxDepth = partitioner.getPartStack().at( maxDqpDepth ); // the parent node of qtDepth + mttDepth == maxDqpDepth if( splitAtMaxDepth.parts[splitAtMaxDepth.idx].blocks[partitioner.chType].pos() == cu.blocks[partitioner.chType].pos() ) return true; @@ -258,7 +278,175 @@ uint32_t CU::getNumNonZeroCoeffNonTs( const CodingUnit& cu ) return count; } +#if JVET_M0102_INTRA_SUBPARTITIONS +bool CU::divideTuInRows( const CodingUnit &cu ) +{ + CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" ); + return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false; +} + +bool CU::firstTestISPHorSplit( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft, const CodingUnit *cuAbove ) +{ + //this function decides which split mode (horizontal or vertical) is tested first (encoder only) + //we check the logarithmic aspect ratios of the block + int aspectRatio = g_aucLog2[width] - g_aucLog2[height]; + if( aspectRatio > 0 ) + { + return true; + } + else if( aspectRatio < 0 ) + { + return false; + } + else //if (aspectRatio == 0) + { + //we gather data from the neighboring CUs + const int cuLeftWidth = cuLeft != nullptr ? cuLeft->blocks[compID].width : -1; + const int cuLeftHeight = cuLeft != nullptr ? cuLeft->blocks[compID].height : -1; + const int cuAboveWidth = cuAbove != nullptr ? cuAbove->blocks[compID].width : -1; + const int cuAboveHeight = cuAbove != nullptr ? cuAbove->blocks[compID].height : -1; + const int cuLeft1dSplit = cuLeft != nullptr && cuLeft->predMode == MODE_INTRA ? cuLeft->ispMode : 0; + const int cuAbove1dSplit = cuAbove != nullptr && cuAbove->predMode == MODE_INTRA ? cuAbove->ispMode : 0; + if( cuLeftWidth != -1 && cuAboveWidth == -1 ) + { + int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight]; + return cuLeftAspectRatio < 0 ? false : cuLeftAspectRatio > 0 ? true : cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeftWidth == -1 && cuAboveWidth != -1 ) + { + int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight]; + return cuAboveAspectRatio < 0 ? false : cuAboveAspectRatio > 0 ? true : cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeftWidth != -1 && cuAboveWidth != -1 ) + { + int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight]; + int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight]; + if( cuLeftAspectRatio < 0 && cuAboveAspectRatio < 0 ) + { + return false; + } + else if( cuLeftAspectRatio > 0 && cuAboveAspectRatio > 0 ) + { + return true; + } + else if( cuLeftAspectRatio == 0 && cuAboveAspectRatio == 0 ) + { + if( cuLeft1dSplit != 0 && cuAbove1dSplit != 0 ) + { + return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS && cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeft1dSplit != 0 && cuAbove1dSplit == 0 ) + { + return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeft1dSplit == 0 && cuAbove1dSplit != 0 ) + { + return cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + return true; + } + else + { + return cuLeftAspectRatio > cuAboveAspectRatio ? cuLeftAspectRatio > 0 : cuAboveAspectRatio > 0; + } + //return true; + } + return true; + } +} + +PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID ) +{ + if( cu.ispMode && isLuma( compID ) ) + { + const bool tuIsDividedInRows = CU::divideTuInRows( cu ); + + return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT; + } + return TU_NO_ISP; +} + +bool CU::isISPLast( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ) +{ + PartSplit partitionType = CU::getISPType( cu, compID ); + + Area originalArea = cu.blocks[compID]; + switch( partitionType ) + { + case TU_1D_HORZ_SPLIT: + return tuArea.y + tuArea.height == originalArea.y + originalArea.height; + case TU_1D_VERT_SPLIT: + return tuArea.x + tuArea.width == originalArea.x + originalArea.width; + default: + THROW( "Unknown ISP processing order type!" ); + return false; + } +} + +bool CU::isISPFirst( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ) +{ + return tuArea == cu.firstTU->blocks[compID]; +} + +ISPType CU::canUseISPSplit( const CodingUnit &cu, const ComponentID compID ) +{ + const int width = cu.blocks[compID].width; + const int height = cu.blocks[compID].height; + const int maxTrSize = cu.cs->sps->getMaxTrSize(); + return CU::canUseISPSplit( width, height, maxTrSize ); +} + +ISPType CU::canUseISPSplit( const int width, const int height, const int maxTrSize ) +{ + bool widthCannotBeUsed = false, heightCannotBeUsed = false; + + const uint32_t minTuSizeForISP = MIN_TU_SIZE; + bool notEnoughSamplesToSplit = ( g_aucLog2[width] + g_aucLog2[height] <= ( g_aucLog2[minTuSizeForISP] << 1 ) ); + widthCannotBeUsed = width > maxTrSize || notEnoughSamplesToSplit; + heightCannotBeUsed = height > maxTrSize || notEnoughSamplesToSplit; + + if( !widthCannotBeUsed && !heightCannotBeUsed ) + { + return CAN_USE_VER_AND_HORL_SPLITS; //both splits can be used + } + else if( widthCannotBeUsed && !heightCannotBeUsed ) + { + return VER_INTRA_SUBPARTITIONS; //only the vertical split can be performed + } + else if( !widthCannotBeUsed && heightCannotBeUsed ) + { + return HOR_INTRA_SUBPARTITIONS; //only the horizontal split can be performed + } + else + { + return NOT_INTRA_SUBPARTITIONS; //neither of the splits can be used + } +} + +uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType ) +{ + bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT; + uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2; + + if( divideTuInRows ) + { + splitDimensionSize = height; + nonSplitDimensionSize = width; + } + else + { + splitDimensionSize = width; + nonSplitDimensionSize = height; + } + + const int minNumberOfSamplesPerCu = 1 << ( ( g_aucLog2[MIN_TU_SIZE] << 1 ) ); + const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> g_aucLog2[nonSplitDimensionSize] : 1; + partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift ); + CHECK( g_aucLog2[partitionSize] + g_aucLog2[nonSplitDimensionSize] < g_aucLog2[minNumberOfSamplesPerCu], "A partition has less than the minimum amount of samples!" ); + return partitionSize; +} +#endif PUTraverser CU::traversePUs( CodingUnit& cu ) @@ -287,6 +475,10 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType { const int numMPMs = NUM_MOST_PROBABLE_MODES; const int extendRefLine = (channelType == CHANNEL_TYPE_LUMA) ? pu.multiRefIdx : 0; +#if JVET_M0102_INTRA_SUBPARTITIONS + const ISPType ispType = isLuma( channelType ) ? ISPType( pu.cu->ispMode ) : NOT_INTRA_SUBPARTITIONS; + const bool isHorSplit = ispType == HOR_INTRA_SUBPARTITIONS; +#endif { int numCand = -1; int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX; @@ -381,6 +573,116 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType } } } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( ispType != NOT_INTRA_SUBPARTITIONS ) + { + //default case + mpm[0] = PLANAR_IDX; + if( isHorSplit ) + { + mpm[1] = HOR_IDX; + mpm[2] = 25; + mpm[3] = 10; + mpm[4] = 65; + mpm[5] = VER_IDX; + } + else + { + mpm[1] = VER_IDX; + mpm[2] = 43; + mpm[3] = 60; + mpm[4] = 3; + mpm[5] = HOR_IDX; + } + int canonicalMode = mpm[1]; + if( leftIntraDir == aboveIntraDir ) //L=A + { + numCand = 1; + if( leftIntraDir > DC_IDX ) + { + mpm[0] = leftIntraDir; + mpm[1] = ( ( leftIntraDir + offset ) % mod ) + 2; + mpm[2] = ( ( leftIntraDir - 1 ) % mod ) + 2; + if( ( isHorSplit && leftIntraDir < DIA_IDX ) || ( !isHorSplit && leftIntraDir >= DIA_IDX ) ) + { + mpm[3] = ( ( leftIntraDir + offset - 1 ) % mod ) + 2; + mpm[4] = ( leftIntraDir % mod ) + 2; + mpm[5] = ( ( leftIntraDir + offset - 2 ) % mod ) + 2;; + } + else + { + if( isHorSplit ) + { + mpm[3] = HOR_IDX; + mpm[4] = 5; + } + else + { + mpm[3] = VER_IDX; + mpm[4] = VDIA_IDX - 3; + } + mpm[5] = PLANAR_IDX; + } + } + } + else //L!=A + { + numCand = 2; + if( ( leftIntraDir > DC_IDX ) && ( aboveIntraDir > DC_IDX ) ) + { + int distLeftToCanonicalMode = abs( leftIntraDir - canonicalMode ); + int distAboveToCanonicalMode = abs( aboveIntraDir - canonicalMode ); + mpm[0] = aboveIntraDir; + mpm[1] = leftIntraDir; + if( distLeftToCanonicalMode <= distAboveToCanonicalMode ) + { + mpm[0] = leftIntraDir; + mpm[1] = aboveIntraDir; + } + int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1; + int minCandModeIdx = 1 - maxCandModeIdx; + if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[3] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + mpm[4] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2; + mpm[5] = ( mpm[maxCandModeIdx] % mod ) + 2; + } + else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[3] = ( ( mpm[maxCandModeIdx] + offset ) % mod ) + 2; + mpm[4] = ( ( mpm[minCandModeIdx] ) % mod ) + 2; + mpm[5] = ( ( mpm[maxCandModeIdx] + offset - 1 ) % mod ) + 2; + } + else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[3] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[4] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + mpm[5] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2; + } + else + { + mpm[2] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[3] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[4] = ( ( mpm[maxCandModeIdx] + offset ) % mod ) + 2; + mpm[5] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + } + } + else if( leftIntraDir + aboveIntraDir > 2 ) + { + //mpm[0] = PLANAR_IDX; + int angMode = leftIntraDir > DC_IDX ? leftIntraDir : aboveIntraDir; + mpm[1] = angMode; + mpm[2] = ( ( angMode + offset ) % mod ) + 2; + mpm[3] = ( ( angMode - 1 ) % mod ) + 2; + mpm[4] = ( ( angMode + offset - 1 ) % mod ) + 2; + mpm[5] = ( ( angMode ) % mod ) + 2; + } + } + } +#endif else { mpm[0] = leftIntraDir; @@ -478,7 +780,7 @@ bool PU::isLMCMode(unsigned mode) } bool PU::isLMCModeEnabled(const PredictionUnit &pu, unsigned mode) { - if ( pu.cs->sps->getSpsNext().getUseLMChroma() ) + if ( pu.cs->sps->getUseLMChroma() ) { return true; } @@ -711,7 +1013,12 @@ bool PU::xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const #if JVET_L0090_PAIR_AVG bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos +#if JVET_M0483_IBC==0 , int mmvdList +#endif +#if JVET_M0483_IBC + , bool ibcFlag +#endif #if JVET_M0170_MRG_SHARELIST , bool isShared #endif @@ -723,7 +1030,9 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter ) #endif { +#if JVET_M0483_IBC==0 int mrgCandIdxIBC = mrgCandIdx; +#endif MotionInfo miNeighbor; bool hasPruned[MRG_MAX_NUM_CANDS]; memset(hasPruned, 0, MRG_MAX_NUM_CANDS * sizeof(bool)); @@ -732,17 +1041,36 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter hasPruned[subPuMvpPos] = true; } #if JVET_M0170_MRG_SHARELIST +#if JVET_M0483_IBC + int num_avai_candInLUT = ibcFlag ? slice.getAvailableLUTIBCMrgNum() : (isShared ? slice.getAvailableLUTBkupMrgNum() : slice.getAvailableLUTMrgNum()); + int offset = ibcFlag ? MAX_NUM_HMVP_CANDS : 0; +#else int num_avai_candInLUT = (isShared ? slice.getAvailableLUTBkupMrgNum() : slice.getAvailableLUTMrgNum()); +#endif +#else +#if JVET_M0483_IBC + int num_avai_candInLUT = ibcFlag ? slice.getAvailableLUTIBCMrgNum() : slice.getAvailableLUTMrgNum(); + int offset = ibcFlag ? MAX_NUM_HMVP_CANDS : 0; #else int num_avai_candInLUT = slice.getAvailableLUTMrgNum(); +#endif #endif for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++) { #if JVET_M0170_MRG_SHARELIST +#if JVET_M0483_IBC + miNeighbor = ibcFlag ? slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx + offset) + : (isShared ? slice.getMotionInfoFromLUTBkup(num_avai_candInLUT - mrgIdx) : slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx)); +#else miNeighbor = isShared ? slice.getMotionInfoFromLUTBkup(num_avai_candInLUT - mrgIdx) : slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx); +#endif +#else +#if JVET_M0483_IBC + miNeighbor = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx + offset); #else miNeighbor = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx); +#endif #endif mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir; mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]); @@ -750,30 +1078,313 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter { mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]); } +#if JVET_M0126_HMVP_MRG_PRUNING + if (mrgIdx > 2 || !xCheckSimilarMotion(cnt, prevCnt, mrgCtx, hasPruned)) +#else if (!xCheckSimilarMotion(cnt, prevCnt, mrgCtx, hasPruned)) +#endif + { +#if !JVET_L0090_PAIR_AVG + isCandInter[cnt] = true; +#endif +#if JVET_M0264_HMVP_WITH_GBIIDX + mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? miNeighbor.GBiIdx : GBI_DEFAULT; +#endif +#if JVET_M0483_IBC==0 + if (miNeighbor.interDir == 1 && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0])->getPOC() == slice.getPOC()) + { + mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; + if(mmvdList != 0 && mrgCandIdx != -1) + mrgCandIdxIBC++; + } + if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif + { + return true; + } + cnt ++; + if (cnt == maxNumMergeCandMin1) + { + break; + } + } + } + return false; +} + +#if JVET_M0483_IBC +void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx) +{ + const CodingStructure &cs = *pu.cs; + const Slice &slice = *pu.cs->slice; + const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand(); + const bool canFastExit = pu.cs->pps->getLog2ParallelMergeLevelMinus2() == 0; + + for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui) + { + mrgCtx.GBiIdx[ui] = GBI_DEFAULT; + mrgCtx.interDirNeighbours[ui] = 0; + mrgCtx.mrgTypeNeighbours[ui] = MRG_TYPE_IBC; + mrgCtx.mvFieldNeighbours[ui * 2].refIdx = NOT_VALID; + mrgCtx.mvFieldNeighbours[ui * 2 + 1].refIdx = NOT_VALID; + } + + mrgCtx.numValidMergeCand = maxNumMergeCand; + // compute the location of the current PU + + int cnt = 0; + + const Position posLT = pu.Y().topLeft(); + const Position posRT = pu.Y().topRight(); + const Position posLB = pu.Y().bottomLeft(); + + MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft; + + //left + const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType); + const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu); + if (isAvailableA1) + { + miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0)); + + // get Inter Dir + mrgCtx.interDirNeighbours[cnt] = miLeft.interDir; + // get Mv from Left + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]); + if (mrgCandIdx == cnt && canFastExit) + { + return; + } + cnt++; + } + + // early termination + if (cnt == maxNumMergeCand) + { + return; + } + + + // above + const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType); + bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu); + if (isAvailableB1) + { + miAbove = puAbove->getMotionInfo(posRT.offset(0, -1)); + + if (!isAvailableA1 || (miAbove != miLeft)) + { + // get Inter Dir + mrgCtx.interDirNeighbours[cnt] = miAbove.interDir; + // get Mv from Above + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]); + if (mrgCandIdx == cnt && canFastExit) + { + return; + } + + cnt++; + } + } + + // early termination + if (cnt == maxNumMergeCand) + { + return; + } + +#if JVET_M0126_HMVP_MRG_PRUNING + int spatialCandPos = cnt; +#endif + + // above right + const PredictionUnit *puAboveRight = cs.getPURestricted(posRT.offset(1, -1), pu, pu.chType); + bool isAvailableB0 = puAboveRight && isDiffMER(pu, *puAboveRight) && CU::isIBC(*puAboveRight->cu); + if (isAvailableB0) + { + miAboveRight = puAboveRight->getMotionInfo(posRT.offset(1, -1)); + +#if HM_JEM_MERGE_CANDS + if ((!isAvailableB1 || (miAbove != miAboveRight)) && (!isAvailableA1 || (miLeft != miAboveRight))) +#else + if (!isAvailableB1 || (miAbove != miAboveRight)) +#endif + { + // get Inter Dir + mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir; + // get Mv from Above-right + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveRight.mv[0], miAboveRight.refIdx[0]); + + if (mrgCandIdx == cnt && canFastExit) + { + return; + } + + cnt++; + } + } + // early termination + if (cnt == maxNumMergeCand) + { + return; + } + + //left bottom + const PredictionUnit *puLeftBottom = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType); + bool isAvailableA0 = puLeftBottom && isDiffMER(pu, *puLeftBottom) && CU::isIBC(*puLeftBottom->cu); + if (isAvailableA0) + { + miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1)); + +#if HM_JEM_MERGE_CANDS + if ((!isAvailableA1 || (miBelowLeft != miLeft)) && (!isAvailableB1 || (miBelowLeft != miAbove)) && (!isAvailableB0 || (miBelowLeft != miAboveRight))) +#else + if (!isAvailableA1 || (miBelowLeft != miLeft)) +#endif + { + // get Inter Dir + mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir; + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[0], miBelowLeft.refIdx[0]); + if (mrgCandIdx == cnt && canFastExit) + { + return; + } + + cnt++; + } + } + // early termination + if (cnt == maxNumMergeCand) + { + return; + } + + // above left + if (cnt < 4) + { + const PredictionUnit *puAboveLeft = cs.getPURestricted(posLT.offset(-1, -1), pu, pu.chType); + bool isAvailableB2 = puAboveLeft && isDiffMER(pu, *puAboveLeft) && CU::isIBC(*puAboveLeft->cu); + if (isAvailableB2) + { + miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1)); + +#if HM_JEM_MERGE_CANDS + if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)) && (!isAvailableA0 || (miBelowLeft != miAboveLeft)) && (!isAvailableB0 || (miAboveRight != miAboveLeft))) +#else + if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft))) +#endif + { + // get Inter Dir + mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir; + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[0], miAboveLeft.refIdx[0]); + if (mrgCandIdx == cnt && canFastExit) + { + return; + } + + cnt++; + } + } + } + // early termination + if (cnt == maxNumMergeCand) + { + return; + } + + int maxNumMergeCandMin1 = maxNumMergeCand - 1; + if (cnt != maxNumMergeCandMin1) + { + bool isAvailableSubPu = false; + unsigned subPuMvpPos = 0; + +#if JVET_L0090_PAIR_AVG + bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit + , mrgCandIdx + , maxNumMergeCandMin1, cnt +#if JVET_M0126_HMVP_MRG_PRUNING + , spatialCandPos +#else + , cnt +#endif + , isAvailableSubPu, subPuMvpPos +#if JVET_M0483_IBC + , true +#endif +#if JVET_M0170_MRG_SHARELIST + , false +#endif + ); +#else + bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit + , mrgCandIdx + , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos + ); +#endif + if (bFound) + { + return; + } + } + +#if JVET_L0090_PAIR_AVG + // pairwise-average candidates +#if JVET_M0193_PAIR_AVG_REDUCTION==0 + const int cutoff = std::min(cnt, 4); + const int end = cutoff * (cutoff - 1) / 2; + constexpr int PRIORITY_LIST0[] = { 0, 0, 1, 0, 1, 2 }; + constexpr int PRIORITY_LIST1[] = { 1, 2, 2, 3, 3, 3 }; + + for (int idx = 0; idx < end && cnt != maxNumMergeCand; idx++) + { + const int i = PRIORITY_LIST0[idx]; + const int j = PRIORITY_LIST1[idx]; +#else + if (cnt>1 && cnt <maxNumMergeCand) + { +#endif + mrgCtx.mvFieldNeighbours[cnt * 2 ].setMvField(Mv(0, 0), NOT_VALID); + mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField(Mv(0, 0), NOT_VALID); + +#if JVET_M0193_PAIR_AVG_REDUCTION + const Mv& MvI = mrgCtx.mvFieldNeighbours[0 * 2].mv; + const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2].mv; +#else + const Mv& MvI = mrgCtx.mvFieldNeighbours[i * 2 ].mv; + const Mv& MvJ = mrgCtx.mvFieldNeighbours[j * 2 ].mv; +#endif + // average two MVs + Mv avgMv = MvI; + + avgMv += MvJ; + mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; +#if JVET_M0265_MV_ROUNDING_CLEANUP + roundAffineMv(avgMv.hor, avgMv.ver, 1); + avgMv.roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); +#else + avgMv.setHor(avgMv.getHor() / 2); + avgMv.setVer(avgMv.getVer() / 2); + avgMv.setHor((avgMv.getHor() / 16) << 4); + avgMv.setVer((avgMv.getVer() / 16) << 4); +#endif + mrgCtx.mvFieldNeighbours[cnt * 2 ].setMvField(avgMv, MAX_NUM_REF); + mrgCtx.interDirNeighbours[cnt] = 1; + cnt++; + } + + // early termination + if (cnt == maxNumMergeCand) { -#if !JVET_L0090_PAIR_AVG - isCandInter[cnt] = true; -#endif - if (miNeighbor.interDir == 1 && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0])->getPOC() == slice.getPOC()) - { - mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; - if(mmvdList != 0 && mrgCandIdx != -1) - mrgCandIdxIBC++; - } - if (mrgCandIdxIBC == cnt && canFastExit) - { - return true; - } - cnt ++; - if (cnt == maxNumMergeCandMin1) - { - break; - } + return; } - } - return false; +#endif + + mrgCtx.numValidMergeCand = cnt; + } +#endif void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, int mmvdList, @@ -806,8 +1417,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, int cnt = 0; - +#if JVET_M0483_IBC==0 int mrgCandIdxIBC = mrgCandIdx; +#endif #if JVET_M0170_MRG_SHARELIST const Position posLT = pu.shareParentPos; @@ -837,19 +1449,25 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.interDirNeighbours[cnt] = miLeft.interDir; mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->GBiIdx : GBI_DEFAULT; // get Mv from Left +#if JVET_M0483_IBC==0 if (puLeft->cu->ibc) { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; if (mmvdList != 0 && mrgCandIdx != -1) mrgCandIdxIBC++; } +#endif mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]); if (slice.isInterB()) { mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]); } +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -883,19 +1501,25 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.interDirNeighbours[cnt] = miAbove.interDir; // get Mv from Above mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->GBiIdx : GBI_DEFAULT; +#if JVET_M0483_IBC==0 if (puAbove->cu->ibc) { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; if (mmvdList != 0 && mrgCandIdx != -1) mrgCandIdxIBC++; } +#endif mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAbove.mv[0], miAbove.refIdx[0] ); if( slice.isInterB() ) { mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAbove.mv[1], miAbove.refIdx[1] ); } +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -910,6 +1534,10 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, return; } +#if JVET_M0126_HMVP_MRG_PRUNING + int spatialCandPos = cnt; +#endif + // above right const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType ); @@ -933,12 +1561,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir; // get Mv from Above-right mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->GBiIdx : GBI_DEFAULT; +#if JVET_M0483_IBC==0 if (puAboveRight->cu->ibc) { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; if (mmvdList != 0 && mrgCandIdx != -1) mrgCandIdxIBC++; } +#endif mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] ); if( slice.isInterB() ) @@ -946,7 +1576,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] ); } +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -983,12 +1617,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir; mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->GBiIdx : GBI_DEFAULT; // get Mv from Bottom-Left +#if JVET_M0483_IBC==0 if (puLeftBottom->cu->ibc) { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; if (mmvdList != 0 && mrgCandIdx != -1) mrgCandIdxIBC++; } +#endif mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] ); if( slice.isInterB() ) @@ -996,7 +1632,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] ); } +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -1036,12 +1676,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir; mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->GBiIdx : GBI_DEFAULT; // get Mv from Above-Left +#if JVET_M0483_IBC==0 if (puAboveLeft->cu->ibc) { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; if (mmvdList != 0 && mrgCandIdx != -1) mrgCandIdxIBC++; } +#endif mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] ); if( slice.isInterB() ) @@ -1049,7 +1691,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] ); } +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -1170,7 +1816,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, isCandInter [uiArrayAddr] = true; #endif mrgCtx.GBiIdx[uiArrayAddr] = GBI_DEFAULT; +#if JVET_M0483_IBC==0 if (mrgCandIdxIBC == cnt && canFastExit) +#else + if (mrgCandIdx == cnt && canFastExit) +#endif { return; } @@ -1196,9 +1846,24 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, bool isShared = ((pu.Y().lumaSize().width != pu.shareParentSize.width) || (pu.Y().lumaSize().height != pu.shareParentSize.height)); #endif bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit +#if JVET_M0483_IBC==0 , (mmvdList != 0 && mrgCandIdx != -1) ? (const int) mrgCandIdxIBC : mrgCandIdx - , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos +#else + , mrgCandIdx +#endif + , maxNumMergeCandMin1, cnt +#if JVET_M0126_HMVP_MRG_PRUNING + , spatialCandPos +#else + , cnt +#endif + , isAvailableSubPu, subPuMvpPos +#if JVET_M0483_IBC==0 , mmvdList +#endif +#if JVET_M0483_IBC + , CU::isIBC(*pu.cu) +#endif #if JVET_M0170_MRG_SHARELIST , isShared #endif @@ -1219,15 +1884,28 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, #if JVET_L0090_PAIR_AVG // pairwise-average candidates { +#if !JVET_M0193_PAIR_AVG_REDUCTION const int cutoff = std::min( cnt, 4 ); const int end = cutoff * (cutoff - 1) / 2; constexpr int PRIORITY_LIST0[] = { 0, 0, 1, 0, 1, 2 }; constexpr int PRIORITY_LIST1[] = { 1, 2, 2, 3, 3, 3 }; +#endif +#if JVET_M0193_PAIR_AVG_REDUCTION +#if JVET_M0483_IBC + if (cnt > 1 && cnt < maxNumMergeCand) +#else + // skip when only 1 candidate is added so far or one is BV and one is MV + if( cnt > 1 && cnt < maxNumMergeCand && !(mrgCtx.mrgTypeNeighbours[0] != mrgCtx.mrgTypeNeighbours[1] && pu.cs->sps->getIBCMode())) +#endif +#else for( int idx = 0; idx < end && cnt != maxNumMergeCand; idx++ ) +#endif { +#if !JVET_M0193_PAIR_AVG_REDUCTION const int i = PRIORITY_LIST0[idx]; const int j = PRIORITY_LIST1[idx]; +#endif mrgCtx.mvFieldNeighbours[cnt * 2].setMvField( Mv( 0, 0 ), NOT_VALID ); mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField( Mv( 0, 0 ), NOT_VALID ); @@ -1235,15 +1913,22 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, unsigned char interDir = 0; +#if !JVET_M0193_PAIR_AVG_REDUCTION && JVET_M0483_IBC==0 // skip when one is BV and one is MV - if (mrgCtx.mrgTypeNeighbours[i] != mrgCtx.mrgTypeNeighbours[j] && pu.cs->sps->getSpsNext().getIBCMode()) + if (mrgCtx.mrgTypeNeighbours[i] != mrgCtx.mrgTypeNeighbours[j] && pu.cs->sps->getIBCMode()) { continue; } +#endif for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ ) { +#if JVET_M0193_PAIR_AVG_REDUCTION + const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx; + const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx; +#else const short refIdxI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].refIdx; const short refIdxJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].refIdx; +#endif // both MVs are invalid, skip if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) ) @@ -1255,35 +1940,55 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, // both MVs are valid, average these two MVs if( (refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID) ) { +#if JVET_M0193_PAIR_AVG_REDUCTION + const Mv& MvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv; + const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv; +#else const Mv& MvI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv; const Mv& MvJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv; +#endif // average two MVs Mv avgMv = MvI; avgMv += MvJ; +#if JVET_M0265_MV_ROUNDING_CLEANUP + roundAffineMv(avgMv.hor, avgMv.ver, 1); +#else avgMv.setHor( avgMv.getHor() / 2 ); avgMv.setVer( avgMv.getVer() / 2 ); +#endif - - - if (mrgCtx.mrgTypeNeighbours[i] == MRG_TYPE_IBC && mrgCtx.mrgTypeNeighbours[j] == MRG_TYPE_IBC && pu.cs->sps->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 +#if JVET_M0193_PAIR_AVG_REDUCTION + if (mrgCtx.mrgTypeNeighbours[0] == MRG_TYPE_IBC && mrgCtx.mrgTypeNeighbours[1] == MRG_TYPE_IBC && pu.cs->sps->getIBCMode()) +#else + if (mrgCtx.mrgTypeNeighbours[i] == MRG_TYPE_IBC && mrgCtx.mrgTypeNeighbours[j] == MRG_TYPE_IBC && pu.cs->sps->getIBCMode()) +#endif { mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC; avgMv.setHor((avgMv.getHor() / 16) << 4); avgMv.setVer((avgMv.getVer() / 16) << 4); } - +#endif mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI ); } // only one MV is valid, take the only one MV else if( refIdxI != NOT_VALID ) { +#if JVET_M0193_PAIR_AVG_REDUCTION + Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv; +#else Mv singleMv = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv; +#endif mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI ); } else if( refIdxJ != NOT_VALID ) { +#if JVET_M0193_PAIR_AVG_REDUCTION + Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv; +#else Mv singleMv = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv; +#endif mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxJ ); } } @@ -1387,6 +2092,27 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, } mrgCtx.numValidMergeCand = uiArrayAddr; } +#if JVET_M0147_DMVR +bool PU::checkDMVRCondition(const PredictionUnit& pu) +{ + if (pu.cs->sps->getUseDMVR()) + { + return pu.mergeFlag + && pu.mergeType == MRG_TYPE_DEFAULT_N + && !pu.cu->affine + && !pu.mmvdMergeFlag + && !pu.cu->mmvdSkip + && PU::isBiPredFromDifferentDirEqDistPoc(pu) + && (pu.lheight() >= 8) + && ((pu.lheight() * pu.lwidth()) >= 64) + ; + } + else + { + return false; + } +} +#endif // for ibc pu validation bool PU::isBlockVectorValid(PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xStartInCU, int yStartInCU, int xBv, int yBv, int ctuSize) { @@ -1501,6 +2227,44 @@ static int xGetDistScaleFactor(const int &iCurrPOC, const int &iCurrRefPOC, cons return iScale; } } + +#if JVET_M0512_MOTION_BUFFER_COMPRESSION +int convertMvFixedToFloat(int32_t val) +{ + int sign = val >> 31; + int scale = floorLog2((val ^ sign) | MV_MANTISSA_UPPER_LIMIT) - (MV_MANTISSA_BITCOUNT - 1); + + int exponent; + int mantissa; + if (scale >= 0) + { + int round = (1 << scale) >> 1; + int n = (val + round) >> scale; + exponent = scale + ((n ^ sign) >> (MV_MANTISSA_BITCOUNT - 1)); + mantissa = (n & MV_MANTISSA_UPPER_LIMIT) | (sign << (MV_MANTISSA_BITCOUNT - 1)); + } + else + { + exponent = 0; + mantissa = val; + } + + return exponent | (mantissa << MV_EXPONENT_BITCOUNT); +} + +int convertMvFloatToFixed(int val) +{ + int exponent = val & MV_EXPONENT_MASK; + int mantissa = val >> MV_EXPONENT_BITCOUNT; + return exponent == 0 ? mantissa : (mantissa ^ MV_MANTISSA_LIMIT) << (exponent - 1); +} + +int roundMvComp(int x) +{ + return convertMvFloatToFixed(convertMvFixedToFloat(x)); +} +#endif + int PU::getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC) { return xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC); @@ -1561,7 +2325,7 @@ void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx ) { // don't perform MV compression when generally disabled or subPuMvp is used - const unsigned scale = ( pu.cs->pcv->noMotComp ? 1 : 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4) ); + const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4); const unsigned mask = ~( scale - 1 ); const Position pos = Position{ PosType( _pos.x & mask ), PosType( _pos.y & mask ) }; @@ -1584,7 +2348,17 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList { return false; } +#if JVET_M0483_IBC + if (mi.isIBCmot) + { + return false; + } +#endif +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) +#else if (eRefPicList == REF_PIC_LIST_0 && pu.cs->slice->getRefPic(eRefPicList, refIdx)->getPOC() == pu.cs->slice->getPOC()) +#endif { return false; } @@ -1627,6 +2401,10 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList // Scale the vector. Mv cColMv = mi.mv[eColRefPicList]; +#if JVET_M0512_MOTION_BUFFER_COMPRESSION + cColMv.setHor(roundMvComp(cColMv.getHor())); + cColMv.setVer(roundMvComp(cColMv.getVer())); +#endif if (bIsCurrRefLongTerm /*|| bIsColRefLongTerm*/) { @@ -1687,7 +2465,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred) //left const PredictionUnit *neibLeftPU = NULL; neibLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, pu.cs->chType); +#if JVET_M0483_IBC + left = (neibLeftPU) ? CU::isIBC(*neibLeftPU->cu) : 0; +#else left = (neibLeftPU) ? neibLeftPU->cu->ibc : 0; +#endif if (left) { @@ -1699,7 +2481,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred) //above const PredictionUnit *neibAbovePU = NULL; neibAbovePU = pu.cs->getPURestricted(posRT.offset(0, -1), pu, pu.cs->chType); +#if JVET_M0483_IBC + above = (neibAbovePU) ? CU::isIBC(*neibAbovePU->cu) : 0; +#else above = (neibAbovePU) ? neibAbovePU->cu->ibc : 0; +#endif if (above) { @@ -1711,7 +2497,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred) // Below Left predictor search const PredictionUnit *neibBelowLeftPU = NULL; neibBelowLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 1), pu, pu.cs->chType); +#if JVET_M0483_IBC + unsigned int belowLeft = (neibBelowLeftPU) ? CU::isIBC(*neibBelowLeftPU->cu) : 0; +#else unsigned int belowLeft = (neibBelowLeftPU) ? neibBelowLeftPU->cu->ibc : 0; +#endif if (belowLeft) { @@ -1724,7 +2514,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred) // Above Right predictor search const PredictionUnit *neibAboveRightPU = NULL; neibAboveRightPU = pu.cs->getPURestricted(posRT.offset(1, -1), pu, pu.cs->chType); +#if JVET_M0483_IBC + unsigned int aboveRight = (neibAboveRightPU) ? CU::isIBC(*neibAboveRightPU->cu) : 0; +#else unsigned int aboveRight = (neibAboveRightPU) ? neibAboveRightPU->cu->ibc : 0; +#endif if (aboveRight) { @@ -1737,7 +2531,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred) // Above Left predictor search const PredictionUnit *neibAboveLeftPU = NULL; neibAboveLeftPU = pu.cs->getPURestricted(posLT.offset(-1, -1), pu, pu.cs->chType); +#if JVET_M0483_IBC + unsigned int aboveLeft = (neibAboveLeftPU) ? CU::isIBC(*neibAboveLeftPU->cu) : 0; +#else unsigned int aboveLeft = (neibAboveLeftPU) ? neibAboveLeftPU->cu->ibc : 0; +#endif if (aboveLeft) { @@ -1765,7 +2563,11 @@ bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv) const PredictionUnit *neibRefPU = NULL; neibRefPU = pu.cs->getPURestricted(pu.lumaPos().offset(offsetX, offsetY), pu, pu.cs->chType); +#if JVET_M0483_IBC + bool isIBC = (neibRefPU) ? CU::isIBC(*neibRefPU->cu) : 0; +#else bool isIBC = (neibRefPU) ? neibRefPU->cu->ibc : 0; +#endif if (isIBC) { derivedMv = neibRefPU->bv; @@ -1773,6 +2575,102 @@ bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv) } return isIBC; } + +#if JVET_M0483_IBC +/** + * Constructs a list of candidates for IBC AMVP (See specification, section "Derivation process for motion vector predictor candidates") + */ +void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo) +{ + CodingStructure &cs = *pu.cs; + + AMVPInfo *pInfo = &amvpInfo; + + pInfo->numCand = 0; + + //-- Get Spatial MV + Position posLT = pu.Y().topLeft(); + Position posRT = pu.Y().topRight(); + Position posLB = pu.Y().bottomLeft(); + + bool isScaledFlagLX = false; /// variable name from specification; true when the PUs below left or left are available (availableA0 || availableA1). + { + const PredictionUnit* tmpPU = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType); // getPUBelowLeft(idx, partIdxLB); + isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu); + if (!isScaledFlagLX) + { + tmpPU = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType); + isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu); + } + } + + // Left predictor search + if (isScaledFlagLX) + { + bool isAdded = addIBCMVPCand(pu, posLB, MD_BELOW_LEFT, *pInfo); + + if (!isAdded) + { + isAdded = addIBCMVPCand(pu, posLB, MD_LEFT, *pInfo); + } + } + + // Above predictor search + { + bool isAdded = addIBCMVPCand(pu, posRT, MD_ABOVE_RIGHT, *pInfo); + + if (!isAdded) + { + isAdded = addIBCMVPCand(pu, posRT, MD_ABOVE, *pInfo); + + if (!isAdded) + { + addIBCMVPCand(pu, posLT, MD_ABOVE_LEFT, *pInfo); + } + } + } + + if (pu.cu->imv != 0) + { + for (int i = 0; i < pInfo->numCand; i++) + { + pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); + } + } + + if (pInfo->numCand == 2) + { + if (pInfo->mvCand[0] == pInfo->mvCand[1]) + { + pInfo->numCand = 1; + } + } + + if (pInfo->numCand < AMVP_MAX_NUM_CANDS) + { + addAMVPHMVPCand(pu, REF_PIC_LIST_0, REF_PIC_LIST_1, cs.slice->getPOC(), *pInfo, pu.cu->imv); + } + + if (pInfo->numCand > AMVP_MAX_NUM_CANDS) + { + pInfo->numCand = AMVP_MAX_NUM_CANDS; + } + + while (pInfo->numCand < AMVP_MAX_NUM_CANDS) + { + pInfo->mvCand[pInfo->numCand] = Mv(0, 0); + pInfo->numCand++; + } + + for (Mv &mv : pInfo->mvCand) + { + mv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + mv.roundToAmvrSignalPrecision(MV_PRECISION_QUARTER, pu.cu->imv); + } +} + +#endif + /** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates") * \param uiPartIdx * \param uiPartAddr @@ -1862,6 +2760,12 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in } } +#if JVET_M0281_AMVP_ROUNDING || JVET_M0117_AMVP_LIST_GEN + for( int i = 0; i < pInfo->numCand; i++ ) + { + pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); + } +#else if( pu.cu->imv != 0) { for( int i = 0; i < pInfo->numCand; i++ ) @@ -1869,6 +2773,7 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); } } +#endif if( pInfo->numCand == 2 ) { @@ -1878,7 +2783,11 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in } } +#if JVET_M0281_AMVP_ROUNDING || JVET_M0117_AMVP_LIST_GEN + if( cs.slice->getEnableTMVPFlag() && pInfo->numCand < AMVP_MAX_NUM_CANDS ) +#else if( cs.slice->getEnableTMVPFlag() ) +#endif { // Get Temporal Motion Predictor const int refIdx_Col = refIdx; @@ -1929,10 +2838,17 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in if ((C0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdx_Col)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdx_Col)) #endif { +#if JVET_M0281_AMVP_ROUNDING || JVET_M0117_AMVP_LIST_GEN + cColMv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); +#else if (pu.cu->imv != 0) { - cColMv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); + cColMv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); } +#endif +#if JVET_M0117_AMVP_LIST_GEN + pInfo->mvCand[pInfo->numCand++] = cColMv; +#else int i = 0; for (i = 0; i < pInfo->numCand; i++) { @@ -1945,14 +2861,17 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in { pInfo->mvCand[pInfo->numCand++] = cColMv; } +#endif } } + if (pInfo->numCand < AMVP_MAX_NUM_CANDS) { const int currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC(); const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0; addAMVPHMVPCand(pu, eRefPicList, eRefPicList2nd, currRefPOC, *pInfo, pu.cu->imv); } + if (pInfo->numCand > AMVP_MAX_NUM_CANDS) { pInfo->numCand = AMVP_MAX_NUM_CANDS; @@ -1963,10 +2882,13 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 ); pInfo->numCand++; } + for (Mv &mv : pInfo->mvCand) { mv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if !JVET_M0281_AMVP_ROUNDING && !JVET_M0117_AMVP_LIST_GEN mv.roundToAmvrSignalPrecision(MV_PRECISION_QUARTER, pu.cu->imv); +#endif } } @@ -2023,14 +2945,36 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r } xInheritedAffineMv( pu, neibPU, eRefPicListIndex, outputAffineMv ); - - outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0]; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1]; if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { - outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2]; } affiAMVPInfo.numCand++; @@ -2051,7 +2995,7 @@ void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puN int curW = pu.Y().width; int neiH = puNeighbour->Y().height; int curH = pu.Y().height; - + Mv mvLT, mvRT, mvLB; mvLT = puNeighbour->mvAffi[eRefPicList][0]; mvRT = puNeighbour->mvAffi[eRefPicList][1]; @@ -2095,6 +3039,9 @@ void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puN roundAffineMv( horTmp, verTmp, shift ); rcMv[0].hor = horTmp; rcMv[0].ver = verTmp; +#if JVET_M0145_AFFINE_MV_CLIP + rcMv[0].clipToStorageBitDepth(); +#endif // v1 horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY); @@ -2102,6 +3049,9 @@ void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puN roundAffineMv( horTmp, verTmp, shift ); rcMv[1].hor = horTmp; rcMv[1].ver = verTmp; +#if JVET_M0145_AFFINE_MV_CLIP + rcMv[1].clipToStorageBitDepth(); +#endif // v2 if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) @@ -2111,6 +3061,9 @@ void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puN roundAffineMv( horTmp, verTmp, shift ); rcMv[2].hor = horTmp; rcMv[2].ver = verTmp; +#if JVET_M0145_AFFINE_MV_CLIP + rcMv[2].clipToStorageBitDepth(); +#endif } } @@ -2131,7 +3084,7 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co Position posRT = pu.Y().topRight(); Position posLB = pu.Y().bottomLeft(); - // check left neighbor + // check left neighbor if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, affiAMVPInfo ) ) { addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, affiAMVPInfo ); @@ -2150,9 +3103,16 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co { for (int i = 0; i < affiAMVPInfo.numCand; i++) { - affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif } return; } @@ -2204,10 +3164,22 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co outputAffineMv[1] = amvpInfo1.mvCand[0]; outputAffineMv[2] = amvpInfo2.mvCand[0]; - - outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif if ( cornerMVPattern == 7 || (cornerMVPattern == 3 && pu.cu->affineType == AFFINEMODEL_4PARAM) ) { @@ -2282,7 +3254,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co if ( (C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol )) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol ) ) #endif { - cColMv.roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + cColMv.roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + cColMv.roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv; @@ -2303,15 +3286,63 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } } - for (int i = 0; i < affiAMVPInfo.numCand; i++) + for (int i = 0; i < affiAMVPInfo.numCand; i++) + { +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif + } + + +} + +#if JVET_M0483_IBC +bool PU::addIBCMVPCand(const PredictionUnit &pu, const Position &pos, const MvpDir &eDir, AMVPInfo &info) +{ + CodingStructure &cs = *pu.cs; + const PredictionUnit *neibPU = NULL; + Position neibPos; + + switch (eDir) { - affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + case MD_LEFT: + neibPos = pos.offset(-1, 0); + break; + case MD_ABOVE: + neibPos = pos.offset(0, -1); + break; + case MD_ABOVE_RIGHT: + neibPos = pos.offset(1, -1); + break; + case MD_BELOW_LEFT: + neibPos = pos.offset(-1, 1); + break; + case MD_ABOVE_LEFT: + neibPos = pos.offset(-1, -1); + break; + default: + break; } + neibPU = cs.getPURestricted(neibPos, pu, pu.chType); + + if (neibPU == NULL || CU::isIBC(*neibPU->cu)==false) + { + return false; + } + const MotionInfo& neibMi = neibPU->getMotionInfo(neibPos); + info.mvCand[info.numCand++] = neibMi.mv[REF_PIC_LIST_0]; + return true; } +#endif bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &info ) { @@ -2405,7 +3436,11 @@ bool PU::addMVPCandWithScaling( const PredictionUnit &pu, const RefPicList &eRef neibPU = cs.getPURestricted( neibPos, pu, pu.chType ); +#if JVET_M0483_IBC + if (neibPU == NULL || !CU::isInter(*neibPU->cu) || !CU::isInter(*pu.cu)) +#else if( neibPU == NULL || !CU::isInter( *neibPU->cu ) ) +#endif { return false; } @@ -2456,8 +3491,15 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const Slice &slice = *(*pu.cs).slice; MotionInfo neibMi; +#if !JVET_M0117_AMVP_LIST_GEN int i = 0; +#endif +#if JVET_M0483_IBC + int offset = CU::isIBC(*pu.cu) ? MAX_NUM_HMVP_CANDS : 0; + int num_avai_candInLUT = CU::isIBC(*pu.cu) ? slice.getAvailableLUTIBCMrgNum() : slice.getAvailableLUTMrgNum(); +#else int num_avai_candInLUT = slice.getAvailableLUTMrgNum(); +#endif int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT); for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++) @@ -2466,20 +3508,48 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, { return; } +#if JVET_M0117_AMVP_LIST_GEN +#if JVET_M0483_IBC + neibMi = slice.getMotionInfoFromLUTs(mrgIdx - 1 + offset) ; +#else + neibMi = slice.getMotionInfoFromLUTs(mrgIdx - 1); +#endif +#else +#if JVET_M0483_IBC + neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx + offset); +#else neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx); +#endif +#endif - for (int predictorSource = 0; predictorSource < 2; predictorSource++) + for (int predictorSource = 0; predictorSource < 2; predictorSource++) { const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd; const int neibRefIdx = neibMi.refIdx[eRefPicListIndex]; +#if JVET_M0483_IBC + if (neibRefIdx >= 0 && (CU::isIBC(*pu.cu) || (currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx)))) +#else if (neibRefIdx >= 0 && currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx)) +#endif { Mv pmv = neibMi.mv[eRefPicListIndex]; +#if JVET_M0281_AMVP_ROUNDING || JVET_M0117_AMVP_LIST_GEN + pmv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv); +#else if (imv != 0) { pmv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, imv); } +#endif + +#if JVET_M0117_AMVP_LIST_GEN + info.mvCand[info.numCand++] = pmv; + if (info.numCand >= AMVP_MAX_NUM_CANDS) + { + return; + } +#else for (i = 0; i < info.numCand; i++) { if (pmv == info.mvCand[i]) @@ -2495,10 +3565,12 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, return; } } +#endif } } } } + bool PU::isBipredRestriction(const PredictionUnit &pu) { if(pu.cu->lumaSize().width == 4 && pu.cu->lumaSize().height ==4 ) @@ -2535,7 +3607,11 @@ void PU::getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4], if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 ) { // check same refidx and different mv +#if JVET_M0228_REMOVE_CPMV_COMPARE + if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l]) +#else if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].mv[l] != mi[idx1].mv[l] ) +#endif { dir |= (l + 1); refIdx[l] = mi[idx0].refIdx[l]; @@ -2556,7 +3632,11 @@ void PU::getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4], if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 && mi[idx2].refIdx[l] >= 0 ) { // check same refidx and different mv +#if JVET_M0228_REMOVE_CPMV_COMPARE + if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].refIdx[l] == mi[idx2].refIdx[l]) +#else if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].refIdx[l] == mi[idx2].refIdx[l] && (mi[idx0].mv[l] != mi[idx1].mv[l] || mi[idx0].mv[l] != mi[idx2].mv[l]) ) +#endif { dir |= (l + 1); refIdx[l] = mi[idx0].refIdx[l]; @@ -2730,7 +3810,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx bool isAvailableSubPu = false; if ( enableSubPuMvp && slice.getEnableTMVPFlag() ) { -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 int cntIBC = 0; #endif MergeCtx mrgCtx = *affMrgCtx.mrgCtx; @@ -2741,9 +3821,14 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx int pos = 0; // Get spatial MV +#if JVET_M0116_ATMVP_LEFT_NB_FOR_OFFSET + const Position posCurLB = pu.Y().bottomLeft(); + MotionInfo miLeft; +#else const Position posCurRT = pu.Y().topRight(); const Position posCurLB = pu.Y().bottomLeft(); MotionInfo miAbove, miLeft, miAboveRight, miBelowLeft; +#endif //left const PredictionUnit* puLeft = cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType ); @@ -2755,7 +3840,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx mrgCtx.interDirNeighbours[pos] = miLeft.interDir; // get Mv from Left -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 if (puLeft->cu->ibc) { cntIBC++; @@ -2770,6 +3855,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx pos++; } +#if !JVET_M0116_ATMVP_LEFT_NB_FOR_OFFSET // above const PredictionUnit *puAbove = cs.getPURestricted( posCurRT.offset( 0, -1 ), pu, pu.chType ); bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu ); @@ -2782,7 +3868,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx // get Inter Dir mrgCtx.interDirNeighbours[pos] = miAbove.interDir; // get Mv from Left -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 if (puAbove->cu->ibc) { cntIBC++; @@ -2815,7 +3901,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx // get Inter Dir mrgCtx.interDirNeighbours[pos] = miAboveRight.interDir; // get Mv from Left -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 if (puAboveRight->cu->ibc) { cntIBC++; @@ -2848,7 +3934,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx // get Inter Dir mrgCtx.interDirNeighbours[pos] = miBelowLeft.interDir; // get Mv from Bottom-Left -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 if (puLeftBottom->cu->ibc) { cntIBC++; @@ -2863,11 +3949,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx pos++; } } +#endif mrgCtx.numValidMergeCand = pos; isAvailableSubPu = getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, pos , 0 -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 , cntIBC #endif ); @@ -2897,7 +3984,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx } } - if ( slice.getSPS()->getSpsNext().getUseAffine() ) + if ( slice.getSPS()->getUseAffine() ) { ///> Start: inherited affine candidates const PredictionUnit* npu[5]; @@ -2957,7 +4044,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType ); if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_M0483_IBC==0 && !puNeigh->cu->ibc +#endif ) { isAvailable[0] = true; @@ -2974,8 +4063,10 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType ); - if ( puNeigh && CU::isInter( *puNeigh->cu ) + if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_M0483_IBC==0 && !puNeigh->cu->ibc +#endif ) { isAvailable[1] = true; @@ -2992,8 +4083,10 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType ); - if ( puNeigh && CU::isInter( *puNeigh->cu ) + if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_M0483_IBC==0 && !puNeigh->cu->ibc +#endif ) { isAvailable[2] = true; @@ -3077,7 +4170,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx }; int verNum[6] = { 3, 3, 3, 3, 2, 2 }; - int startIdx = pu.cs->sps->getSpsNext().getUseAffineType() ? 0 : 4; + int startIdx = pu.cs->sps->getUseAffineType() ? 0 : 4; for ( int idx = startIdx; idx < modelNum; idx++ ) { int modelIdx = order[idx]; @@ -3182,13 +4275,21 @@ void PU::setAllAffineMv( PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPi mvScaleTmpHor = mvScaleHor + deltaMvHorX * (halfBW + w) + deltaMvVerX * (halfBH + h); mvScaleTmpVer = mvScaleVer + deltaMvHorY * (halfBW + w) + deltaMvVerY * (halfBH + h); roundAffineMv( mvScaleTmpHor, mvScaleTmpVer, shift ); +#if JVET_M0145_AFFINE_MV_CLIP + Mv curMv(mvScaleTmpHor, mvScaleTmpVer); + curMv.clipToStorageBitDepth(); +#endif for ( int y = (h >> MIN_CU_LOG2); y < ((h + blockHeight) >> MIN_CU_LOG2); y++ ) { for ( int x = (w >> MIN_CU_LOG2); x < ((w + blockWidth) >> MIN_CU_LOG2); x++ ) { +#if JVET_M0145_AFFINE_MV_CLIP + mb.at(x, y).mv[eRefList] = curMv; +#else mb.at(x, y).mv[eRefList].hor = mvScaleTmpHor; mb.at(x, y).mv[eRefList].ver = mvScaleTmpVer; +#endif } } } @@ -3260,6 +4361,10 @@ static bool deriveScaledMotionTemporal( const Slice& slice, iCurrRefPOC = slice.getRefPic(eCurrRefPicList, 0)->getPOC(); // Scale the vector. cColMv = mi.mv[eColRefPicList]; +#if JVET_M0512_MOTION_BUFFER_COMPRESSION + cColMv.setHor(roundMvComp(cColMv.getHor())); + cColMv.setVer(roundMvComp(cColMv.getVer())); +#endif //pcMvFieldSP[2*iPartition + eCurrRefPicList].getMv(); // Assume always short-term for now iScale = xGetDistScaleFactor(iCurrPOC, iCurrRefPOC, iColPOC, iColRefPOC); @@ -3292,13 +4397,13 @@ void clipColPos(int& posX, int& posY, const PredictionUnit& pu) bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count , int mmvdList -#if !JVET_M0409_ATMVP_FIX +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 , const int countIBC #endif ) { -#if !JVET_M0409_ATMVP_FIX - if (count == countIBC && pu.cs->slice->getSPS()->getSpsNext().getIBCMode()) +#if !JVET_M0409_ATMVP_FIX && JVET_M0483_IBC==0 + if (count == countIBC && pu.cs->slice->getSPS()->getIBCMode()) return false; #endif const Slice &slice = *pu.cs->slice; @@ -3315,7 +4420,7 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b if ( count ) { RefPicList currRefPicList = RefPicList(slice.getCheckLDC() ? (slice.getColFromL0Flag() ? currRefListId : 1 - currRefListId) : currRefListId); - + if ((mrgCtx.interDirNeighbours[0] & (1 << currRefPicList)) && slice.getRefPic(currRefPicList, mrgCtx.mvFieldNeighbours[0 * 2 + currRefPicList].refIdx) == pColPic) { cTMv = mrgCtx.mvFieldNeighbours[0 * 2 + currRefPicList].mv; @@ -3363,7 +4468,11 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b // derivation of center motion parameters from the collocated CU const MotionInfo &mi = pColPic->cs->getMotionInfo(centerPos); +#if JVET_M0483_IBC + if (mi.isInter && mi.isIBCmot == false) +#else if (mi.isInter) +#endif { for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++) { @@ -3413,9 +4522,19 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b MotionInfo mi; + // initialize to default vector in case no motion vector is available + mi.mv[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].mv; + mi.mv[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].mv; + mi.refIdx[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].refIdx; + mi.refIdx[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].refIdx; mi.isInter = true; mi.sliceIdx = slice.getIndependentSliceIdx(); - if (colMi.isInter && !((colMi.interDir == 1 || colMi.interDir == 3) && (pColPic->cs->slice->getRefPOC(REF_PIC_LIST_0, colMi.refIdx[0]) == pColPic->cs->slice->getPOC()) && pu.cs->sps->getSpsNext().getIBCMode())) +#if JVET_M0483_IBC + mi.isIBCmot = false; + if (colMi.isInter && colMi.isIBCmot == false) +#else + if (colMi.isInter && !((colMi.interDir == 1 || colMi.interDir == 3) && (pColPic->cs->slice->getRefPOC(REF_PIC_LIST_0, colMi.refIdx[0]) == pColPic->cs->slice->getPOC()) && pu.cs->sps->getIBCMode())) +#endif { for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++) { @@ -3426,14 +4545,6 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b mi.mv[currRefListId] = cColMv; } } - } - else - { - // intra coded, in this case, no motion vector is available for list 0 or list 1, so use default - mi.mv[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].mv; - mi.mv[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].mv; - mi.refIdx[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].refIdx; - mi.refIdx[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].refIdx; } mi.interDir = (mi.refIdx[0] != -1 ? 1 : 0) + (mi.refIdx[1] != -1 ? 2 : 0); @@ -3456,13 +4567,18 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx ) { MotionBuf mb = pu.getMotionBuf(); - if( !pu.mergeFlag || pu.mergeType == MRG_TYPE_DEFAULT_N + if( !pu.mergeFlag || pu.mergeType == MRG_TYPE_DEFAULT_N || pu.mergeType == MRG_TYPE_IBC ) { MotionInfo mi; +#if JVET_M0483_IBC + mi.isInter = !CU::isIntra(*pu.cu); + mi.isIBCmot = CU::isIBC(*pu.cu); +#else mi.isInter = CU::isInter( *pu.cu ); +#endif mi.sliceIdx = pu.cu->slice->getIndependentSliceIdx(); if( mi.isInter ) @@ -3474,7 +4590,11 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx ) mi.mv[i] = pu.mv[i]; mi.refIdx[i] = pu.refIdx[i]; } +#if JVET_M0483_IBC + if (mi.isIBCmot) +#else if (pu.interDir == 1 && pu.cu->slice->getRefPOC(REF_PIC_LIST_0, pu.refIdx[0]) == pu.cu->slice->getPOC()) +#endif { mi.bv = pu.bv; } @@ -3488,6 +4608,9 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx ) { MotionInfo &dest = mb.at( x, y ); dest.isInter = mi.isInter; +#if JVET_M0483_IBC + dest.isIBCmot = false; +#endif dest.interDir = mi.interDir; dest.sliceIdx = mi.sliceIdx; for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ ) @@ -3542,15 +4665,24 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP pu.mvd[0].changePrecisionAmvr( pu.cu->imv, MV_PRECISION_QUARTER); unsigned mvp_idx = pu.mvpIdx[0]; AMVPInfo amvpInfo; +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + { + PU::fillIBCMvpCand(pu, amvpInfo); + } + else +#endif PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo); pu.mvpNum[0] = amvpInfo.numCand; pu.mvpIdx[0] = mvp_idx; pu.mv [0] = amvpInfo.mvCand[mvp_idx] + pu.mvd[0]; pu.mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0483_IBC==0 if (pu.interDir == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0])->getPOC() == pu.cs->slice->getPOC()) { pu.cu->ibc = true; } +#endif } if (pu.interDir != 1 /* PRED_L0 */) @@ -3572,7 +4704,7 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP { // this function is never called for merge THROW("unexpected"); - PU::getInterMergeCandidates ( pu, mrgCtx + PU::getInterMergeCandidates ( pu, mrgCtx , 0 ); #if !JVET_M0068_M0171_MMVD_CLEANUP @@ -3600,7 +4732,25 @@ bool PU::isBiPredFromDifferentDir( const PredictionUnit& pu ) return false; } - +#if JVET_M0147_DMVR +bool PU::isBiPredFromDifferentDirEqDistPoc(const PredictionUnit& pu) +{ + if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0) + { + const int poc0 = pu.cu->slice->getRefPOC(REF_PIC_LIST_0, pu.refIdx[0]); + const int poc1 = pu.cu->slice->getRefPOC(REF_PIC_LIST_1, pu.refIdx[1]); + const int poc = pu.cu->slice->getPOC(); + if ((poc - poc0)*(poc - poc1) < 0) + { + if (abs(poc - poc0) == abs(poc - poc1)) + { + return true; + } + } + } + return false; +} +#endif void PU::restrictBiPredMergeCands( const PredictionUnit &pu, MergeCtx& mergeCtx ) { if( PU::isBipredRestriction( pu ) ) @@ -3662,7 +4812,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl //left const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType ); const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu ) +#if JVET_M0483_IBC==0 && !puLeft->cu->ibc +#endif ; if( isAvailableA1 ) { @@ -3679,12 +4831,14 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl // above const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType ); bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu ) +#if JVET_M0483_IBC==0 && !puAbove->cu->ibc +#endif ; if( isAvailableB1 ) { miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) ); - + if( !isAvailableA1 || ( miAbove != miLeft ) ) { candidate[candCount].isInter = true; @@ -3696,11 +4850,13 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl candCount++; } } - + // above right const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType ); bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu ) +#if JVET_M0483_IBC==0 && !puAboveRight->cu->ibc +#endif ; if( isAvailableB0 ) @@ -3717,17 +4873,19 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl candidate[candCount].refIdx[1] = miAboveRight.refIdx[1]; candCount++; } - } + } //left bottom const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType ); bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu ) +#if JVET_M0483_IBC==0 && !puLeftBottom->cu->ibc +#endif ; if( isAvailableA0 ) { miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) ); - + if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) ) { candidate[candCount].isInter = true; @@ -3743,7 +4901,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl // above left const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType ); bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu ) +#if JVET_M0483_IBC==0 && !puAboveLeft->cu->ibc +#endif ; if( isAvailableB2 ) @@ -3761,7 +4921,7 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl candCount++; } } - + if( slice.getEnableTMVPFlag() ) { Position posRB = pu.Y().bottomRight().offset(-3, -3); @@ -3833,7 +4993,7 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl candidate[candCount].refIdx[1] = temporalMv.refIdx[1]; candCount++; } - + // C1 temporalMv.interDir = 0; #if JVET_M0170_MRG_SHARELIST @@ -3871,10 +5031,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl candCount++; } } - // put uni-prediction candidate to the triangle candidate list for( int32_t i = 0; i < candCount; i++ ) - { + { if( candidate[i].interDir != 3 ) { triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = candidate[i].interDir; @@ -3943,9 +5102,13 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl { aveMv = aveMv.scaleMv( distscale ); // scaling to L0 } +#if JVET_M0265_MV_ROUNDING_CLEANUP + aveMv = aveMv + candidate[i].mv[0]; + roundAffineMv(aveMv.hor, aveMv.ver, 1); +#else aveMv.setHor( ( aveMv.getHor() + candidate[i].mv[0].getHor() + 1 ) >> 1 ); aveMv.setVer( ( aveMv.getVer() + candidate[i].mv[0].getVer() + 1 ) >> 1 ); - +#endif triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1; triangleMrgCtx.mrgTypeNeighbours [triangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N; triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) ].mv = aveMv; @@ -3958,8 +5121,8 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl return; } } - } - + } + // fill with Mv(0, 0) int32_t numRefIdx = std::min( slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1) ); int32_t cnt = 0; @@ -3969,20 +5132,24 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl { triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 1; triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].setMvField(Mv(0, 0), cnt); + triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = NOT_VALID; + triangleMrgCtx.mvFieldNeighbours[(triangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(); triangleMrgCtx.numValidMergeCand++; - + if( triangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) { return; } - + triangleMrgCtx.interDirNeighbours[triangleMrgCtx.numValidMergeCand] = 2; triangleMrgCtx.mvFieldNeighbours [(triangleMrgCtx.numValidMergeCand << 1) + 1 ].setMvField(Mv(0, 0), cnt); + triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].refIdx = NOT_VALID; + triangleMrgCtx.mvFieldNeighbours[triangleMrgCtx.numValidMergeCand << 1].mv = Mv(); triangleMrgCtx.numValidMergeCand++; - + cnt = (cnt + 1) % numRefIdx; } - } + } } bool PU::isUniqueTriangleCandidates( const PredictionUnit &pu, MergeCtx& triangleMrgCtx ) @@ -3999,26 +5166,27 @@ bool PU::isUniqueTriangleCandidates( const PredictionUnit &pu, MergeCtx& triangl return false; } } - return true; + return true; } +#if !JVET_M0328_KEEP_ONE_WEIGHT_GROUP bool PU::getTriangleWeights( const PredictionUnit& pu, MergeCtx &triangleMrgCtx, const uint8_t candIdx0, const uint8_t candIdx1 ) { RefPicList refPicListCand0 = triangleMrgCtx.interDirNeighbours[candIdx0] == 1 ? REF_PIC_LIST_0 : REF_PIC_LIST_1; RefPicList refPicListCand1 = triangleMrgCtx.interDirNeighbours[candIdx1] == 1 ? REF_PIC_LIST_0 : REF_PIC_LIST_1; int32_t refPicPoc0 = pu.cs->slice->getRefPOC( refPicListCand0, triangleMrgCtx.mvFieldNeighbours[ (candIdx0 << 1) + refPicListCand0 ].refIdx ); int32_t refPicPoc1 = pu.cs->slice->getRefPOC( refPicListCand1, triangleMrgCtx.mvFieldNeighbours[ (candIdx1 << 1) + refPicListCand1 ].refIdx ); - + if( refPicPoc0 != refPicPoc1 ) { // different reference picture return true; } - + // same reference picture, but mv difference is larger than 16 pel int32_t threshold = 16 << 4; Mv diffMv = triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + refPicListCand0].mv - triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + refPicListCand1].mv; - + if( diffMv.getAbsHor() > threshold || diffMv.getAbsVer() > threshold ) { return true; @@ -4026,15 +5194,26 @@ bool PU::getTriangleWeights( const PredictionUnit& pu, MergeCtx &triangleMrgCtx, return false; } +#endif +#if JVET_M0883_TRIANGLE_SIGNALING +void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 ) +#else void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, const uint8_t mergeIdx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1 ) +#endif { +#if JVET_M0883_TRIANGLE_SIGNALING + pu.triangleSplitDir = splitDir; + pu.triangleMergeIdx0 = candIdx0; + pu.triangleMergeIdx1 = candIdx1; +#else pu.mergeIdx = mergeIdx; +#endif MotionBuf mb = pu.getMotionBuf(); MotionInfo biMv; biMv.isInter = true; - + if( triangleMrgCtx.interDirNeighbours[candIdx0] == 1 && triangleMrgCtx.interDirNeighbours[candIdx1] == 2 ) { biMv.interDir = 3; @@ -4089,7 +5268,7 @@ void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, c biMv.interDir = ( refIdx != -1 ) ? 3 : 2; biMv.mv[0] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv : Mv(0, 0); biMv.mv[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv : triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].mv; - biMv.refIdx[0] = ( refIdx != -1 ) ? refIdx : -1; + biMv.refIdx[0] = ( refIdx != -1 ) ? refIdx : -1; biMv.refIdx[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx : triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx; } } @@ -4158,6 +5337,11 @@ void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred ) Mv mv = pu.mv[0]; Mv mvPred; AMVPInfo amvpInfo; +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + PU::fillIBCMvpCand(pu, amvpInfo); + else +#endif PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo); pu.mvpNum[0] = amvpInfo.numCand; @@ -4194,7 +5378,7 @@ void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred ) } else { - PU::getInterMergeCandidates ( pu, mrgCtx + PU::getInterMergeCandidates ( pu, mrgCtx , 0 ); #if !JVET_M0068_M0171_MMVD_CLEANUP @@ -4235,6 +5419,47 @@ bool CU::hasSubCUNonZeroMVd( const CodingUnit& cu ) return bNonZeroMvd; } +#if JVET_M0246_AFFINE_AMVR +bool CU::hasSubCUNonZeroAffineMVd( const CodingUnit& cu ) +{ + bool nonZeroAffineMvd = false; + + if ( !cu.affine || cu.firstPU->mergeFlag ) + { + return false; + } + + for ( const auto &pu : CU::traversePUs( cu ) ) + { + if ( ( !pu.mergeFlag ) && ( !cu.skip ) ) + { + if ( pu.interDir != 2 /* PRED_L1 */ ) + { + for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ ) + { + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_0][i].getHor() != 0; + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_0][i].getVer() != 0; + } + } + + if ( pu.interDir != 1 /* PRED_L0 */ ) + { + if ( !pu.cu->cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ ) + { + for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ ) + { + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_1][i].getHor() != 0; + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_1][i].getVer() != 0; + } + } + } + } + } + + return nonZeroAffineMvd; +} +#endif + int CU::getMaxNeighboriMVCandNum( const CodingStructure& cs, const Position& pos ) { const int numDefault = 0; @@ -4259,14 +5484,136 @@ int CU::getMaxNeighboriMVCandNum( const CodingStructure& cs, const Position& pos return maxImvNumCand; } +#if JVET_M0140_SBT +uint8_t CU::getSbtInfo( uint8_t idx, uint8_t pos ) +{ + return ( pos << 4 ) + ( idx << 0 ); +} + +uint8_t CU::getSbtIdx( const uint8_t sbtInfo ) +{ + return ( sbtInfo >> 0 ) & 0xf; +} + +uint8_t CU::getSbtPos( const uint8_t sbtInfo ) +{ + return ( sbtInfo >> 4 ) & 0x3; +} + +uint8_t CU::getSbtMode( uint8_t sbtIdx, uint8_t sbtPos ) +{ + uint8_t sbtMode = 0; + switch( sbtIdx ) + { + case SBT_VER_HALF: sbtMode = sbtPos + SBT_VER_H0; break; + case SBT_HOR_HALF: sbtMode = sbtPos + SBT_HOR_H0; break; + case SBT_VER_QUAD: sbtMode = sbtPos + SBT_VER_Q0; break; + case SBT_HOR_QUAD: sbtMode = sbtPos + SBT_HOR_Q0; break; + default: assert( 0 ); + } + + assert( sbtMode < NUMBER_SBT_MODE ); + return sbtMode; +} + +uint8_t CU::getSbtIdxFromSbtMode( uint8_t sbtMode ) +{ + if( sbtMode <= SBT_VER_H1 ) + return SBT_VER_HALF; + else if( sbtMode <= SBT_HOR_H1 ) + return SBT_HOR_HALF; + else if( sbtMode <= SBT_VER_Q1 ) + return SBT_VER_QUAD; + else if( sbtMode <= SBT_HOR_Q1 ) + return SBT_HOR_QUAD; + else + { + assert( 0 ); + return 0; + } +} + +uint8_t CU::getSbtPosFromSbtMode( uint8_t sbtMode ) +{ + if( sbtMode <= SBT_VER_H1 ) + return sbtMode - SBT_VER_H0; + else if( sbtMode <= SBT_HOR_H1 ) + return sbtMode - SBT_HOR_H0; + else if( sbtMode <= SBT_VER_Q1 ) + return sbtMode - SBT_VER_Q0; + else if( sbtMode <= SBT_HOR_Q1 ) + return sbtMode - SBT_HOR_Q0; + else + { + assert( 0 ); + return 0; + } +} + +uint8_t CU::targetSbtAllowed( uint8_t sbtIdx, uint8_t sbtAllowed ) +{ + uint8_t val = 0; + switch( sbtIdx ) + { + case SBT_VER_HALF: val = ( ( sbtAllowed >> SBT_VER_HALF ) & 0x1 ); break; + case SBT_HOR_HALF: val = ( ( sbtAllowed >> SBT_HOR_HALF ) & 0x1 ); break; + case SBT_VER_QUAD: val = ( ( sbtAllowed >> SBT_VER_QUAD ) & 0x1 ); break; + case SBT_HOR_QUAD: val = ( ( sbtAllowed >> SBT_HOR_QUAD ) & 0x1 ); break; + default: CHECK( 1, "unknown SBT type" ); + } + return val; +} + +uint8_t CU::numSbtModeRdo( uint8_t sbtAllowed ) +{ + uint8_t num = 0; + uint8_t sum = 0; + num = targetSbtAllowed( SBT_VER_HALF, sbtAllowed ) + targetSbtAllowed( SBT_HOR_HALF, sbtAllowed ); + sum += std::min( SBT_NUM_RDO, ( num << 1 ) ); + num = targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ); + sum += std::min( SBT_NUM_RDO, ( num << 1 ) ); + return sum; +} + +bool CU::isMtsMode( const uint8_t sbtInfo ) +{ + return getSbtIdx( sbtInfo ) == SBT_OFF_MTS; +} + +bool CU::isSbtMode( const uint8_t sbtInfo ) +{ + uint8_t sbtIdx = getSbtIdx( sbtInfo ); + return sbtIdx >= SBT_VER_HALF && sbtIdx <= SBT_HOR_QUAD; +} + +bool CU::isSameSbtSize( const uint8_t sbtInfo1, const uint8_t sbtInfo2 ) +{ + uint8_t sbtIdx1 = getSbtIdxFromSbtMode( sbtInfo1 ); + uint8_t sbtIdx2 = getSbtIdxFromSbtMode( sbtInfo2 ); + if( sbtIdx1 == SBT_HOR_HALF || sbtIdx1 == SBT_VER_HALF ) + return sbtIdx2 == SBT_HOR_HALF || sbtIdx2 == SBT_VER_HALF; + else if( sbtIdx1 == SBT_HOR_QUAD || sbtIdx1 == SBT_VER_QUAD ) + return sbtIdx2 == SBT_HOR_QUAD || sbtIdx2 == SBT_VER_QUAD; + else + return false; +} +#endif + bool CU::isGBiIdxCoded( const CodingUnit &cu ) { - if( cu.cs->sps->getSpsNext().getUseGBi() == false ) + if( cu.cs->sps->getUseGBi() == false ) { CHECK(cu.GBiIdx != GBI_DEFAULT, "Error: cu.GBiIdx != GBI_DEFAULT"); return false; } +#if JVET_M0483_IBC + if (cu.predMode == MODE_IBC) + { + return false; + } +#endif + if( cu.predMode == MODE_INTRA || cu.cs->slice->isInterP() ) { return false; @@ -4362,14 +5709,6 @@ uint8_t CU::deriveGbiIdx( uint8_t gbiLO, uint8_t gbiL1 ) // TU tools -#if HEVC_USE_4x4_DSTVII -bool TU::useDST(const TransformUnit &tu, const ComponentID &compID) -{ - return isLuma(compID) && tu.cu->predMode == MODE_INTRA; -} - -#endif - bool TU::isNonTransformedResidualRotated(const TransformUnit &tu, const ComponentID &compID) { return tu.cs->sps->getSpsRangeExtension().getTransformSkipRotationEnabledFlag() && tu.blocks[compID].width == 4 && tu.cu->predMode == MODE_INTRA; @@ -4401,9 +5740,15 @@ bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID) tsAllowed &= tu.cs->pps->getUseTransformSkip(); tsAllowed &= !tu.cu->transQuantBypass; +#if JVET_M0102_INTRA_SUBPARTITIONS + tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) ); +#endif SizeType transformSkipMaxSize = 1 << maxSize; tsAllowed &= tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize; +#if JVET_M0140_SBT + tsAllowed &= !tu.cu->sbtInfo; +#endif return tsAllowed; } @@ -4413,8 +5758,14 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID) bool mtsAllowed = compID == COMPONENT_Y; const int maxSize = CU::isIntra( *tu.cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE; - mtsAllowed &= CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraMTS() : tu.cs->sps->getSpsNext().getUseInterMTS(); + mtsAllowed &= CU::isIntra( *tu.cu ) ? tu.cs->sps->getUseIntraMTS() : tu.cs->sps->getUseInterMTS(); mtsAllowed &= ( tu.lwidth() <= maxSize && tu.lheight() <= maxSize ); +#if JVET_M0102_INTRA_SUBPARTITIONS + mtsAllowed &= !tu.cu->ispMode; +#endif +#if JVET_M0140_SBT + mtsAllowed &= !tu.cu->sbtInfo; +#endif return mtsAllowed; } #else @@ -4506,8 +5857,13 @@ uint32_t TU::getCoefScanIdx(const TransformUnit &tu, const ComponentID &compID) #endif bool TU::hasCrossCompPredInfo( const TransformUnit &tu, const ComponentID &compID ) { +#if JVET_M0483_IBC + return (isChroma(compID) && tu.cs->pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf(tu, COMPONENT_Y) && + (!CU::isIntra(*tu.cu) || PU::isChromaIntraModeCrossCheckMode(*tu.cs->getPU(tu.blocks[compID].pos(), toChannelType(compID))))); +#else return ( isChroma(compID) && tu.cs->pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( tu, COMPONENT_Y ) && ( CU::isInter(*tu.cu) || PU::isChromaIntraModeCrossCheckMode( *tu.cs->getPU( tu.blocks[compID].pos(), toChannelType( compID ) ) ) ) ); +#endif } uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma, const bool bChroma ) @@ -4535,17 +5891,37 @@ uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma return count; } +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT +bool TU::needsSqrt2Scale( const TransformUnit &tu, const ComponentID &compID ) +{ + const Size &size=tu.blocks[compID]; +#if JVET_M0464_UNI_MTS + const bool isTransformSkip = tu.mtsIdx==1 && isLuma(compID); +#else + const bool isTransformSkip = tu.transformSkip[compID]; +#endif + return (!isTransformSkip) && (((g_aucLog2[size.width] + g_aucLog2[size.height]) & 1) == 1); +} +#else bool TU::needsSqrt2Scale( const Size& size ) { return (((g_aucLog2[size.width] + g_aucLog2[size.height]) & 1) == 1); } +#endif #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT +bool TU::needsBlockSizeTrafoScale( const TransformUnit &tu, const ComponentID &compID ) +{ + return needsSqrt2Scale( tu, compID ) || isNonLog2BlockSize( tu.blocks[compID] ); +} +#else bool TU::needsBlockSizeTrafoScale( const Size& size ) { return needsSqrt2Scale( size ) || isNonLog2BlockSize( size ); } +#endif #else bool TU::needsQP3Offset(const TransformUnit &tu, const ComponentID &compID) { @@ -4558,7 +5934,57 @@ bool TU::needsQP3Offset(const TransformUnit &tu, const ComponentID &compID) #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +TransformUnit* TU::getPrevTU( const TransformUnit &tu, const ComponentID compID ) +{ + TransformUnit* prevTU = tu.prev; + + if( prevTU != nullptr && ( prevTU->cu != tu.cu || !prevTU->blocks[compID].valid() ) ) + { + prevTU = nullptr; + } + + return prevTU; +} + +bool TU::getPrevTuCbfAtDepth( const TransformUnit ¤tTu, const ComponentID compID, const int trDepth ) +{ + const TransformUnit* prevTU = getPrevTU( currentTu, compID ); + return ( prevTU != nullptr ) ? TU::getCbfAtDepth( *prevTU, compID, trDepth ) : false; +} + +void TU::getTransformTypeISP( const TransformUnit &tu, const ComponentID compID, int &typeH, int &typeV ) +{ + typeH = DCT2, typeV = DCT2; + const int uiChFinalMode = PU::getFinalIntraMode( *tu.cu->firstPU, toChannelType( compID ) ); + bool intraModeIsEven = uiChFinalMode % 2 == 0; + if( uiChFinalMode == DC_IDX || uiChFinalMode == 33 || uiChFinalMode == 35 ) + { + typeH = DCT2; + typeV = typeH; + } + else if( uiChFinalMode == PLANAR_IDX || ( uiChFinalMode >= 31 && uiChFinalMode <= 37 ) ) + { + typeH = DST7; + typeV = typeH; + } + else if( ( intraModeIsEven && uiChFinalMode >= 2 && uiChFinalMode <= 30 ) || ( !intraModeIsEven && uiChFinalMode >= 39 && uiChFinalMode <= 65 ) ) + { + typeH = DST7; + typeV = DCT2; + } + else if( ( !intraModeIsEven && uiChFinalMode >= 3 && uiChFinalMode <= 29 ) || ( intraModeIsEven && uiChFinalMode >= 38 && uiChFinalMode <= 66 ) ) + { + typeH = DCT2; + typeV = DST7; + } + //Size restriction for non-DCT-II transforms + Area tuArea = tu.blocks[compID]; + typeH = tuArea.width <= 2 || tuArea.width >= 32 ? DCT2 : typeH; + typeV = tuArea.height <= 2 || tuArea.height >= 32 ? DCT2 : typeV; +} +#endif // other tools diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 0b7c97f00bbcb8f128e2befbc791a9d559ad5034..b49f8b758672f21d4c397ba1506802bf21e3ea1b 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -49,6 +49,9 @@ namespace CS uint64_t getEstBits ( const CodingStructure &cs ); UnitArea getArea ( const CodingStructure &cs, const UnitArea &area, const ChannelType chType ); bool isDualITree ( const CodingStructure &cs ); +#if JVET_M0147_DMVR + void setRefinedMotionField(CodingStructure &cs); +#endif } @@ -57,6 +60,9 @@ namespace CU { bool isIntra (const CodingUnit &cu); bool isInter (const CodingUnit &cu); +#if JVET_M0483_IBC + bool isIBC (const CodingUnit &cu); +#endif bool isRDPCMEnabled (const CodingUnit &cu); bool isLosslessCoded (const CodingUnit &cu); uint32_t getIntraSizeIdx (const CodingUnit &cu); @@ -86,16 +92,42 @@ namespace CU void setGbiIdx (CodingUnit& cu, uint8_t uh); uint8_t deriveGbiIdx (uint8_t gbiLO, uint8_t gbiL1); +#if JVET_M0102_INTRA_SUBPARTITIONS + bool divideTuInRows ( const CodingUnit &cu ); + bool firstTestISPHorSplit ( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft = nullptr, const CodingUnit *cuAbove = nullptr ); + PartSplit getISPType ( const CodingUnit &cu, const ComponentID compID ); + bool isISPLast ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); + bool isISPFirst ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); + ISPType canUseISPSplit ( const CodingUnit &cu, const ComponentID compID ); + ISPType canUseISPSplit ( const int width, const int height, const int maxTrSize = MAX_TU_SIZE ); + uint32_t getISPSplitDim ( const int width, const int height, const PartSplit ispType ); +#endif + PUTraverser traversePUs ( CodingUnit& cu); TUTraverser traverseTUs ( CodingUnit& cu); cPUTraverser traversePUs (const CodingUnit& cu); cTUTraverser traverseTUs (const CodingUnit& cu); bool hasSubCUNonZeroMVd (const CodingUnit& cu); +#if JVET_M0246_AFFINE_AMVR + bool hasSubCUNonZeroAffineMVd ( const CodingUnit& cu ); +#endif int getMaxNeighboriMVCandNum (const CodingStructure& cs, const Position& pos); void resetMVDandMV2Int ( CodingUnit& cu, InterPrediction *interPred ); - +#if JVET_M0140_SBT + uint8_t getSbtInfo (uint8_t idx, uint8_t pos); + uint8_t getSbtIdx (const uint8_t sbtInfo); + uint8_t getSbtPos (const uint8_t sbtInfo); + uint8_t getSbtMode (const uint8_t sbtIdx, const uint8_t sbtPos); + uint8_t getSbtIdxFromSbtMode (const uint8_t sbtMode); + uint8_t getSbtPosFromSbtMode (const uint8_t sbtMode); + uint8_t targetSbtAllowed (uint8_t idx, uint8_t sbtAllowed); + uint8_t numSbtModeRdo (uint8_t sbtAllowed); + bool isMtsMode (const uint8_t sbtInfo); + bool isSbtMode (const uint8_t sbtInfo); + bool isSameSbtSize (const uint8_t sbtInfo1, const uint8_t sbtInfo2); +#endif } // PU tools namespace PU @@ -107,11 +139,18 @@ namespace PU void getInterMergeCandidates (const PredictionUnit &pu, MergeCtx& mrgCtx, int mmvdList, const int& mrgCandIdx = -1 ); +#if JVET_M0483_IBC + void getIBCMergeCandidates (const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1); +#endif void getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1); int getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC); bool isDiffMER (const PredictionUnit &pu, const PredictionUnit &pu2); bool getColocatedMVP (const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &pos, Mv& rcMv, const int &refIdx); void fillMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo ); +#if JVET_M0483_IBC + void fillIBCMvpCand (PredictionUnit &pu, AMVPInfo &amvpInfo); + bool addIBCMVPCand (const PredictionUnit &pu, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo); +#endif void fillAffineMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo); bool addMVPCandUnscaled (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo); bool addMVPCandWithScaling (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo); @@ -119,14 +158,21 @@ namespace PU bool xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const MergeCtx mergeCandList, bool hasPruned[MRG_MAX_NUM_CANDS]); #if JVET_L0090_PAIR_AVG bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos +#if JVET_M0483_IBC==0 , int mmvdList +#endif +#if JVET_M0483_IBC + , bool ibcFlag +#endif #if JVET_M0170_MRG_SHARELIST , bool isShared #endif ); #else bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter[MRG_MAX_NUM_CANDS], bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos +#if JVET_M0483_IBC==0 , int mmvdList +#endif ); #endif void addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv); @@ -137,17 +183,22 @@ namespace PU void getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4], bool isAvailable[4], int verIdx[4], int modelIdx, int verNum, AffineMergeCtx& affMrgCtx ); void getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx, const int mrgCandIdx = -1 ); void setAllAffineMvField ( PredictionUnit &pu, MvField *mvField, RefPicList eRefList ); - void setAllAffineMv ( PredictionUnit &pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList + void setAllAffineMv ( PredictionUnit &pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList , bool setHighPrec = false ); bool getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx &mrgCtx, bool& LICFlag, const int count , int mmvdList #if !JVET_M0409_ATMVP_FIX +#if JVET_M0483_IBC==0 , const int countIBC +#endif #endif ); bool getInterMergeSubPuRecurCand(const PredictionUnit &pu, MergeCtx &mrgCtx, const int count); bool isBiPredFromDifferentDir (const PredictionUnit &pu); +#if JVET_M0147_DMVR + bool isBiPredFromDifferentDirEqDistPoc(const PredictionUnit &pu); +#endif void restrictBiPredMergeCands (const PredictionUnit &pu, MergeCtx& mrgCtx); #if JVET_M0068_M0171_MMVD_CLEANUP void restrictBiPredMergeCandsOne (PredictionUnit &pu); @@ -160,21 +211,27 @@ namespace PU int getNarrowShape (const int width, const int height); void getTriangleMergeCandidates (const PredictionUnit &pu, MergeCtx &triangleMrgCtx); bool isUniqueTriangleCandidates (const PredictionUnit &pu, MergeCtx &triangleMrgCtx); +#if !JVET_M0328_KEEP_ONE_WEIGHT_GROUP bool getTriangleWeights (const PredictionUnit &pu, MergeCtx &triangleMrgCtx, const uint8_t candIdx0, const uint8_t candIdx1); +#endif +#if JVET_M0883_TRIANGLE_SIGNALING + void spanTriangleMotionInfo ( PredictionUnit &pu, MergeCtx &triangleMrgCtx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1); +#else void spanTriangleMotionInfo ( PredictionUnit &pu, MergeCtx &triangleMrgCtx, const uint8_t mergeIdx, const bool splitDir, const uint8_t candIdx0, const uint8_t candIdx1); +#endif int32_t mappingRefPic (const PredictionUnit &pu, int32_t refPicPoc, bool targetRefPicList); void getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred); bool getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv); bool isBlockVectorValid(PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xStartInCU, int yStartInCU, int xBv, int yBv, int ctuSize); +#if JVET_M0147_DMVR + bool checkDMVRCondition(const PredictionUnit& pu); +#endif } // TU tools namespace TU { uint32_t getNumNonZeroCoeffsNonTS (const TransformUnit &tu, const bool bLuma = true, const bool bChroma = true); -#if HEVC_USE_4x4_DSTVII - bool useDST (const TransformUnit &tu, const ComponentID &compID); -#endif bool isNonTransformedResidualRotated(const TransformUnit &tu, const ComponentID &compID); bool getCbf (const TransformUnit &tu, const ComponentID &compID); bool getCbfAtDepth (const TransformUnit &tu, const ComponentID &compID, const unsigned &depth); @@ -191,12 +248,26 @@ namespace TU #endif bool hasCrossCompPredInfo (const TransformUnit &tu, const ComponentID &compID); + +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + bool needsSqrt2Scale ( const TransformUnit &tu, const ComponentID &compID ); +#else bool needsSqrt2Scale ( const Size& size ); +#endif #if HM_QTBT_AS_IN_JEM_QUANT +#if JVET_M0119_NO_TRANSFORM_SKIP_QUANTISATION_ADJUSTMENT + bool needsBlockSizeTrafoScale ( const TransformUnit &tu, const ComponentID &compID ); +#else bool needsBlockSizeTrafoScale ( const Size& size ); +#endif #else bool needsQP3Offset (const TransformUnit &tu, const ComponentID &compID); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit* getPrevTU ( const TransformUnit &tu, const ComponentID compID ); + bool getPrevTuCbfAtDepth( const TransformUnit &tu, const ComponentID compID, const int trDepth ); + void getTransformTypeISP( const TransformUnit &tu, const ComponentID compID, int &typeH, int &typeV ); +#endif } uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); @@ -227,7 +298,7 @@ uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeLi if (extendRef != -1) { extendRefList[currSize - i] = extendRefList[currSize - 1 - i]; - } + } } candModeList[currSize - shift] = uiMode; candCostList[currSize - shift] = uiCost; @@ -301,7 +372,7 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode candCostList.insert(candCostList.end() - shift, cost); if (iserttPos != nullptr) { - *iserttPos = int(candModeList.size() - shift - 1); + *iserttPos = int(candModeList.size() - shift - 1); } return 1; } diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.cpp b/source/Lib/CommonLib/dtrace_blockstatistics.cpp index 5971ab4046563e91164918e0f8c3608e9921a4fa..a0557fd30d6555b0a340149d039fb68cab62572f 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.cpp +++ b/source/Lib/CommonLib/dtrace_blockstatistics.cpp @@ -195,7 +195,7 @@ void CDTrace::dtrace_block_vector( int k, const PredictionUnit &pu, std::string } void CDTrace::dtrace_block_scalar(int k, const TransformUnit &tu, std::string stat_type, signed value, bool isChroma /*= false*/ ) -{ +{ const CodingStructure& cs = *tu.cs; #if BLOCK_STATS_AS_CSV if(isChroma) @@ -273,7 +273,11 @@ void CDTrace::dtrace_polygon_vector(int k, int poc, const std::vector<Position> void retrieveTriangularMvInfo(const PredictionUnit& pu, MotionInfo& mi0, MotionInfo& mi1) { +#if JVET_M0883_TRIANGLE_SIGNALING + int triangleDir = pu.triangleSplitDir; +#else int triangleDir = g_triangleCombination[pu.mergeIdx][0]; +#endif CMotionBuf mb = pu.getMotionBuf(); bool foundMv[2] = { false, false }; bool foundBi = false; @@ -296,7 +300,7 @@ void retrieveTriangularMvInfo(const PredictionUnit& pu, MotionInfo& mi0, MotionI mi1.mv[0] = mb.at(x, y).mv[0]; mi1.mv[1] = mb.at(x, y).mv[1]; mi1.refIdx[0] = mb.at(x, y).refIdx[0]; - mi1.refIdx[1] = mb.at(x, y).refIdx[1]; + mi1.refIdx[1] = mb.at(x, y).refIdx[1]; foundMv[1] = true; } if (g_triangleMvStorage[triangleDir][idxH][idxW][y][x] == 2 && foundMv[0] == false && foundMv[1] == false) @@ -325,8 +329,12 @@ void retrieveTriangularMvInfo(const PredictionUnit& pu, MotionInfo& mi0, MotionI } void retrieveTrianglePolygon(const PredictionUnit& pu, std::vector<Position>& triangle0, std::vector<Position>& triangle1, Position& S, Position& E) { +#if JVET_M0883_TRIANGLE_SIGNALING + TriangleSplit triangleDir = TriangleSplit(pu.triangleSplitDir); +#else TriangleSplit triangleDir = TriangleSplit(g_triangleCombination[pu.mergeIdx][0]); - Position TL = pu.Y().topLeft(); +#endif + Position TL = pu.Y().topLeft(); Position TR = pu.Y().topRight(); TR = TR.offset(1, 0); Position BL = pu.Y().bottomLeft(); BL = BL.offset(0, 1); Position BR = pu.Y().bottomRight(); BR = BR.offset(1, 1); @@ -337,7 +345,7 @@ void retrieveTrianglePolygon(const PredictionUnit& pu, std::vector<Position>& tr E = Position(pu.Y().width, pu.Y().height); triangle0.push_back(TL); triangle0.push_back(TR); - triangle0.push_back(BR); + triangle0.push_back(BR); triangle1.push_back(TL); triangle1.push_back(BL); triangle1.push_back(BR); @@ -348,7 +356,7 @@ void retrieveTrianglePolygon(const PredictionUnit& pu, std::vector<Position>& tr E = Position(pu.Y().width, 0); triangle0.push_back(TL); triangle0.push_back(TR); - triangle0.push_back(BL); + triangle0.push_back(BL); triangle1.push_back(TR); triangle1.push_back(BL); triangle1.push_back(BR); @@ -437,10 +445,12 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::SkipFlag), cu.skip); } - if (!(!((cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getSpsNext().getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) +#if !JVET_M0464_UNI_MTS + if (!(!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::EMTFlag), cu.emtFlag); } +#endif DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::MMVDSkipFlag), cu.mmvdSkip); } else if( chType == CHANNEL_TYPE_CHROMA ) @@ -458,10 +468,12 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::TransQuantBypassFlag_Chroma), cu.transQuantBypass); } - if (!(!((cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getSpsNext().getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) +#if !JVET_M0464_UNI_MTS + if (!(!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::EMTFlag_Chroma), cu.emtFlag); } +#endif } @@ -668,8 +680,11 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::IMVMode), cu.imv); DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::RootCbf), cu.rootCbf); DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::GBIIndex), cu.GBiIdx); +#if !JVET_M0483_IBC DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::IBCFlag), cu.ibc); - +#else + DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::IBCFlag), cu.predMode == MODE_IBC); +#endif } break; case MODE_INTRA: @@ -721,15 +736,21 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) if (tu.Y().valid()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Y), tu.cbf[COMPONENT_Y]); +#if JVET_M0464_UNI_MTS + DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::MTSIdx), tu.mtsIdx); +#else DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Y), tu.transformSkip[COMPONENT_Y]); +#endif } if (!(cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_LUMA))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); +#if !JVET_M0464_UNI_MTS DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Cb), tu.transformSkip[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Cr), tu.transformSkip[COMPONENT_Cr]); - } +#endif + } } } } @@ -777,7 +798,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) if (CU::isIntra(cu)) { - if (!(!sps.getUsePCM() || cu.lumaSize().width > (1 << sps.getPCMLog2MaxSize()) || cu.lumaSize().width < (1 << sps.getPCMLog2MinSize()))) + if (!(!sps.getPCMEnabledFlag() || cu.lumaSize().width > (1 << sps.getPCMLog2MaxSize()) || cu.lumaSize().width < (1 << sps.getPCMLog2MinSize()))) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, cu, GetBlockStatisticName(BlockStatistic::IPCM), cu.ipcm); } @@ -800,7 +821,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) if (CU::isIntra(cu)) { - if (!(!sps.getUsePCM() || cu.lumaSize().width > (1 << sps.getPCMLog2MaxSize()) || cu.lumaSize().width < (1 << sps.getPCMLog2MinSize()))) + if (!(!sps.getPCMEnabledFlag() || cu.lumaSize().width > (1 << sps.getPCMLog2MaxSize()) || cu.lumaSize().width < (1 << sps.getPCMLog2MinSize()))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, cu, GetBlockStatisticName(BlockStatistic::IPCM_Chroma), cu.ipcm); } @@ -812,7 +833,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) switch (pu.cu->predMode) { case MODE_INTRA: - { + { if (pu.Y().valid()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::Luma_IntraMode), PU::getFinalIntraMode(pu, ChannelType(chType))); @@ -842,13 +863,13 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::MMVDMergeIdx), pu.mmvdMergeIdx); } - if (!cu.cs->slice->isIntra() && cu.cs->sps->getSpsNext().getUseAffine() && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 + if (!cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 && !pu.mmvdMergeFlag && !cu.mmvdSkip ) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::AffineFlag), pu.cu->affine); } - if (pu.cs->sps->getSpsNext().getUseMHIntra() && !pu.cu->skip && !pu.cu->affine && !(pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE) + if (pu.cs->sps->getUseMHIntra() && !pu.cu->skip && !pu.cu->affine && !(pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE) && !pu.mmvdMergeFlag ) { @@ -862,7 +883,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) } } } - if (cu.cs->slice->getSPS()->getSpsNext().getUseTriangle() && cu.cs->slice->isInterB() && cu.lwidth() * cu.lheight() >= TRIANGLE_MIN_SIZE && !cu.affine) + if (cu.cs->slice->getSPS()->getUseTriangle() && cu.cs->slice->isInterB() && cu.lwidth() * cu.lheight() >= TRIANGLE_MIN_SIZE && !cu.affine) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, cu, GetBlockStatisticName(BlockStatistic::TriangleFlag), cu.triangle); @@ -874,10 +895,10 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::InterDir), pu.interDir); } - if (!cu.cs->slice->isIntra() && cu.cs->sps->getSpsNext().getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8) + if (!cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::AffineFlag), pu.cu->affine); - if (cu.affine && !cu.firstPU->mergeFlag && cu.cs->sps->getSpsNext().getUseAffineType()) + if (cu.affine && !cu.firstPU->mergeFlag && cu.cs->sps->getUseAffineType()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::AffineType), pu.cu->affineType); } @@ -974,13 +995,13 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) DTRACE_BLOCK_AFFINETF(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::AffineMVL1), mv[0].hor, mv[0].ver, mv[1].hor, mv[1].ver, mv[2].hor, mv[2].ver); } } - if (cu.cs->sps->getSpsNext().getUseIMV() && CU::hasSubCUNonZeroMVd(cu)) + if (cu.cs->sps->getAMVREnabledFlag() && CU::hasSubCUNonZeroMVd(cu)) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, cu, GetBlockStatisticName(BlockStatistic::IMVMode), cu.imv); } if (CU::isGBiIdxCoded(cu)) { - DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::GBIIndex), cu.GBiIdx); + DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, cu, GetBlockStatisticName(BlockStatistic::GBIIndex), cu.GBiIdx); } break; } @@ -1000,21 +1021,26 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) } } if (cu.rootCbf || CU::isIntra(cu)) - { + { for (const TransformUnit &tu : CU::traverseTUs(cu)) { if (tu.Y().valid()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Y), tu.cbf[COMPONENT_Y]); +#if JVET_M0464_UNI_MTS + DTRACE_BLOCK_SCALAR( g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName( BlockStatistic::MTSIdx ), tu.mtsIdx ); +#else if (!(!tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag(*tu.cs, tu.blocks[COMPONENT_Y]) || (isLuma(COMPONENT_Y) && tu.cu->emtFlag))) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Y), tu.transformSkip[COMPONENT_Y]); } +#endif } if (!(cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_LUMA))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); +#if !JVET_M0464_UNI_MTS if (!(!tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag(*tu.cs, tu.blocks[COMPONENT_Cb]) || (isLuma(COMPONENT_Cb) && tu.cu->emtFlag))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Cb), tu.transformSkip[COMPONENT_Cb]); @@ -1023,10 +1049,12 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::TransformSkipFlag_Cr), tu.transformSkip[COMPONENT_Cr]); } +#endif } } } - if (!(!((cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getSpsNext().getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) +#if !JVET_M0464_UNI_MTS + if (!(!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && CU::isInter(cu))) || isChroma(cu.chType))) { if( isLuma( ChannelType( chType ) ) ) { @@ -1037,6 +1065,7 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, cu, GetBlockStatisticName(BlockStatistic::EMTFlag_Chroma), cu.emtFlag); } } +#endif } } } diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.h b/source/Lib/CommonLib/dtrace_blockstatistics.h index 34d457098ab571aa683c1cd49efbba568eee2515..72241ce8ae4f56ea5b04dbcd5d4be5cfd8e7c0bd 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.h +++ b/source/Lib/CommonLib/dtrace_blockstatistics.h @@ -64,10 +64,14 @@ enum class BlockStatistic { QP, SplitSeries, TransQuantBypassFlag, +#if JVET_M0464_UNI_MTS + MTSIdx, +#else EMTFlag, TransformSkipFlag_Y, TransformSkipFlag_Cb, TransformSkipFlag_Cr, +#endif // intra IPCM, @@ -119,7 +123,9 @@ enum class BlockStatistic { QP_Chroma, SplitSeries_Chroma, TransQuantBypassFlag_Chroma, +#if !JVET_M0464_UNI_MTS EMTFlag_Chroma, // this is called flag, though the type is UChar ?! +#endif // intra IPCM_Chroma, @@ -150,14 +156,18 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType { BlockStatistic::Luma_IntraMode, std::tuple<std::string, BlockStatisticType, std::string>{"Luma_IntraMode", BlockStatisticType::Integer, "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}}, { BlockStatistic::Chroma_IntraMode, std::tuple<std::string, BlockStatisticType, std::string>{"Chroma_IntraMode", BlockStatisticType::Integer, "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}}, { BlockStatistic::SkipFlag, std::tuple<std::string, BlockStatisticType, std::string>{"SkipFlag", BlockStatisticType::Flag, ""}}, +#if JVET_M0464_UNI_MTS + { BlockStatistic::MTSIdx, std::tuple<std::string, BlockStatisticType, std::string>{"TransformSkipFlag_Y", BlockStatisticType::Integer, ""}}, +#else { BlockStatistic::TransformSkipFlag_Y, std::tuple<std::string, BlockStatisticType, std::string>{"TransformSkipFlag_Y", BlockStatisticType::Flag, ""}}, { BlockStatistic::TransformSkipFlag_Cb, std::tuple<std::string, BlockStatisticType, std::string>{"TransformSkipFlag_Cb", BlockStatisticType::Flag, ""}}, { BlockStatistic::TransformSkipFlag_Cr, std::tuple<std::string, BlockStatisticType, std::string>{"TransformSkipFlag_Cr", BlockStatisticType::Flag, ""}}, - { BlockStatistic::Depth, std::tuple<std::string, BlockStatisticType, std::string>{"Depth", BlockStatisticType::Integer, "[0, 7]"}}, - { BlockStatistic::QT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"QT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, - { BlockStatistic::BT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"BT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, - { BlockStatistic::MT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"MT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, - { BlockStatistic::ChromaQPAdj, std::tuple<std::string, BlockStatisticType, std::string>{"ChromaQPAdj", BlockStatisticType::Integer, "[-10, 10]"}}, +#endif + { BlockStatistic::Depth, std::tuple<std::string, BlockStatisticType, std::string>{"Depth", BlockStatisticType::Integer, "[0, 7]"}}, + { BlockStatistic::QT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"QT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, + { BlockStatistic::BT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"BT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, + { BlockStatistic::MT_Depth, std::tuple<std::string, BlockStatisticType, std::string>{"MT_Depth", BlockStatisticType::Integer, "[0, 7]"}}, + { BlockStatistic::ChromaQPAdj, std::tuple<std::string, BlockStatisticType, std::string>{"ChromaQPAdj", BlockStatisticType::Integer, "[-10, 10]"}}, { BlockStatistic::QP, std::tuple<std::string, BlockStatisticType, std::string>{"QP", BlockStatisticType::Integer, "[0, 51]"}}, { BlockStatistic::SplitSeries, std::tuple<std::string, BlockStatisticType, std::string>{"SplitSeries", BlockStatisticType::Integer, "[0, " + std::to_string(std::numeric_limits<SplitSeries>::max()) + "]"}}, { BlockStatistic::RootCbf, std::tuple<std::string, BlockStatisticType, std::string>{"RootCbf", BlockStatisticType::Flag, ""}}, @@ -168,30 +178,32 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType { BlockStatistic::MergeIdx, std::tuple<std::string, BlockStatisticType, std::string>{"MergeIdx", BlockStatisticType::Integer, "[0, 7]"}}, { BlockStatistic::InterDir, std::tuple<std::string, BlockStatisticType, std::string>{"InterDir", BlockStatisticType::Integer, "[1, 3]"}}, { BlockStatistic::MergeType, std::tuple<std::string, BlockStatisticType, std::string>{"MergeType", BlockStatisticType::Integer, "[0, 2]"}}, - { BlockStatistic::MVPIdxL0, std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL0", BlockStatisticType::Integer, "[0, 1]"}}, + { BlockStatistic::MVPIdxL0, std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL0", BlockStatisticType::Integer, "[0, 1]"}}, { BlockStatistic::MVDL0, std::tuple<std::string, BlockStatisticType, std::string>{"MVDL0", BlockStatisticType::Vector, "Scale: 4"}}, - { BlockStatistic::RefIdxL0, std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL0", BlockStatisticType::Integer, "[0, 4]"}}, - { BlockStatistic::MVPIdxL1, std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL1", BlockStatisticType::Integer, "[0, 1]"}}, + { BlockStatistic::RefIdxL0, std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL0", BlockStatisticType::Integer, "[0, 4]"}}, + { BlockStatistic::MVPIdxL1, std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL1", BlockStatisticType::Integer, "[0, 1]"}}, { BlockStatistic::MVDL1, std::tuple<std::string, BlockStatisticType, std::string>{"MVDL1", BlockStatisticType::Vector, "Scale: 4"}}, - { BlockStatistic::RefIdxL1, std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL1", BlockStatisticType::Integer, "[0, 4]"}}, + { BlockStatistic::RefIdxL1, std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL1", BlockStatisticType::Integer, "[0, 4]"}}, { BlockStatistic::IMVMode, std::tuple<std::string, BlockStatisticType, std::string>{"IMVMode", BlockStatisticType::Integer, "[0, 2]"}}, { BlockStatistic::AffineFlag, std::tuple<std::string, BlockStatisticType, std::string>{"AffineFlag", BlockStatisticType::Flag, ""}}, { BlockStatistic::AffineMVL0, std::tuple<std::string, BlockStatisticType, std::string>{"AffineMVL0", BlockStatisticType::AffineTFVectors, "Scale: 4"}}, { BlockStatistic::AffineMVL1, std::tuple<std::string, BlockStatisticType, std::string>{"AffineMVL1", BlockStatisticType::AffineTFVectors, "Scale: 4"}}, { BlockStatistic::AffineType, std::tuple<std::string, BlockStatisticType, std::string>{"AffineType", BlockStatisticType::Flag, ""} }, +#if !JVET_M0464_UNI_MTS { BlockStatistic::EMTFlag, std::tuple<std::string, BlockStatisticType, std::string>{"EMTFlag", BlockStatisticType::Flag, ""}}, +#endif { BlockStatistic::MotionBufL0, std::tuple<std::string, BlockStatisticType, std::string>{"MotionBufL0", BlockStatisticType::Vector, "Scale: 16"}}, { BlockStatistic::MotionBufL1, std::tuple<std::string, BlockStatisticType, std::string>{"MotionBufL1", BlockStatisticType::Vector, "Scale: 16"}}, - { BlockStatistic::MultiRefIdx, std::tuple<std::string, BlockStatisticType, std::string>{"MultiRefIdx", BlockStatisticType::Integer, "[0, 1]"}}, + { BlockStatistic::MultiRefIdx, std::tuple<std::string, BlockStatisticType, std::string>{"MultiRefIdx", BlockStatisticType::Integer, "[0, 1]"}}, { BlockStatistic::MMVDSkipFlag, std::tuple<std::string, BlockStatisticType, std::string>{"MMVDSkipFlag", BlockStatisticType::Flag, ""}}, { BlockStatistic::MMVDMergeFlag, std::tuple<std::string, BlockStatisticType, std::string>{"MMVDMergeFlag", BlockStatisticType::Flag, ""}}, - { BlockStatistic::MMVDMergeIdx, std::tuple<std::string, BlockStatisticType, std::string>{"MMVDMergeIdx", BlockStatisticType::Integer, "[0, 1]"}}, + { BlockStatistic::MMVDMergeIdx, std::tuple<std::string, BlockStatisticType, std::string>{"MMVDMergeIdx", BlockStatisticType::Integer, "[0, 1]"}}, { BlockStatistic::MHIntraFlag, std::tuple<std::string, BlockStatisticType, std::string>{"MHIntraFlag", BlockStatisticType::Flag, ""}}, { BlockStatistic::TriangleFlag, std::tuple<std::string, BlockStatisticType, std::string>{"TriangleFlag", BlockStatisticType::Flag, ""}}, { BlockStatistic::TrianglePartitioning, std::tuple<std::string, BlockStatisticType, std::string>{"TrianglePartitioning", BlockStatisticType::Line, ""}}, { BlockStatistic::TriangleMVL0, std::tuple<std::string, BlockStatisticType, std::string>{"TriangleMVL0", BlockStatisticType::VectorPolygon, "Scale: 4"}}, { BlockStatistic::TriangleMVL1, std::tuple<std::string, BlockStatisticType, std::string>{"TriangleMVL1", BlockStatisticType::VectorPolygon, "Scale: 4"}}, - { BlockStatistic::GBIIndex, std::tuple<std::string, BlockStatisticType, std::string>{"GBIIndex", BlockStatisticType::Integer, "[0, 4]"}}, + { BlockStatistic::GBIIndex, std::tuple<std::string, BlockStatisticType, std::string>{"GBIIndex", BlockStatisticType::Integer, "[0, 4]"}}, { BlockStatistic::IBCFlag, std::tuple<std::string, BlockStatisticType, std::string>{"IBCFlag", BlockStatisticType::Flag, ""}}, // for dual tree { BlockStatistic::Depth_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"Depth_Chroma", BlockStatisticType::Integer, "[0, 10]"}}, // todo: actual limits? @@ -202,7 +214,9 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType { BlockStatistic::QP_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"QP_Chroma", BlockStatisticType::Integer, "[0, 51]"}}, { BlockStatistic::SplitSeries_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"SplitSeries_Chroma", BlockStatisticType::Integer, "[0, " + std::to_string(std::numeric_limits<SplitSeries>::max()) + "]"}}, { BlockStatistic::TransQuantBypassFlag_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"TransQuantBypassFlag_Chroma", BlockStatisticType::Flag, ""}}, +#if !JVET_M0464_UNI_MTS { BlockStatistic::EMTFlag_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"EMTFlag_Chroma", BlockStatisticType::Integer, "[0, 10]"}}, // todo: actual limits? +#endif { BlockStatistic::IPCM_Chroma, std::tuple<std::string, BlockStatisticType, std::string>{"IPCM_Chroma", BlockStatisticType::Flag, ""}}, }; diff --git a/source/Lib/CommonLib/dtrace_codingstruct.h b/source/Lib/CommonLib/dtrace_codingstruct.h index a6876cd95ee89111e17e98f020488d9a5beeb1d7..eafc916e1b9cbfbb4fb646a057cbd8e59f1bc436 100644 --- a/source/Lib/CommonLib/dtrace_codingstruct.h +++ b/source/Lib/CommonLib/dtrace_codingstruct.h @@ -107,7 +107,7 @@ inline void dtraceModeCost(CodingStructure &cs, double lambda) cs.cus[0]->predMode, cs.cus[0]->skip, cs.pus[0]->mergeFlag, - 0, 0, + 0, 0, imvVal, 0, 0, intraModeL, intraModeC, diff --git a/source/Lib/CommonLib/version.h b/source/Lib/CommonLib/version.h index 31f140a5fca24d5bd588d7ed3d0e9ffe33735350..bc3dcb17073bc44cd1bfe4840b773451d978a4db 100644 --- a/source/Lib/CommonLib/version.h +++ b/source/Lib/CommonLib/version.h @@ -1,3 +1,3 @@ #if ! defined( VTM_VERSION ) -#define VTM_VERSION "3.2" +#define VTM_VERSION "4.0" #endif diff --git a/source/Lib/CommonLib/x86/AffineGradientSearchX86.h b/source/Lib/CommonLib/x86/AffineGradientSearchX86.h index b422db4f866e9c189c5d596e044e11d44dfc61c7..b49d703b9113dabc67a7c9d0637da9035a8cb3f7 100644 --- a/source/Lib/CommonLib/x86/AffineGradientSearchX86.h +++ b/source/Lib/CommonLib/x86/AffineGradientSearchX86.h @@ -214,7 +214,7 @@ static void simdEqualCoeffComputer( Pel *pResidue, int residueStride, int **ppDe int idx1 = 0, idx2 = 0; idx1 = -2 * derivateBufStride - 4; idx2 = -derivateBufStride - 4; - + for ( int j = 0; j < height; j += 2 ) { if (!(j & 3)) diff --git a/source/Lib/CommonLib/x86/BufferX86.h b/source/Lib/CommonLib/x86/BufferX86.h index bdae6dcc51a4b2c2d87629bf3ff32b6e79e4bc64..0f10ff83cf6fd5ab2a39fb5b5109af51d1575a8b 100644 --- a/source/Lib/CommonLib/x86/BufferX86.h +++ b/source/Lib/CommonLib/x86/BufferX86.h @@ -128,6 +128,125 @@ void addAvg_SSE( const int16_t* src0, int src0Stride, const int16_t* src1, int s } } +#if JVET_M0147_DMVR +template<X86_VEXT vext> +void copyBufferSimd(Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height) +{ + __m128i x; +#ifdef USE_AVX2 + __m256i x16; +#endif + int j, temp; + for (int i = 0; i < height; i++) + { + j = 0; + temp = width; +#ifdef USE_AVX2 + while ((temp >> 4) > 0) + { + x16 = _mm256_loadu_si256((const __m256i*)(&src[i * srcStride + j])); + _mm256_storeu_si256((__m256i*)(&dst[i * dstStride + j]), x16); + j += 16; + temp -= 16; + } +#endif + while ((temp >> 3) > 0) + { + x = _mm_loadu_si128((const __m128i*)(&src[ i * srcStride + j])); + _mm_storeu_si128((__m128i*)(&dst[ i * dstStride + j]), x); + j += 8; + temp -= 8; + } + while ((temp >> 2) > 0) + { + x = _mm_loadl_epi64((const __m128i*)(&src[i * srcStride + j])); + _mm_storel_epi64((__m128i*)(&dst[i*dstStride + j]), x); + j += 4; + temp -= 4; + } + while (temp > 0) + { + dst[i * dstStride + j] = src[i * srcStride + j]; + j++; + temp--; + } + } +} + + +template<X86_VEXT vext> +void paddingSimd(Pel *dst, int stride, int width, int height, int padSize) +{ + __m128i x; +#ifdef USE_AVX2 + __m256i x16; +#endif + int temp, j; + for (int i = 1; i <= padSize; i++) + { + j = 0; + temp = width; +#ifdef USE_AVX2 + while ((temp >> 4) > 0) + { + + x16 = _mm256_loadu_si256((const __m256i*)(&(dst[j]))); + _mm256_storeu_si256((__m256i*)(dst + j - i*stride), x16); + x16 = _mm256_loadu_si256((const __m256i*)(dst + j + (height - 1)*stride)); + _mm256_storeu_si256((__m256i*)(dst + j + (height - 1 + i)*stride), x16); + + + j = j + 16; + temp = temp - 16; + } +#endif + while ((temp >> 3) > 0) + { + + x = _mm_loadu_si128((const __m128i*)(&(dst[j]))); + _mm_storeu_si128((__m128i*)(dst + j - i*stride), x); + x = _mm_loadu_si128((const __m128i*)(dst + j + (height - 1)*stride)); + _mm_storeu_si128((__m128i*)(dst + j + (height - 1 + i)*stride), x); + + j = j + 8; + temp = temp - 8; + } + while ((temp >> 2) > 0) + { + x = _mm_loadl_epi64((const __m128i*)(&dst[j])); + _mm_storel_epi64((__m128i*)(dst + j - i*stride), x); + x = _mm_loadl_epi64((const __m128i*)(dst + j + (height - 1)*stride)); + _mm_storel_epi64((__m128i*)(dst + j + (height - 1 + i)*stride), x); + + j = j + 4; + temp = temp - 4; + } + while (temp > 0) + { + dst[j - i*stride] = dst[j]; + dst[j + (height - 1 + i)*stride] = dst[j + (height - 1)*stride]; + j++; + temp--; + } + } + + + //Left and Right Padding + Pel* ptr1 = dst - padSize*stride; + Pel* ptr2 = dst - padSize*stride + width - 1; + int offset = 0; + for (int i = 0; i < height + 2 * padSize; i++) + { + offset = stride * i; + for (int j = 1; j <= padSize; j++) + { + *(ptr1 - j + offset) = *(ptr1 + offset); + *(ptr2 + j + offset) = *(ptr2 + offset); + } + + } +} +#endif template< X86_VEXT vext > void addBIOAvg4_SSE(const Pel* src0, int src0Stride, const Pel* src1, int src1Stride, Pel *dst, int dstStride, const Pel *gradX0, const Pel *gradX1, const Pel *gradY0, const Pel*gradY1, int gradStride, int width, int height, int tmpx, int tmpy, int shift, int offset, const ClpRng& clpRng) { @@ -162,7 +281,11 @@ void addBIOAvg4_SSE(const Pel* src0, int src0Stride, const Pel* src1, int src1St } template< X86_VEXT vext > +#if JVET_M0063_BDOF_FIX +void gradFilter_SSE(Pel* src, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, const int bitDepth) +#else void gradFilter_SSE(Pel* src, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY) +#endif { __m128i vzero = _mm_setzero_si128(); Pel* srcTmp = src + srcStride + 1; @@ -171,6 +294,10 @@ void gradFilter_SSE(Pel* src, int srcStride, int width, int height, int gradStri int widthInside = width - 2 * BIO_EXTEND_SIZE; int heightInside = height - 2 * BIO_EXTEND_SIZE; +#if JVET_M0063_BDOF_FIX + int shift1 = std::max<int>(2, (14 - bitDepth)); +#endif + assert((widthInside & 3) == 0); @@ -184,8 +311,13 @@ void gradFilter_SSE(Pel* src, int srcStride, int width, int height, int gradStri __m128i mmPixLeft = _mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i*)(srcTmp + x - 1))); __m128i mmPixRight = _mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i*)(srcTmp + x + 1))); +#if JVET_M0063_BDOF_FIX + __m128i mmGradVer = _mm_sra_epi32(_mm_sub_epi32(mmPixBottom, mmPixTop), _mm_cvtsi32_si128(shift1)); + __m128i mmGradHor = _mm_sra_epi32(_mm_sub_epi32(mmPixRight, mmPixLeft), _mm_cvtsi32_si128(shift1)); +#else __m128i mmGradVer = _mm_srai_epi32(_mm_sub_epi32(mmPixBottom, mmPixTop), 4); __m128i mmGradHor = _mm_srai_epi32(_mm_sub_epi32(mmPixRight, mmPixLeft), 4); +#endif mmGradVer = _mm_packs_epi32(mmGradVer, vzero); mmGradHor = _mm_packs_epi32(mmGradHor, vzero); @@ -220,23 +352,41 @@ void gradFilter_SSE(Pel* src, int srcStride, int width, int height, int gradStri } template< X86_VEXT vext > +#if JVET_M0063_BDOF_FIX +void calcBIOPar_SSE(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, const int bitDepth) +#else void calcBIOPar_SSE(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG) +#endif { +#if JVET_M0063_BDOF_FIX + int shift4 = std::min<int>(8, (bitDepth - 4)); + int shift5 = std::min<int>(5, (bitDepth - 7)); +#endif for (int y = 0; y < heightG; y++) { int x = 0; for (; x < ((widthG >> 3) << 3); x += 8) { +#if JVET_M0063_BDOF_FIX + __m128i mmSrcY0Temp = _mm_sra_epi16(_mm_loadu_si128((__m128i*)(srcY0Temp + x)), _mm_cvtsi32_si128(shift4)); + __m128i mmSrcY1Temp = _mm_sra_epi16(_mm_loadu_si128((__m128i*)(srcY1Temp + x)), _mm_cvtsi32_si128(shift4)); +#else __m128i mmSrcY0Temp = _mm_srai_epi16(_mm_loadu_si128((__m128i*)(srcY0Temp + x)), 6); __m128i mmSrcY1Temp = _mm_srai_epi16(_mm_loadu_si128((__m128i*)(srcY1Temp + x)), 6); +#endif __m128i mmGradX0 = _mm_loadu_si128((__m128i*)(gradX0 + x)); __m128i mmGradX1 = _mm_loadu_si128((__m128i*)(gradX1 + x)); __m128i mmGradY0 = _mm_loadu_si128((__m128i*)(gradY0 + x)); __m128i mmGradY1 = _mm_loadu_si128((__m128i*)(gradY1 + x)); __m128i mmTemp1 = _mm_sub_epi16(mmSrcY1Temp, mmSrcY0Temp); +#if JVET_M0063_BDOF_FIX + __m128i mmTempX = _mm_sra_epi16(_mm_add_epi16(mmGradX0, mmGradX1), _mm_cvtsi32_si128(shift5)); + __m128i mmTempY = _mm_sra_epi16(_mm_add_epi16(mmGradY0, mmGradY1), _mm_cvtsi32_si128(shift5)); +#else __m128i mmTempX = _mm_srai_epi16(_mm_add_epi16(mmGradX0, mmGradX1), 3); __m128i mmTempY = _mm_srai_epi16(_mm_add_epi16(mmGradY0, mmGradY1), 3); +#endif // m_piDotProductTemp1 __m128i mm_b = _mm_mulhi_epi16(mmTempX, mmTempX); @@ -291,16 +441,26 @@ void calcBIOPar_SSE(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX for (; x < ((widthG >> 2) << 2); x += 4) { +#if JVET_M0063_BDOF_FIX + __m128i mmSrcY0Temp = _mm_sra_epi16(_mm_loadl_epi64((__m128i*)(srcY0Temp + x)), _mm_cvtsi32_si128(shift4)); + __m128i mmSrcY1Temp = _mm_sra_epi16(_mm_loadl_epi64((__m128i*)(srcY1Temp + x)), _mm_cvtsi32_si128(shift4)); +#else __m128i mmSrcY0Temp = _mm_srai_epi16(_mm_loadl_epi64((__m128i*)(srcY0Temp + x)), 6); __m128i mmSrcY1Temp = _mm_srai_epi16(_mm_loadl_epi64((__m128i*)(srcY1Temp + x)), 6); +#endif __m128i mmGradX0 = _mm_loadl_epi64((__m128i*)(gradX0 + x)); __m128i mmGradX1 = _mm_loadl_epi64((__m128i*)(gradX1 + x)); __m128i mmGradY0 = _mm_loadl_epi64((__m128i*)(gradY0 + x)); __m128i mmGradY1 = _mm_loadl_epi64((__m128i*)(gradY1 + x)); __m128i mmTemp1 = _mm_sub_epi16(mmSrcY1Temp, mmSrcY0Temp); +#if JVET_M0063_BDOF_FIX + __m128i mmTempX = _mm_sra_epi16(_mm_add_epi16(mmGradX0, mmGradX1), _mm_cvtsi32_si128(shift5)); + __m128i mmTempY = _mm_sra_epi16(_mm_add_epi16(mmGradY0, mmGradY1), _mm_cvtsi32_si128(shift5)); +#else __m128i mmTempX = _mm_srai_epi16(_mm_add_epi16(mmGradX0, mmGradX1), 3); __m128i mmTempY = _mm_srai_epi16(_mm_add_epi16(mmGradY0, mmGradY1), 3); +#endif // m_piDotProductTemp1 __m128i mm_b = _mm_mulhi_epi16(mmTempX, mmTempX); @@ -340,9 +500,15 @@ void calcBIOPar_SSE(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX for (; x < widthG; x++) { +#if JVET_M0063_BDOF_FIX + int temp = (srcY0Temp[x] >> shift4) - (srcY1Temp[x] >> shift4); + int tempX = (gradX0[x] + gradX1[x]) >> shift5; + int tempY = (gradY0[x] + gradY1[x]) >> shift5; +#else int temp = (srcY0Temp[x] >> 6) - (srcY1Temp[x] >> 6); int tempX = (gradX0[x] + gradX1[x]) >> 3; int tempY = (gradY0[x] + gradY1[x]) >> 3; +#endif dotProductTemp1[x] = tempX * tempX; dotProductTemp2[x] = tempX * tempY; dotProductTemp3[x] = -tempX * temp; @@ -446,7 +612,7 @@ void reco_SSE( const int16_t* src0, int src0Stride, const int16_t* src1, int src __m256i vdest = _mm256_lddqu_si256( ( const __m256i * )&src0[col] ); __m256i vsrc1 = _mm256_lddqu_si256( ( const __m256i * )&src1[col] ); - vdest = _mm256_add_epi16( vdest, vsrc1 ); + vdest = _mm256_adds_epi16( vdest, vsrc1 ); vdest = _mm256_min_epi16( vbdmax, _mm256_max_epi16( vbdmin, vdest ) ); _mm256_storeu_si256( ( __m256i * )&dst[col], vdest ); @@ -470,7 +636,7 @@ void reco_SSE( const int16_t* src0, int src0Stride, const int16_t* src1, int src __m128i vdest = _mm_loadu_si128( ( const __m128i * )&src0[col] ); __m128i vsrc1 = _mm_loadu_si128( ( const __m128i * )&src1[col] ); - vdest = _mm_add_epi16( vdest, vsrc1 ); + vdest = _mm_adds_epi16( vdest, vsrc1 ); vdest = _mm_min_epi16( vbdmax, _mm_max_epi16( vbdmin, vdest ) ); _mm_storeu_si128( ( __m128i * )&dst[col], vdest ); @@ -494,7 +660,7 @@ void reco_SSE( const int16_t* src0, int src0Stride, const int16_t* src1, int src __m128i vsrc = _mm_loadl_epi64( ( const __m128i * )&src0[col] ); __m128i vdst = _mm_loadl_epi64( ( const __m128i * )&src1[col] ); - vdst = _mm_add_epi16( vdst, vsrc ); + vdst = _mm_adds_epi16( vdst, vsrc ); vdst = _mm_min_epi16( vbdmax, _mm_max_epi16( vbdmin, vdst ) ); _mm_storel_epi64( ( __m128i * )&dst[col], vdst ); @@ -801,6 +967,10 @@ void PelBufferOps::_initPelBufOpsX86() calcBIOPar = calcBIOPar_SSE<vext>; calcBlkGradient = calcBlkGradient_SSE<vext>; +#if JVET_M0147_DMVR + copyBuffer = copyBufferSimd<vext>; + padding = paddingSimd<vext>; +#endif reco8 = reco_SSE<vext, 8>; reco4 = reco_SSE<vext, 4>; diff --git a/source/Lib/CommonLib/x86/InitX86.cpp b/source/Lib/CommonLib/x86/InitX86.cpp index 00f18ae12450d7db4c8c03c51cd6d3c31850b756..334987013a8315ad5381a103efed5cbf226c448c 100644 --- a/source/Lib/CommonLib/x86/InitX86.cpp +++ b/source/Lib/CommonLib/x86/InitX86.cpp @@ -171,7 +171,7 @@ void AdaptiveLoopFilter::initAdaptiveLoopFilterX86() void IbcHashMap::initIbcHashMapX86() { auto vext = read_x86_extension_flags(); - switch (vext) + switch (vext) { case AVX512: case AVX2: diff --git a/source/Lib/CommonLib/x86/InterpolationFilterX86.h b/source/Lib/CommonLib/x86/InterpolationFilterX86.h index 1c3b75f5383f4d4d51f27f44f23fb0f354c043eb..4bea013a3de5c0948e0d580980e0adf18c2df25c 100644 --- a/source/Lib/CommonLib/x86/InterpolationFilterX86.h +++ b/source/Lib/CommonLib/x86/InterpolationFilterX86.h @@ -193,7 +193,11 @@ static void fullPelCopyAVX2( const ClpRng& clpRng, const void*_src, int srcStrid template<X86_VEXT vext, bool isFirst, bool isLast> +#if JVET_M0147_DMVR +static void simdFilterCopy( const ClpRng& clpRng, const Pel* src, int srcStride, int16_t* dst, int dstStride, int width, int height, bool biMCForDMVR) +#else static void simdFilterCopy( const ClpRng& clpRng, const Pel* src, int srcStride, int16_t* dst, int dstStride, int width, int height ) +#endif { #if !HM_JEM_CLIP_PEL if( vext >= AVX2 && ( width % 16 ) == 0 ) @@ -211,7 +215,11 @@ static void simdFilterCopy( const ClpRng& clpRng, const Pel* src, int srcStride, else #endif { //Scalar +#if JVET_M0147_DMVR + InterpolationFilter::filterCopy<isFirst, isLast>( clpRng, src, srcStride, dst, dstStride, width, height, biMCForDMVR); +#else InterpolationFilter::filterCopy<isFirst, isLast>( clpRng, src, srcStride, dst, dstStride, width, height ); +#endif } } @@ -979,9 +987,102 @@ static void simdInterpolateN2_M4( const int16_t* src, int srcStride, int16_t *ds dst += dstStride; } } +#if JVET_M0147_DMVR +#ifdef USE_AVX2 +static inline __m256i simdInterpolateLuma10Bit2P16(int16_t const *src1, int srcStride, __m256i *mmCoeff, const __m256i & mmOffset, __m128i &mmShift) +{ + __m256i sumLo; + { + __m256i mmPix = _mm256_loadu_si256((__m256i*)src1); + __m256i mmPix1 = _mm256_loadu_si256((__m256i*)(src1 + srcStride)); + __m256i lo0 = _mm256_mullo_epi16(mmPix, mmCoeff[0]); + __m256i lo1 = _mm256_mullo_epi16(mmPix1, mmCoeff[1]); + sumLo = _mm256_add_epi16(lo0, lo1); + } + sumLo = _mm256_sra_epi16(_mm256_add_epi16(sumLo, mmOffset), mmShift); + return(sumLo); +} +#endif + +static inline __m128i simdInterpolateLuma10Bit2P8(int16_t const *src1, int srcStride, __m128i *mmCoeff, const __m128i & mmOffset, __m128i &mmShift) +{ + __m128i sumLo; + { + __m128i mmPix = _mm_loadu_si128((__m128i*)src1); + __m128i mmPix1 = _mm_loadu_si128((__m128i*)(src1 + srcStride)); + __m128i lo0 = _mm_mullo_epi16(mmPix, mmCoeff[0]); + __m128i lo1 = _mm_mullo_epi16(mmPix1, mmCoeff[1]); + sumLo = _mm_add_epi16(lo0, lo1); + } + sumLo = _mm_sra_epi16(_mm_add_epi16(sumLo, mmOffset), mmShift); + return(sumLo); +} + +static inline __m128i simdInterpolateLuma10Bit2P4(int16_t const *src, int srcStride, __m128i *mmCoeff, const __m128i & mmOffset, __m128i &mmShift) +{ + __m128i sumLo; + { + __m128i mmPix = _mm_loadl_epi64((__m128i*)src); + __m128i mmPix1 = _mm_loadl_epi64((__m128i*)(src + srcStride)); + __m128i lo0 = _mm_mullo_epi16(mmPix, mmCoeff[0]); + __m128i lo1 = _mm_mullo_epi16(mmPix1, mmCoeff[1]); + sumLo = _mm_add_epi16(lo0, lo1); + } + sumLo = _mm_sra_epi16(_mm_add_epi16(sumLo, mmOffset), mmShift); + return sumLo; +} + +template<X86_VEXT vext, bool isLast> +static void simdInterpolateN2_10BIT_M4(const int16_t* src, int srcStride, int16_t *dst, int dstStride, int cStride, int width, int height, int shift, int offset, const ClpRng& clpRng, int16_t const *c) +{ + int row, col; + __m128i mmOffset = _mm_set1_epi16(offset); + __m128i mmShift = _mm_set_epi64x(0, shift); + __m128i mmCoeff[2]; + for (int n = 0; n < 2; n++) + mmCoeff[n] = _mm_set1_epi16(c[n]); + + CHECK(isLast, "Not Supported"); + +#if USE_AVX2 + __m256i mm256Offset = _mm256_set1_epi16(offset); + __m256i mm256Coeff[2]; + for (int n = 0; n < 2; n++) + mm256Coeff[n] = _mm256_set1_epi16(c[n]); +#endif + for (row = 0; row < height; row++) + { + col = 0; +#if USE_AVX2 + // multiple of 16 + for (; col < ((width >> 4) << 4); col += 16) + { + __m256i mmFiltered = simdInterpolateLuma10Bit2P16(src + col, cStride, mm256Coeff, mm256Offset, mmShift); + _mm256_storeu_si256((__m256i *)(dst + col), mmFiltered); + } +#endif + // multiple of 8 + for (; col < ((width >> 3) << 3); col += 8) + { + __m128i mmFiltered = simdInterpolateLuma10Bit2P8(src + col, cStride, mmCoeff, mmOffset, mmShift); + _mm_storeu_si128((__m128i *)(dst + col), mmFiltered); + } + + // last 4 samples + __m128i mmFiltered = simdInterpolateLuma10Bit2P4(src + col, cStride, mmCoeff, mmOffset, mmShift); + _mm_storel_epi64((__m128i *)(dst + col), mmFiltered); + src += srcStride; + dst += dstStride; + } +} +#endif template<X86_VEXT vext, int N, bool isVertical, bool isFirst, bool isLast> +#if JVET_M0147_DMVR +static void simdFilter( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff, bool biMCForDMVR) +#else static void simdFilter( const ClpRng& clpRng, Pel const *src, int srcStride, Pel *dst, int dstStride, int width, int height, TFilterCoeff const *coeff ) +#endif { int row, col; @@ -1027,6 +1128,13 @@ static void simdFilter( const ClpRng& clpRng, Pel const *src, int srcStride, Pel offset = ( isFirst ) ? -IF_INTERNAL_OFFS << shift : 0; } +#if JVET_M0147_DMVR + if (biMCForDMVR) + { + shift = IF_FILTER_PREC_BILINEAR - (IF_INTERNAL_PREC_BILINEAR - clpRng.bd); + offset = 1 << (shift - 1); + } +#endif if( clpRng.bd <= 10 ) { if( N == 8 && !( width & 0x07 ) ) @@ -1075,6 +1183,16 @@ static void simdFilter( const ClpRng& clpRng, Pel const *src, int srcStride, Pel simdInterpolateVerM4<vext, 4, isLast>( src, srcStride, dst, dstStride, width, height, shift, offset, clpRng, c ); return; } +#if JVET_M0147_DMVR + else if (biMCForDMVR) + { + if (N == 2 && !(width & 0x03)) + { + simdInterpolateN2_10BIT_M4<vext, isLast>(src, srcStride, dst, dstStride, cStride, width, height, shift, offset, clpRng, c); + return; + } + } +#endif else if( N == 2 && !( width & 0x07 ) ) { simdInterpolateN2_M8<vext, isLast>( src, srcStride, dst, dstStride, cStride, width, height, shift, offset, clpRng, c ); diff --git a/source/Lib/DecoderLib/BinDecoder.cpp b/source/Lib/DecoderLib/BinDecoder.cpp index 6486ebe33d38be96d304fdc5b91666194f5975c7..d86ba85529a7db610aa0eda10d8fde4538d9a277 100644 --- a/source/Lib/DecoderLib/BinDecoder.cpp +++ b/source/Lib/DecoderLib/BinDecoder.cpp @@ -182,8 +182,14 @@ unsigned BinDecoderBase::decodeBinsEP( unsigned numBins ) unsigned BinDecoderBase::decodeRemAbsEP( unsigned goRicePar, bool useLimitedPrefixLength, int maxLog2TrDynamicRange ) { +#if JVET_M0470 + unsigned cutoff = COEF_REMAIN_BIN_REDUCTION; + unsigned prefix = 0; + useLimitedPrefixLength = true; +#else unsigned cutoff = g_auiGoRiceRange[ goRicePar ]; unsigned prefix = 0; +#endif if( useLimitedPrefixLength ) { const unsigned maxPrefix = 32 - maxLog2TrDynamicRange; diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 6015b1921d223706e2740de44633a9e6e42c505d..4fb88ca5c9b5052e9487536da93e44777ab1ed7d 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -127,10 +127,6 @@ void CABACReader::remaining_bytes( bool noTrailingBytesExpected ) } } - - - - //================================================================================ // clause 7.3.8.2 //-------------------------------------------------------------------------------- @@ -217,10 +213,6 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i return isLast; } - - - - //================================================================================ // clause 7.3.8.3 //-------------------------------------------------------------------------------- @@ -380,9 +372,6 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) } } - - - //================================================================================ // clause 7.3.8.4 //-------------------------------------------------------------------------------- @@ -690,7 +679,7 @@ PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitio RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__SPLIT_FLAG, partitioner.currArea().blocks[partitioner.chType].size(), partitioner.chType ); PartSplit mode = CU_DONT_SPLIT; - + bool canNo, canQt, canBh, canBv, canTh, canTv; partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); @@ -813,7 +802,7 @@ PartSplit CABACReader::split_cu_mode_mt( CodingStructure& cs, Partitioner &parti dt.setAvail( DTT_SPLIT_BT_HORZ, partitioner.canSplit( CU_HORZ_SPLIT, cs ) ); dt.setAvail( DTT_SPLIT_BT_VERT, partitioner.canSplit( CU_VERT_SPLIT, cs ) ); - + dt.setAvail( DTT_SPLIT_TT_HORZ, partitioner.canSplit( CU_TRIH_SPLIT, cs ) ); dt.setAvail( DTT_SPLIT_TT_VERT, partitioner.canSplit( CU_TRIV_SPLIT, cs ) ); dt.setAvail( DTT_SPLIT_NO_SPLIT, partitioner.canSplit( CU_DONT_SPLIT, cs ) ); @@ -885,7 +874,11 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& } // skip flag +#if JVET_M0483_IBC + if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && cu.Y().valid()) +#else if (!cs.slice->isIntra() && cu.Y().valid()) +#endif { cu_skip_flag( cu ); } @@ -924,6 +917,9 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& extend_ref_line( cu ); +#if JVET_M0102_INTRA_SUBPARTITIONS + isp_mode( cu ); +#endif // prediction data ( intra prediction modes / reference indexes + motion vectors ) cu_pred_data( cu ); @@ -948,12 +944,54 @@ void CABACReader::cu_skip_flag( CodingUnit& cu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SKIP_FLAG ); +#if JVET_M0483_IBC + if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag()) + { + cu.skip = false; + cu.rootCbf = false; + cu.predMode = MODE_INTRA; + cu.mmvdSkip = false; + unsigned ctxId = DeriveCtx::CtxSkipFlag(cu); + unsigned skip = m_BinDecoder.decodeBin(Ctx::SkipFlag(ctxId)); + if (skip) + { + cu.skip = true; + cu.rootCbf = false; + cu.predMode = MODE_IBC; + cu.mmvdSkip = false; + } + + return; + } +#endif + unsigned ctxId = DeriveCtx::CtxSkipFlag(cu); unsigned skip = m_BinDecoder.decodeBin( Ctx::SkipFlag(ctxId) ); DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, skip ? 1 : 0 ); +#if JVET_M0483_IBC + if (skip && cu.cs->slice->getSPS()->getIBCFlag()) + { + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx))) + { + cu.skip = true; + cu.rootCbf = false; + cu.predMode = MODE_IBC; + cu.mmvdSkip = false; + } + else + { + cu.predMode = MODE_INTER; + } + DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode); + } + if ((skip && CU::isInter(cu) && cu.cs->slice->getSPS()->getIBCFlag()) || + (skip && !cu.cs->slice->getSPS()->getIBCFlag())) +#else if( skip ) +#endif { unsigned mmvdSkip = m_BinDecoder.decodeBin(Ctx::MmvdFlag(0)); cu.mmvdSkip = mmvdSkip; @@ -968,7 +1006,7 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__OTHER ); - if( !cu.cs->sps->getSpsNext().getUseIMV() ) + if( !cu.cs->sps->getAMVREnabledFlag() ) { return; } @@ -979,17 +1017,28 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx ) return; } - const SPSNext& spsNext = cu.cs->sps->getSpsNext(); +#if JVET_M0246_AFFINE_AMVR + if ( cu.affine ) + { + return; + } +#endif + + const SPS *sps = cu.cs->sps; unsigned value = 0; unsigned ctxId = DeriveCtx::CtxIMVFlag( cu ); +#if JVET_M0483_IBC + if (CU::isIBC(cu)) +#else if (cu.firstPU->interDir == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, cu.firstPU->refIdx[REF_PIC_LIST_0])->getPOC() == cu.cs->slice->getPOC()) // the first bin of IMV flag does need to be signaled in IBC block +#endif value = 1; else value = m_BinDecoder.decodeBin( Ctx::ImvFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", value, ctxId ); - if( spsNext.getImvMode() == IMV_4PEL && value ) + if( sps->getAMVREnabledFlag() && value ) { value = m_BinDecoder.decodeBin( Ctx::ImvFlag( 3 ) ); DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", value, 3 ); @@ -1000,10 +1049,92 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx ) DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv ); } +#if JVET_M0246_AFFINE_AMVR +void CABACReader::affine_amvr_mode( CodingUnit& cu, MergeCtx& mrgCtx ) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__OTHER ); + + const SPS* sps = cu.slice->getSPS(); + + if( !sps->getAffineAmvrEnabledFlag() || !cu.affine ) + { + return; + } + + if ( !CU::hasSubCUNonZeroAffineMVd( cu ) ) + { + return; + } + + unsigned value = 0; + value = m_BinDecoder.decodeBin( Ctx::ImvFlag( 4 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", value, 4 ); + + if( value ) + { + value = m_BinDecoder.decodeBin( Ctx::ImvFlag( 5 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", value, 5 ); + value++; + } + + cu.imv = value; + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv ); +} +#endif + void CABACReader::pred_mode( CodingUnit& cu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__PRED_MODE ); +#if JVET_M0483_IBC + if (cu.cs->slice->getSPS()->getIBCFlag()) + { + if (cu.cs->slice->isIntra()) + { + cu.predMode = MODE_INTRA; + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx))) + { + cu.predMode = MODE_IBC; + } + } + else + { +#if JVET_M0502_PRED_MODE_CTX + if (m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)))) +#else + if (m_BinDecoder.decodeBin(Ctx::PredMode())) +#endif + { + cu.predMode = MODE_INTRA; + } + else + { + cu.predMode = MODE_INTER; + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx))) + { + cu.predMode = MODE_IBC; + } + } + } + } + else + { +#if JVET_M0502_PRED_MODE_CTX + if (cu.cs->slice->isIntra() || m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)))) +#else + if (cu.cs->slice->isIntra() || m_BinDecoder.decodeBin(Ctx::PredMode())) +#endif + { + cu.predMode = MODE_INTRA; + } + else + { + cu.predMode = MODE_INTER; + } + } +#else #if JVET_M0502_PRED_MODE_CTX if( cu.cs->slice->isIntra() || m_BinDecoder.decodeBin( Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)) ) ) #else @@ -1016,12 +1147,13 @@ void CABACReader::pred_mode( CodingUnit& cu ) { cu.predMode = MODE_INTER; } +#endif } void CABACReader::pcm_flag( CodingUnit& cu, Partitioner &partitioner ) { const SPS& sps = *cu.cs->sps; - if( !sps.getPCMEnabledFlag() || partitioner.currArea().lwidth() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lwidth() < (1 << sps.getPCMLog2MinSize()) + if( !sps.getPCMEnabledFlag() || partitioner.currArea().lwidth() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lwidth() < (1 << sps.getPCMLog2MinSize()) || partitioner.currArea().lheight() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lheight() < (1 << sps.getPCMLog2MinSize()) ) { cu.ipcm = false; @@ -1041,8 +1173,12 @@ void CABACReader::cu_pred_data( CodingUnit &cu ) } if (!cu.Y().valid()) // dual tree chroma CU { +#if JVET_M0483_IBC + cu.predMode = MODE_IBC; +#else cu.predMode = MODE_INTER; cu.ibc = true; +#endif return; } MergeCtx mrgCtx; @@ -1057,7 +1193,9 @@ void CABACReader::cu_pred_data( CodingUnit &cu ) } imv_mode ( cu, mrgCtx ); - +#if JVET_M0246_AFFINE_AMVR + affine_amvr_mode( cu, mrgCtx ); +#endif cu_gbi_flag( cu ); } @@ -1142,8 +1280,13 @@ void CABACReader::xReadTruncBinCode(uint32_t& symbol, uint32_t maxSymbol) symbol -= (val - b); } } + void CABACReader::extend_ref_line(CodingUnit& cu) { +#if !ENABLE_JVET_L0283_MRL + return; +#endif + if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) { cu.firstPU->multiRefIdx = 0; @@ -1197,12 +1340,18 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) for( int k = 0; k < numBlocks; k++ ) { CHECK(numBlocks != 1, "not supported yet"); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.firstPU->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#else if (cu.firstPU->multiRefIdx) +#endif { mpmFlag[0] = true; } else - mpmFlag[k] = m_BinDecoder.decodeBin( Ctx::IPredMode[0]() ); + { + mpmFlag[k] = m_BinDecoder.decodeBin(Ctx::IntraLumaMpmFlag()); + } } PredictionUnit *pu = cu.firstPU; @@ -1273,16 +1422,17 @@ void CABACReader::intra_chroma_pred_modes( CodingUnit& cu ) intra_chroma_pred_mode( *pu ); } } + bool CABACReader::intra_chroma_lmc_mode( PredictionUnit& pu ) { - int lmModeList[10]; - int maxSymbol = PU::getLMSymbolList(pu, lmModeList); - int symbol = unary_max_symbol( Ctx::IPredMode[1]( 2 ), Ctx::IPredMode[1]( 3 ), maxSymbol - 1 ); - if ( lmModeList[ symbol ] != -1 ) - { - pu.intraDir[1] = lmModeList[ symbol ]; - return true; - } + int lmModeList[10]; + int maxSymbol = PU::getLMSymbolList(pu, lmModeList); + int symbol = unary_max_symbol(Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1); + if (lmModeList[symbol] != -1) + { + pu.intraDir[1] = lmModeList[symbol]; + return true; + } return false; } @@ -1290,16 +1440,14 @@ void CABACReader::intra_chroma_pred_mode( PredictionUnit& pu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__INTRA_DIR_ANG, pu.cu->blocks[pu.chType].lumaSize(), CHANNEL_TYPE_CHROMA ); + if (m_BinDecoder.decodeBin(Ctx::IntraChromaPredMode(0)) == 0) { - if( m_BinDecoder.decodeBin( Ctx::IPredMode[1]( 1 ) ) == 0 ) - { - pu.intraDir[1] = DM_CHROMA_IDX; - return; - } + pu.intraDir[1] = DM_CHROMA_IDX; + return; } // LM chroma mode - if( pu.cs->sps->getSpsNext().getUseLMChroma() ) + if( pu.cs->sps->getUseLMChroma() ) { if( intra_chroma_lmc_mode( pu ) ) { @@ -1320,7 +1468,11 @@ void CABACReader::intra_chroma_pred_mode( PredictionUnit& pu ) void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& cuCtx ) { +#if JVET_M0483_IBC + if (!CU::isIntra(cu)) +#else if( CU::isInter( cu ) ) +#endif { PredictionUnit& pu = *cu.firstPU; if( !pu.mergeFlag ) @@ -1331,6 +1483,12 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& { cu.rootCbf = true; } +#if JVET_M0140_SBT + if( cu.rootCbf ) + { + sbt_mode( cu ); + } +#endif if( !cu.rootCbf ) { TransformUnit& tu = cu.cs->addTU(cu, partitioner.chType); @@ -1347,7 +1505,19 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& } ChromaCbfs chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && isLuma( partitioner.chType ) ) + { + TUIntraSubPartitioner subTuPartitioner( partitioner ); + transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 ); + } + else + { + transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); + } +#else transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); +#endif } void CABACReader::rqt_root_cbf( CodingUnit& cu ) @@ -1359,6 +1529,64 @@ void CABACReader::rqt_root_cbf( CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "rqt_root_cbf() ctx=0 root_cbf=%d pos=(%d,%d)\n", cu.rootCbf ? 1 : 0, cu.lumaPos().x, cu.lumaPos().y ); } +#if JVET_M0140_SBT +void CABACReader::sbt_mode( CodingUnit& cu ) +{ + const uint8_t sbtAllowed = cu.checkAllowedSbt(); + if( !sbtAllowed ) + { + return; + } + + SizeType cuWidth = cu.lwidth(); + SizeType cuHeight = cu.lheight(); + + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SBT_MODE ); + //bin - flag + uint8_t ctxIdx = ( cuWidth * cuHeight <= 256 ) ? 1 : 0; + bool sbtFlag = m_BinDecoder.decodeBin( Ctx::SbtFlag( ctxIdx ) ); + if( !sbtFlag ) + { + return; + } + + uint8_t sbtVerHalfAllow = CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed ); + uint8_t sbtHorHalfAllow = CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed ); + uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ); + uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ); + + //bin - type + bool sbtQuadFlag = false; + if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) ) + { + sbtQuadFlag = m_BinDecoder.decodeBin( Ctx::SbtQuadFlag( 0 ) ); + } + else + { + sbtQuadFlag = 0; + } + + //bin - dir + bool sbtHorFlag = false; + if( ( sbtQuadFlag && sbtVerQuadAllow && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtVerHalfAllow && sbtHorHalfAllow ) ) //both direction allowed + { + uint8_t ctxIdx = ( cuWidth == cuHeight ) ? 0 : ( cuWidth < cuHeight ? 1 : 2 ); + sbtHorFlag = m_BinDecoder.decodeBin( Ctx::SbtHorFlag( ctxIdx ) ); + } + else + { + sbtHorFlag = ( sbtQuadFlag && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtHorHalfAllow ); + } + cu.setSbtIdx( sbtHorFlag ? ( sbtQuadFlag ? SBT_HOR_QUAD : SBT_HOR_HALF ) : ( sbtQuadFlag ? SBT_VER_QUAD : SBT_VER_HALF ) ); + + //bin - pos + bool sbtPosFlag = m_BinDecoder.decodeBin( Ctx::SbtPosFlag( 0 ) ); + cu.setSbtPos( sbtPosFlag ? SBT_POS1 : SBT_POS0 ); + + DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo ); +} +#endif + bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) { @@ -1378,8 +1606,6 @@ bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) return false; } - - //================================================================================ // clause 7.3.8.6 //-------------------------------------------------------------------------------- @@ -1404,6 +1630,14 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) } if( pu.mergeFlag ) { +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + { + merge_idx(pu); + } + else + { +#endif subblock_merge_flag( *pu.cu ); MHIntra_flag(pu); if (pu.mhIntraFlag) @@ -1417,8 +1651,21 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) mmvd_merge_idx(pu); } else - merge_data ( pu ); + merge_data ( pu ); +#if JVET_M0483_IBC + } +#endif } +#if JVET_M0483_IBC + else if (CU::isIBC(*pu.cu)) + { + pu.interDir = 1; + pu.cu->affine = false; + pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; + mvd_coding(pu.mvd[REF_PIC_LIST_0]); + mvp_flag(pu, REF_PIC_LIST_0); + } +#endif else { inter_pred_idc( pu ); @@ -1528,7 +1775,7 @@ void CABACReader::subblock_merge_flag( CodingUnit& cu ) return; } - if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getSpsNext().getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 ) + if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__AFFINE_FLAG ); @@ -1540,7 +1787,7 @@ void CABACReader::subblock_merge_flag( CodingUnit& cu ) void CABACReader::affine_flag( CodingUnit& cu ) { - if ( !cu.cs->slice->isIntra() && cu.cs->sps->getSpsNext().getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 ) + if ( !cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__AFFINE_FLAG ); @@ -1548,7 +1795,7 @@ void CABACReader::affine_flag( CodingUnit& cu ) cu.affine = m_BinDecoder.decodeBin( Ctx::AffineFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "affine_flag() affine=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y ); - if ( cu.affine && cu.cs->sps->getSpsNext().getUseAffineType() ) + if ( cu.affine && cu.cs->sps->getUseAffineType() ) { ctxId = 0; cu.affineType = m_BinDecoder.decodeBin( Ctx::AffineType( ctxId ) ); @@ -1568,6 +1815,15 @@ void CABACReader::merge_flag( PredictionUnit& pu ) pu.mergeFlag = ( m_BinDecoder.decodeBin( Ctx::MergeFlag() ) ); DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height ); + +#if JVET_M0483_IBC + if (pu.mergeFlag && CU::isIBC(*pu.cu)) + { + pu.mmvdMergeFlag = false; + return; + } +#endif + if (pu.mergeFlag) { pu.mmvdMergeFlag = (m_BinDecoder.decodeBin(Ctx::MmvdFlag(0))); @@ -1578,13 +1834,14 @@ void CABACReader::merge_flag( PredictionUnit& pu ) void CABACReader::merge_data( PredictionUnit& pu ) { - if (pu.cu->mmvdSkip) { mmvd_merge_idx(pu); } else - merge_idx( pu ); + { + merge_idx(pu); + } } @@ -1600,10 +1857,13 @@ void CABACReader::merge_idx( PredictionUnit& pu ) { if ( m_BinDecoder.decodeBin( Ctx::AffMergeIdx() ) ) { +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX bool useExtCtx = pu.cs->sps->getSBTMVPEnabledFlag(); +#endif pu.mergeIdx++; for ( ; pu.mergeIdx < numCandminus1; pu.mergeIdx++ ) { +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX if ( useExtCtx ) { if ( !m_BinDecoder.decodeBin( Ctx::AffMergeIdx( std::min<int>( pu.mergeIdx, NUM_MERGE_IDX_EXT_CTX - 1 ) ) ) ) @@ -1613,11 +1873,14 @@ void CABACReader::merge_idx( PredictionUnit& pu ) } else { +#endif if ( !m_BinDecoder.decodeBinEP() ) { break; } +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX } +#endif } } } @@ -1631,6 +1894,38 @@ void CABACReader::merge_idx( PredictionUnit& pu ) if( pu.cu->triangle ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__TRIANGLE_INDEX ); +#if JVET_M0883_TRIANGLE_SIGNALING + bool splitDir; + uint8_t candIdx0; + uint8_t candIdx1; + splitDir = m_BinDecoder.decodeBinEP(); + auto decodeOneIdx = [this](int numCandminus1) -> uint8_t + { + uint8_t decIdx = 0; + if( numCandminus1 > 0 ) + { + if( this->m_BinDecoder.decodeBin( Ctx::MergeIdx() ) ) + { + decIdx++; + for( ; decIdx < numCandminus1; decIdx++ ) + { + if( !this->m_BinDecoder.decodeBinEP() ) + break; + } + } + } + return decIdx; + }; + candIdx0 = decodeOneIdx(TRIANGLE_MAX_NUM_UNI_CANDS - 1); + candIdx1 = decodeOneIdx(TRIANGLE_MAX_NUM_UNI_CANDS - 2); + candIdx1 += candIdx1 >= candIdx0 ? 1 : 0; + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_split_dir=%d\n", splitDir ); + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx0=%d\n", candIdx0 ); + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx1=%d\n", candIdx1 ); + pu.triangleSplitDir = splitDir; + pu.triangleMergeIdx0 = candIdx0; + pu.triangleMergeIdx1 = candIdx1; +#else if( m_BinDecoder.decodeBin( Ctx::TriangleIdx() ) == 0 ) { pu.mergeIdx += m_BinDecoder.decodeBinEP(); @@ -1641,6 +1936,7 @@ void CABACReader::merge_idx( PredictionUnit& pu ) } DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx=%d\n", pu.mergeIdx ); +#endif return; } @@ -1775,6 +2071,7 @@ void CABACReader::ref_idx( PredictionUnit &pu, RefPicList eRefList ) #endif int numRef = pu.cs->slice->getNumRefIdx(eRefList); + if( numRef <= 1 || !m_BinDecoder.decodeBin( Ctx::RefPic() ) ) { if( numRef > 1 ) @@ -1816,7 +2113,7 @@ void CABACReader::mvp_flag( PredictionUnit& pu, RefPicList eRefList ) void CABACReader::MHIntra_flag(PredictionUnit& pu) { - if (!pu.cs->sps->getSpsNext().getUseMHIntra()) + if (!pu.cs->sps->getUseMHIntra()) { pu.mhIntraFlag = false; return; @@ -1946,11 +2243,11 @@ void CABACReader::triangle_mode( CodingUnit& cu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__TRIANGLE_FLAG ); - if( !cu.cs->slice->getSPS()->getSpsNext().getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) + if( !cu.cs->slice->getSPS()->getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) { return; } - + #if JVET_M0118_M0185_TRIANGLE_FLAG_FIX if ( cu.firstPU->mmvdMergeFlag || cu.mmvdSkip ) { @@ -2003,10 +2300,6 @@ void CABACReader::pcm_samples( TransformUnit& tu ) m_BinDecoder.start(); } - - - - //================================================================================ // clause 7.3.8.8 //-------------------------------------------------------------------------------- @@ -2015,33 +2308,83 @@ void CABACReader::pcm_samples( TransformUnit& tu ) // bool cbf_comp ( area, depth ) //================================================================================ +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx ) +#else void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ) +#endif { +#if JVET_M0140_SBT + ChromaCbfs chromaCbfsLastDepth; + chromaCbfsLastDepth.Cb = chromaCbfs.Cb; + chromaCbfsLastDepth.Cr = chromaCbfs.Cr; +#endif const UnitArea& area = partitioner.currArea(); CodingUnit& cu = *cs.getCU( area.blocks[partitioner.chType], partitioner.chType ); const unsigned trDepth = partitioner.currTrDepth; +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; +#endif // split_transform_flag bool split = false; split = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_M0140_SBT + if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + split = true; + } +#endif + +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !split && cu.ispMode ) + { + split = partitioner.canSplit( ispType, cs ); + } + const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split; +#endif // cbf_cb & cbf_cr +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) ) +#endif { +#if JVET_M0102_INTRA_SUBPARTITIONS + const int cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; + if (chromaCbfs.Cb) { - { - if( chromaCbfs.Cb ) - { - chromaCbfs.Cb &= cbf_comp( cs, area.blocks[COMPONENT_Cb], trDepth ); - } - if( chromaCbfs.Cr ) - { - chromaCbfs.Cr &= cbf_comp( cs, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb ); - } - } +#if JVET_M0140_SBT + if (!(cu.sbtInfo && trDepth == 1)) +#endif + chromaCbfs.Cb &= cbf_comp(cs, area.blocks[COMPONENT_Cb], cbfDepth); } + if (chromaCbfs.Cr) + { +#if JVET_M0140_SBT + if (!(cu.sbtInfo && trDepth == 1)) +#endif + chromaCbfs.Cr &= cbf_comp(cs, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb); + } +#else + if (chromaCbfs.Cb) + { +#if JVET_M0140_SBT + if (!(cu.sbtInfo && trDepth == 1)) +#endif + chromaCbfs.Cb &= cbf_comp(cs, area.blocks[COMPONENT_Cb], trDepth); + } + if (chromaCbfs.Cr) + { +#if JVET_M0140_SBT + if (!(cu.sbtInfo && trDepth == 1)) +#endif + chromaCbfs.Cr &= cbf_comp(cs, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb); + } +#endif } else if( CS::isDualITree( cs ) ) { @@ -2052,7 +2395,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if( trDepth == 0 && !cu.ispMode ) emt_cu_flag( cu ); +#else if( trDepth == 0 ) emt_cu_flag( cu ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -2064,6 +2411,18 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, #endif partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); + } +#endif else THROW( "Implicit TU split not available!" ); } @@ -2071,7 +2430,12 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, do { ChromaCbfs subCbfs = chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + transform_tree( cs, partitioner, cuCtx, subCbfs, ispType, subTuCounter ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else transform_tree( cs, partitioner, cuCtx, subCbfs ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -2081,7 +2445,17 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, const unsigned numTBlocks = getNumberValidTBlocks( *cs.pcv ); unsigned compCbf[3] = { 0, 0, 0 }; - +#if JVET_M0102_INTRA_SUBPARTITIONS + unsigned cbfDepth = 0; + for( auto &currTU : cs.traverseTUs( currArea, partitioner.chType ) ) + { + for( unsigned ch = 0; ch < numTBlocks; ch++ ) + { + cbfDepth = !isLuma( ComponentID( ch ) ) && cu.ispMode ? currDepth : currDepth + 1; + compCbf[ch] |= ( TU::getCbfAtDepth( currTU, ComponentID( ch ), cbfDepth ) ? 1 : 0 ); + } + } +#else for( auto &currTU : cs.traverseTUs( currArea, partitioner.chType ) ) { for( unsigned ch = 0; ch < numTBlocks; ch++ ) @@ -2089,17 +2463,15 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, compCbf[ch] |= ( TU::getCbfAtDepth( currTU, ComponentID( ch ), currDepth + 1 ) ? 1 : 0 ); } } +#endif + for (auto &currTU: cs.traverseTUs(currArea, partitioner.chType)) { - - for( auto &currTU : cs.traverseTUs( currArea, partitioner.chType ) ) + TU::setCbfAtDepth(currTU, COMPONENT_Y, currDepth, compCbf[COMPONENT_Y]); + if (currArea.chromaFormat != CHROMA_400) { - TU::setCbfAtDepth( currTU, COMPONENT_Y, currDepth, compCbf[COMPONENT_Y] ); - if( currArea.chromaFormat != CHROMA_400 ) - { - TU::setCbfAtDepth( currTU, COMPONENT_Cb, currDepth, compCbf[COMPONENT_Cb] ); - TU::setCbfAtDepth( currTU, COMPONENT_Cr, currDepth, compCbf[COMPONENT_Cr] ); - } + TU::setCbfAtDepth(currTU, COMPONENT_Cb, currDepth, compCbf[COMPONENT_Cb]); + TU::setCbfAtDepth(currTU, COMPONENT_Cr, currDepth, compCbf[COMPONENT_Cr]); } } } @@ -2107,6 +2479,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { TransformUnit &tu = cs.addTU( CS::getArea( cs, area, partitioner.chType ), partitioner.chType ); unsigned numBlocks = ::getNumberValidTBlocks( *cs.pcv ); +#if JVET_M0140_SBT + tu.checkTuNoResidual( partitioner.currPartIdx() ); + chromaCbfs.Cb &= !tu.noResidual; + chromaCbfs.Cr &= !tu.noResidual; +#endif for( unsigned compID = COMPONENT_Y; compID < numBlocks; compID++ ) { @@ -2125,13 +2502,56 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { TU::setCbfAtDepth( tu, COMPONENT_Y, trDepth, 1 ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && tu.noResidual ) + { + TU::setCbfAtDepth( tu, COMPONENT_Y, trDepth, 0 ); + } + else if( cu.sbtInfo && !chromaCbfsLastDepth.sigChroma( area.chromaFormat ) ) + { + assert( !tu.noResidual ); + TU::setCbfAtDepth( tu, COMPONENT_Y, trDepth, 1 ); + } +#endif else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool rootCbfSoFar = false; + bool lastCbfIsInferred = false; + if( cu.ispMode ) + { + uint32_t nTus = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[tu.lheight()] : cu.lwidth() >> g_aucLog2[tu.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = cu.firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, trDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( tu, COMPONENT_Y, trDepth ); + } + } + bool cbfY = lastCbfIsInferred ? true : cbf_comp( cs, tu.Y(), trDepth, previousCbf, cu.ispMode ); +#else bool cbfY = cbf_comp( cs, tu.Y(), trDepth ); +#endif TU::setCbfAtDepth( tu, COMPONENT_Y, trDepth, ( cbfY ? 1 : 0 ) ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 ) +#endif { TU::setCbfAtDepth( tu, COMPONENT_Cb, trDepth, ( chromaCbfs.Cb ? 1 : 0 ) ); TU::setCbfAtDepth( tu, COMPONENT_Cr, trDepth, ( chromaCbfs.Cr ? 1 : 0 ) ); @@ -2145,9 +2565,15 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, } } +#if JVET_M0102_INTRA_SUBPARTITIONS +bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbf, const bool useISP ) +{ + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbf, useISP && isLuma( area.compID ) ); +#else bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf ) { const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf ); +#endif const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2(STATS__CABAC_BITS__QT_CBF, area.size(), area.compID); @@ -2158,10 +2584,6 @@ bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned return cbf; } - - - - //================================================================================ // clause 7.3.8.9 //-------------------------------------------------------------------------------- @@ -2233,7 +2655,11 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c CodingUnit& cu = *tu.cu; bool lumaOnly = ( cu.chromaFormat == CHROMA_400 || !tu.blocks[COMPONENT_Cb].valid() ); bool cbfLuma = ( tu.cbf[ COMPONENT_Y ] != 0 ); +#if JVET_M0102_INTRA_SUBPARTITIONS + bool cbfChroma = ( lumaOnly ? false : ( chromaCbfs.Cb || chromaCbfs.Cr ) ); +#else bool cbfChroma = ( cu.chromaFormat == CHROMA_400 ? false : ( chromaCbfs.Cb || chromaCbfs.Cr ) ); +#endif if( cbfLuma || cbfChroma ) { @@ -2316,10 +2742,6 @@ void CABACReader::cu_chroma_qp_offset( CodingUnit& cu ) cu.chromaQpAdj = cu.cs->chromaQpAdj = qpAdj; } - - - - //================================================================================ // clause 7.3.8.11 //-------------------------------------------------------------------------------- @@ -2374,20 +2796,48 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) #endif // parse last coeff position +#if JVET_M0297_32PT_MTS_ZERO_OUT + cctx.setScanPosLast( last_sig_coeff( cctx, tu, compID ) ); +#else cctx.setScanPosLast( last_sig_coeff( cctx ) ); +#endif // parse subblocks const int stateTransTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 ); int state = 0; #if !JVET_M0464_UNI_MTS - bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); + bool useEmt = ( cu.cs->sps->getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + useEmt = useEmt && !cu.ispMode; +#endif #endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId ); +#if JVET_M0297_32PT_MTS_ZERO_OUT +#if JVET_M0140_SBT +#if JVET_M0464_UNI_MTS + if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#else +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#endif + { + if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) ) || ( tu.blocks[ compID ].width == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth() ) ) ) + { + continue; + } + } +#endif residual_coding_subblock( cctx, coeff, stateTransTab, state ); #if !JVET_M0464_UNI_MTS if (useEmt) @@ -2422,6 +2872,8 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) if( !mtsAllowed && !tsAllowed ) return; + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__MTS_FLAGS, tu.blocks[compID], compID ); + int symbol = 0; int ctxIdx = 0; @@ -2461,8 +2913,11 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) #else void CABACReader::transform_skip_flag( TransformUnit& tu, ComponentID compID ) { - +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) || ( tu.cu->ispMode && isLuma( compID ) ) ) +#else if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) ) +#endif { tu.transformSkip[compID] = false; return; @@ -2506,9 +2961,19 @@ void CABACReader::emt_tu_index( TransformUnit& tu ) void CABACReader::emt_cu_flag( CodingUnit& cu ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( CU::isIntra( cu ) && cu.ispMode ) + { + return; + } +#endif const CodingStructure &cs = *cu.cs; - if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) +#if JVET_M0483_IBC + if (!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && !CU::isIntra(cu))) || isChroma(cu.chType)) +#else + if( !( ( cs.sps->getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) +#endif { return; } @@ -2539,6 +3004,46 @@ void CABACReader::emt_cu_flag( CodingUnit& cu ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACReader::isp_mode( CodingUnit& cu ) +{ + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx ) + { + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + return; + } + + const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); + if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) + { + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + return; + } + + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_MODE_FLAG ); + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + int symbol = m_BinDecoder.decodeBin( Ctx::ISPMode( 0 ) ); + + if( symbol ) + { + if( allowedSplits == HOR_INTRA_SUBPARTITIONS ) + { + cu.ispMode = HOR_INTRA_SUBPARTITIONS; + } + else if( allowedSplits == VER_INTRA_SUBPARTITIONS ) + { + cu.ispMode = VER_INTRA_SUBPARTITIONS; + } + else + { + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_SPLIT_FLAG ); + cu.ispMode = 1 + m_BinDecoder.decodeBin( Ctx::ISPMode( 1 ) ); + } + } + DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); +} +#endif + void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; @@ -2569,11 +3074,52 @@ void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) } +#if JVET_M0297_32PT_MTS_ZERO_OUT +int CABACReader::last_sig_coeff( CoeffCodingContext& cctx, TransformUnit& tu, ComponentID compID ) +#else int CABACReader::last_sig_coeff( CoeffCodingContext& cctx ) +#endif { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__LAST_SIG_X_Y, Size( cctx.width(), cctx.height() ), cctx.compID() ); unsigned PosLastX = 0, PosLastY = 0; +#if JVET_M0297_32PT_MTS_ZERO_OUT + unsigned maxLastPosX = cctx.maxLastPosX(); + unsigned maxLastPosY = cctx.maxLastPosY(); + +#if JVET_M0140_SBT +#if JVET_M0464_UNI_MTS + if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#else +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#endif + { + maxLastPosX = ( tu.blocks[ compID ].width == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX; + maxLastPosY = ( tu.blocks[ compID ].height == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosY; + } + + for( ; PosLastX < maxLastPosX; PosLastX++ ) + { + if( !m_BinDecoder.decodeBin( cctx.lastXCtxId( PosLastX ) ) ) + { + break; + } + } + for( ; PosLastY < maxLastPosY; PosLastY++ ) + { + if( !m_BinDecoder.decodeBin( cctx.lastYCtxId( PosLastY ) ) ) + { + break; + } + } +#else for( ; PosLastX < cctx.maxLastPosX(); PosLastX++ ) { if( ! m_BinDecoder.decodeBin( cctx.lastXCtxId( PosLastX ) ) ) @@ -2588,6 +3134,7 @@ int CABACReader::last_sig_coeff( CoeffCodingContext& cctx ) break; } } +#endif if( PosLastX > 3 ) { uint32_t uiTemp = 0; @@ -2873,11 +3420,6 @@ void CABACReader::residual_coding_subblock( CoeffCodingContext& cctx, TCoeff* co #endif } - - - - - //================================================================================ // clause 7.3.8.12 //-------------------------------------------------------------------------------- diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 8e5586e5007f95e5575812bfd5fbe899116e6aca..e0724dac6d9fe647a80ef5751e64e9a051e08898 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -96,6 +96,9 @@ public: void intra_chroma_pred_mode ( PredictionUnit& pu ); void cu_residual ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); void rqt_root_cbf ( CodingUnit& cu ); +#if JVET_M0140_SBT + void sbt_mode ( CodingUnit& cu ); +#endif bool end_of_ctu ( CodingUnit& cu, CUCtx& cuCtx ); // prediction unit (clause 7.3.8.6) @@ -107,6 +110,9 @@ public: void merge_idx ( PredictionUnit& pu ); void mmvd_merge_idx(PredictionUnit& pu); void imv_mode ( CodingUnit& cu, MergeCtx& mrgCtx ); +#if JVET_M0246_AFFINE_AMVR + void affine_amvr_mode ( CodingUnit& cu, MergeCtx& mrgCtx ); +#endif void inter_pred_idc ( PredictionUnit& pu ); void ref_idx ( PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( PredictionUnit& pu, RefPicList eRefList ); @@ -121,8 +127,13 @@ public: void pcm_samples ( TransformUnit& tu ); // transform tree (clause 7.3.8.8) +#if JVET_M0102_INTRA_SUBPARTITIONS + void transform_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); + bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); +#else void transform_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf = false ); +#endif // mvd coding (clause 7.3.8.9) void mvd_coding ( Mv &rMvd ); @@ -140,9 +151,16 @@ public: void transform_skip_flag ( TransformUnit& tu, ComponentID compID ); void emt_tu_index ( TransformUnit& tu ); void emt_cu_flag ( CodingUnit& cu ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + void isp_mode ( CodingUnit& cu ); #endif void explicit_rdpcm_mode ( TransformUnit& tu, ComponentID compID ); +#if JVET_M0297_32PT_MTS_ZERO_OUT + int last_sig_coeff ( CoeffCodingContext& cctx, TransformUnit& tu, ComponentID compID ); +#else int last_sig_coeff ( CoeffCodingContext& cctx ); +#endif void residual_coding_subblock ( CoeffCodingContext& cctx, TCoeff* coeff, const int stateTransTable, int& state ); // cross component prediction (clause 7.3.8.12) diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 6913f67f690f184b7f47a0e3664118494d989372..8a85f4cc748f6b1789d92f6f44eece7df1bdf674 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -62,6 +62,9 @@ DecCu::DecCu() { +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU = NULL; +#endif } DecCu::~DecCu() @@ -74,6 +77,27 @@ void DecCu::init( TrQuant* pcTrQuant, IntraPrediction* pcIntra, InterPrediction* m_pcIntraPred = pcIntra; m_pcInterPred = pcInter; } +#if JVET_M0427_INLOOP_RESHAPER +void DecCu::initDecCuReshaper (Reshape* pcReshape, ChromaFormat chromaFormatIDC) +{ + m_pcReshape = pcReshape; + if (m_tmpStorageLCU == NULL) + { + m_tmpStorageLCU = new PelStorage; + m_tmpStorageLCU->create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); + } + +} +void DecCu::destoryDecCuReshaprBuf() +{ + if (m_tmpStorageLCU) + { + m_tmpStorageLCU->destroy(); + delete m_tmpStorageLCU; + m_tmpStorageLCU = NULL; + } +} +#endif // ==================================================================================================================== // Public member functions @@ -96,7 +120,7 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) const ChannelType chType = ChannelType( ch ); #if JVET_M0170_MRG_SHARELIST Position prevTmpPos; - prevTmpPos.x = -1; prevTmpPos.y = -1; + prevTmpPos.x = -1; prevTmpPos.y = -1; #endif for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, chType ), chType ) ) @@ -109,7 +133,7 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) m_shareStateDec = GEN_ON_SHARED_BOUND; cs.slice->copyMotionLUTs(cs.slice->getMotionLUTs(), cs.slice->m_MotionCandLuTsBkup); } - + if (currCU.shareParentPos.x < 0) { m_shareStateDec = 0; @@ -125,6 +149,9 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) switch( currCU.predMode ) { case MODE_INTER: +#if JVET_M0483_IBC + case MODE_IBC: +#endif xReconInter( currCU ); break; case MODE_INTRA: @@ -185,7 +212,24 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) { m_pcIntraPred->predIntraAng( compID, piPred, pu, bUseFilteredPredictions ); } - +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; +#if JVET_M0483_IBC + bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())); +#else + bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()) || (slice.getSliceType() == P_SLICE && slice.getSPS()->getIBCMode())); +#endif + if (flag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && (compID != COMPONENT_Y)) + { + const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size())); + const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area); + PelBuf piPredY; + piPredY = cs.picture->getPredBuf(areaY); + const Pel avgLuma = piPredY.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif //===== inverse transform ===== PelBuf piResi = cs.getResiBuf( area ); @@ -201,6 +245,13 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + flag = flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); + if (flag && TU::getCbf(tu, compID) && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); + } +#endif if( isChroma(compID) && tu.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true ); @@ -208,8 +259,38 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) PelBuf pReco = cs.getRecoBuf( area ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->ispMode || !isLuma( compID ) ) + { + cs.setDecomp( area ); + } + else if( tu.cu->ispMode && isLuma( compID ) && CU::isISPFirst( *tu.cu, tu.blocks[compID], compID ) ) + { + cs.setDecomp( tu.cu->blocks[compID] ); + } +#else cs.setDecomp( area ); +#endif +#if JVET_M0427_INLOOP_RESHAPER +#if REUSE_CU_RESULTS + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred; +#endif +#if JVET_M0483_IBC + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) +#else + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra() || (slice.getSliceType() == P_SLICE && slice.getSPS()->getIBCMode())) && compID == COMPONENT_Y) +#endif + { +#if REUSE_CU_RESULTS + { + tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(piPred); + } +#endif + } +#endif #if KEEP_PRED_AND_RESI_SIGNALS pReco.reconstruct( piPred, piResi, tu.cu->cs->slice->clpRng( compID ) ); #else @@ -218,10 +299,27 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) #if !KEEP_PRED_AND_RESI_SIGNALS pReco.copyFrom( piPred ); #endif +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra()) && compID == COMPONENT_Y) +#else + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra() || (slice.getSliceType() == P_SLICE && slice.getSPS()->getIBCMode())) && compID == COMPONENT_Y) +#endif + { +#if REUSE_CU_RESULTS + { + piPred.copyFrom(tmpPred); + } +#endif + } +#endif #if REUSE_CU_RESULTS if( cs.pcv->isEncoder ) { cs.picture->getRecoBuf( area ).copyFrom( pReco ); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(area).copyFrom(piPred); +#endif } #endif } @@ -352,22 +450,39 @@ void DecCu::xReconInter(CodingUnit &cu) { if( cu.triangle ) { +#if JVET_M0883_TRIANGLE_SIGNALING + const bool splitDir = cu.firstPU->triangleSplitDir; + const uint8_t candIdx0 = cu.firstPU->triangleMergeIdx0; + const uint8_t candIdx1 = cu.firstPU->triangleMergeIdx1; +#else const uint8_t mergeIdx = cu.firstPU->mergeIdx; const bool splitDir = g_triangleCombination[mergeIdx][0]; const uint8_t candIdx0 = g_triangleCombination[mergeIdx][1]; const uint8_t candIdx1 = g_triangleCombination[mergeIdx][2]; +#endif m_pcInterPred->motionCompensation4Triangle( cu, m_triangleMrgCtx, splitDir, candIdx0, candIdx1 ); +#if JVET_M0883_TRIANGLE_SIGNALING + PU::spanTriangleMotionInfo( *cu.firstPU, m_triangleMrgCtx, splitDir, candIdx0, candIdx1 ); +#else PU::spanTriangleMotionInfo( *cu.firstPU, m_triangleMrgCtx, mergeIdx, splitDir, candIdx0, candIdx1 ); +#endif } else { m_pcIntraPred->geneIntrainterPred(cu); // inter prediction +#if JVET_M0483_IBC + CHECK(CU::isIBC(cu) && cu.firstPU->mhIntraFlag, "IBC and MHIntra cannot be used together"); + CHECK(CU::isIBC(cu) && cu.affine, "IBC and Affine cannot be used together"); + CHECK(CU::isIBC(cu) && cu.triangle, "IBC and triangle cannot be used together"); + CHECK(CU::isIBC(cu) && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together"); +#else CHECK(cu.ibc && cu.firstPU->mhIntraFlag, "IBC and MHIntra cannot be used together"); CHECK(cu.ibc && cu.affine, "IBC and Affine cannot be used together"); CHECK(cu.ibc && cu.triangle, "IBC and triangle cannot be used together"); CHECK(cu.ibc && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together"); +#endif const bool luma = cu.Y().valid(); const bool chroma = cu.Cb().valid(); if (luma && chroma) @@ -384,6 +499,12 @@ void DecCu::xReconInter(CodingUnit &cu) if (cu.firstPU->mhIntraFlag) { +#if JVET_M0427_INLOOP_RESHAPER + if (cu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + cu.cs->getPredBuf(*cu.firstPU).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraPred->geneWeightedPred(COMPONENT_Y, cu.cs->getPredBuf(*cu.firstPU).Y(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Y, 0)); m_pcIntraPred->geneWeightedPred(COMPONENT_Cb, cu.cs->getPredBuf(*cu.firstPU).Cb(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cb, 0)); m_pcIntraPred->geneWeightedPred(COMPONENT_Cr, cu.cs->getPredBuf(*cu.firstPU).Cr(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cr, 0)); @@ -391,7 +512,7 @@ void DecCu::xReconInter(CodingUnit &cu) DTRACE ( g_trace_ctx, D_TMP, "pred " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getPredBuf( cu ), &cu.Y() ); - + // inter recon xDecodeInterTexture(cu); @@ -400,18 +521,62 @@ void DecCu::xReconInter(CodingUnit &cu) if (cu.rootCbf) { +#if JVET_M0427_INLOOP_RESHAPER +#if REUSE_CU_RESULTS + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred; +#endif + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { +#if REUSE_CU_RESULTS + if (cs.pcv->isEncoder) + { + tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(cu).get(COMPONENT_Y)); + } +#endif +#if JVET_M0483_IBC + if (!cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (!cu.firstPU->mhIntraFlag && !cu.ibc ) +#endif + cs.getPredBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + } +#endif #if KEEP_PRED_AND_RESI_SIGNALS cs.getRecoBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); #else cs.getResiBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); cs.getRecoBuf( cu ).copyFrom ( cs.getResiBuf( cu ) ); +#endif +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { +#if REUSE_CU_RESULTS + if (cs.pcv->isEncoder) + { + cs.getPredBuf(cu).get(COMPONENT_Y).copyFrom(tmpPred); + } +#endif + } #endif } else { cs.getRecoBuf(cu).copyClip(cs.getPredBuf(cu), cs.slice->clpRngs()); +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + { + cs.getRecoBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + } +#endif } - + DTRACE ( g_trace_ctx, D_TMP, "reco " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getRecoBuf( cu ), &cu.Y() ); @@ -441,6 +606,13 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + if ( slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && TU::getCbf(currTU, compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && currTU.blocks[compID].width*currTU.blocks[compID].height > 4 ) + { + resiBuf.scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(compID)); + } +#endif if( isChroma( compID ) && currTU.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( currTU, compID, cs.getResiBuf( currTU.Y() ), resiBuf, resiBuf, true ); @@ -462,6 +634,27 @@ void DecCu::xDecodeInterTexture(CodingUnit &cu) for( auto& currTU : CU::traverseTUs( cu ) ) { +#if JVET_M0427_INLOOP_RESHAPER + CodingStructure &cs = *cu.cs; + const Slice &slice = *cs.slice; + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && slice.getReshapeInfo().getSliceReshapeChromaAdj() && (compID == COMPONENT_Y)) + { + const CompArea &areaY = currTU.blocks[COMPONENT_Y]; + PelBuf predY = cs.getPredBuf(areaY); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(predY); +#if JVET_M0483_IBC + if (!cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (!cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + const Pel avgLuma = tmpPred.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + currTU.setChromaAdj(adj); + } +#endif xDecodeInterTU( currTU, compID ); } } @@ -557,6 +750,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) #if JVET_M0170_MRG_SHARELIST pu.shareParentPos = cu.shareParentPos; pu.shareParentSize = cu.shareParentSize; +#endif +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx); + else #endif PU::getInterMergeCandidates(pu, mrgCtx, 0, pu.mergeIdx); #if !JVET_M0068_M0171_MMVD_CLEANUP @@ -573,7 +771,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) else { #if REUSE_CU_RESULTS +#if JVET_M0246_AFFINE_AMVR + if ( cu.imv && !pu.cu->affine && !cu.cs->pcv->isEncoder ) +#else if (cu.imv && !cu.cs->pcv->isEncoder) +#endif #else if (cu.imv) #endif @@ -598,7 +800,39 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) // Mv mv[3]; CHECK( pu.refIdx[eRefList] < 0, "Unexpected negative refIdx." ); +#if JVET_M0246_AFFINE_AMVR +#if !JVET_M0055_DEBUG_CTU + Mv tmpMvd[3]; + memcpy( tmpMvd, pu.mvdAffi[eRefList], 3 * sizeof( Mv ) ); +#endif + const int imvShift = ( !cu.cs->pcv->isEncoder && pu.cu->imv == 2 ) ? MV_FRACTIONAL_BITS_DIFF : 0; + pu.mvdAffi[eRefList][0] <<= imvShift; + pu.mvdAffi[eRefList][1] <<= imvShift; + Mv mvLT = affineAMVPInfo.mvCandLT[mvp_idx] + pu.mvdAffi[eRefList][0]; + Mv mvRT = affineAMVPInfo.mvCandRT[mvp_idx] + pu.mvdAffi[eRefList][1]; + mvRT += pu.mvdAffi[eRefList][0]; + if ( pu.cu->imv != 1 ) + { + mvLT.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + mvRT.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + + Mv mvLB; + if ( cu.affineType == AFFINEMODEL_6PARAM ) + { + pu.mvdAffi[eRefList][2] <<= imvShift; + mvLB = affineAMVPInfo.mvCandLB[mvp_idx] + pu.mvdAffi[eRefList][2]; + mvLB += pu.mvdAffi[eRefList][0]; + if ( pu.cu->imv != 1 ) + { + mvLB.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + } +#if !JVET_M0055_DEBUG_CTU //th this leads to different interpretation of mvdAffi at encoder and decoder + memcpy( pu.mvdAffi[eRefList], tmpMvd, 3 * sizeof( Mv ) ); +#endif +#else Mv mvLT = affineAMVPInfo.mvCandLT[mvp_idx] + pu.mvdAffi[eRefList][0]; Mv mvRT = affineAMVPInfo.mvCandRT[mvp_idx] + pu.mvdAffi[eRefList][1]; mvRT += pu.mvdAffi[eRefList][0]; @@ -612,20 +846,41 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) mvLB += pu.mvdAffi[eRefList][0]; mvLB.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); } +#endif PU::setAllAffineMv( pu, mvLT, mvRT, mvLB, eRefList ); } } } +#if JVET_M0483_IBC + else if (CU::isIBC(*pu.cu) && pu.interDir == 1) + { + AMVPInfo amvpInfo; + PU::fillIBCMvpCand(pu, amvpInfo); + pu.mvpNum[REF_PIC_LIST_0] = amvpInfo.numCand; + Mv mvd = pu.mvd[REF_PIC_LIST_0]; +#if REUSE_CU_RESULTS + if (!cu.cs->pcv->isEncoder) +#endif + mvd <<= 2; + pu.mv[REF_PIC_LIST_0] = amvpInfo.mvCand[pu.mvpIdx[REF_PIC_LIST_0]] + mvd; + pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + } +#endif else { for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) { RefPicList eRefList = RefPicList( uiRefListIdx ); +#if JVET_M0483_IBC + if ((pu.cs->slice->getNumRefIdx(eRefList) > 0 || (eRefList == REF_PIC_LIST_0 && CU::isIBC(*pu.cu))) && (pu.interDir & (1 << uiRefListIdx))) +#else if ( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << uiRefListIdx ) ) ) +#endif { AMVPInfo amvpInfo; PU::fillMvpCand(pu, eRefList, pu.refIdx[eRefList], amvpInfo); pu.mvpNum [eRefList] = amvpInfo.numCand; +#if JVET_M0483_IBC==0 Mv mvd = pu.mvd[eRefList]; if (eRefList == REF_PIC_LIST_0 && pu.cs->slice->getRefPic(eRefList, pu.refIdx[eRefList])->getPOC() == pu.cs->slice->getPOC()) { @@ -636,6 +891,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) mvd.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER); } pu.mv [eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + mvd; +#else + pu.mv[eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + pu.mvd[eRefList]; +#endif pu.mv[eRefList].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); } } diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h index 67e5dc4fbc2a15faa777b7c1c34b35042e1d6fa0..40114ce68e6528104ff586e1d387dd5535ff956f 100644 --- a/source/Lib/DecoderLib/DecCu.h +++ b/source/Lib/DecoderLib/DecCu.h @@ -48,7 +48,9 @@ #include "CommonLib/InterPrediction.h" #include "CommonLib/IntraPrediction.h" #include "CommonLib/Unit.h" - +#if JVET_M0427_INLOOP_RESHAPER +#include "CommonLib/Reshape.h" +#endif //! \ingroup DecoderLib //! \{ @@ -68,6 +70,12 @@ public: /// destroy internal buffers void decompressCtu ( CodingStructure& cs, const UnitArea& ctuArea ); +#if JVET_M0427_INLOOP_RESHAPER + Reshape* m_pcReshape; + Reshape* getReshape () { return m_pcReshape; } + void initDecCuReshaper ( Reshape* pcReshape, ChromaFormat chromaFormatIDC) ; + void destoryDecCuReshaprBuf(); +#endif #if JVET_M0170_MRG_SHARELIST void setShareStateDec (int shareStateDecIn) { m_shareStateDec = shareStateDecIn; } @@ -87,7 +95,9 @@ protected: void xDecodeInterTU ( TransformUnit& tu, const ComponentID compID ); void xDeriveCUMV ( CodingUnit& cu ); - +#if JVET_M0427_INLOOP_RESHAPER + PelStorage *m_tmpStorageLCU; +#endif private: TrQuant* m_pcTrQuant; IntraPrediction* m_pcIntraPred; diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 09b493dd5c22f0168a000b5768cd947043a1d35d..6190cfb5b474d53e4570dcd60527186eca241b33 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -56,7 +56,11 @@ #include "CommonLib/CodingStatistics.h" #endif +#if JVET_M0055_DEBUG_CTU +bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound /* = false */, int debugCTU /* = -1*/, int debugPOC /* = -1*/ ) +#else bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound /* = false */ ) +#endif { int poc; PicList* pcListPic = NULL; @@ -91,6 +95,10 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri #endif ); +#if JVET_M0055_DEBUG_CTU + pcDecLib->setDebugCTU( debugCTU ); + pcDecLib->setDebugPOC( debugPOC ); +#endif pcDecLib->setDecodedPictureHashSEIEnabled( true ); bFirstCall = false; @@ -156,6 +164,10 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri CHECK( expectedPoc != poc, "mismatch in POC - check encoder configuration" ); +#if JVET_M0055_DEBUG_CTU + if( debugCTU < 0 || poc != debugPOC ) + { +#endif for( int i = 0; i < pic->slices.size(); i++ ) { if( pcEncPic->slices.size() <= i ) @@ -165,9 +177,33 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri } pcEncPic->slices[i]->copySliceInfo( pic->slices[i], false ); } +#if JVET_M0055_DEBUG_CTU + } +#endif pcEncPic->cs->slice = pcEncPic->slices.back(); +#if JVET_M0055_DEBUG_CTU + if( debugCTU >= 0 && poc == debugPOC ) + { + pcEncPic->cs->initStructData(); + + pcEncPic->cs->copyStructure( *pic->cs, CH_L, true, true ); + + if( CS::isDualITree( *pcEncPic->cs ) ) + { + pcEncPic->cs->copyStructure( *pic->cs, CH_C, true, true ); + } + + for( auto &cu : pcEncPic->cs->cus ) + { + cu->slice = pcEncPic->cs->slice; + } + pcEncPic->cs->slice->copyMotionLUTs( pic->slices.back()->getMotionLUTs(), pcEncPic->slices.back()->getMotionLUTs()); + } + else + { +#endif if ( pic->cs->sps->getSAOEnabledFlag() ) { pcEncPic->copySAO( *pic, 0 ); @@ -198,6 +234,9 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri { pcEncPic->cs->copyStructure( *pic->cs, CH_C, true, true ); } +#if JVET_M0055_DEBUG_CTU + } +#endif goOn = false; // exit the loop return bRet = true; break; @@ -353,6 +392,9 @@ DecLib::DecLib() , m_cSAO() #if JVET_J0090_MEMORY_BANDWITH_MEASURE , m_cacheModel() +#endif +#if JVET_M0427_INLOOP_RESHAPER + , m_cReshaper() #endif , m_pcPic(NULL) , m_prevPOC(MAX_INT) @@ -370,6 +412,10 @@ DecLib::DecLib() , m_numberOfChecksumErrorsDetected(0) , m_warningMessageSkipPicture(false) , m_prefixSEINALUs() +#if JVET_M0055_DEBUG_CTU + , m_debugPOC( -1 ) + , m_debugCTU( -1 ) +#endif { #if ENABLE_SIMD_OPT_BUFFER g_pelBufOP.initPelBufOpsX86(); @@ -401,7 +447,7 @@ void DecLib::destroy() void DecLib::init( #if JVET_J0090_MEMORY_BANDWITH_MEASURE - const std::string& cacheCfgFileName + const std::string& cacheCfgFileName #endif ) { @@ -434,6 +480,10 @@ void DecLib::deletePicBuffer ( ) m_cacheModel.reportSequence( ); m_cacheModel.destroy( ); #endif +#if JVET_M0427_INLOOP_RESHAPER + m_cCuDecoder.destoryDecCuReshaprBuf(); + m_cReshaper.destroy(); +#endif } Picture* DecLib::xGetNewPicBuffer ( const SPS &sps, const PPS &pps, const uint32_t temporalLayer ) @@ -508,9 +558,19 @@ void DecLib::executeLoopFilters() CodingStructure& cs = *m_pcPic->cs; +#if JVET_M0427_INLOOP_RESHAPER + if (cs.sps->getUseReshaper() && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) + { + CHECK((m_cReshaper.getRecReshaped() == false), "Rec picture is not reshaped!"); + m_pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_cReshaper.getInvLUT()); + m_cReshaper.setRecReshaped(false); + } +#endif // deblocking filter m_cLoopFilter.loopFilterPic( cs ); - +#if JVET_M0147_DMVR + CS::setRefinedMotionField(cs); +#endif if( cs.sps->getSAOEnabledFlag() ) { m_cSAO.SAOProcess( cs, cs.picture->getSAO() ); @@ -738,7 +798,12 @@ void DecLib::xActivateParameterSets() m_cLoopFilter.create( sps->getMaxCodingDepth() ); m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth( CHANNEL_TYPE_LUMA ) ); m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc() ); - +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + m_cReshaper.createDec(sps->getBitDepth(CHANNEL_TYPE_LUMA)); + } +#endif bool isField = false; bool isTopField = false; @@ -765,6 +830,12 @@ void DecLib::xActivateParameterSets() // Recursive structure m_cCuDecoder.init( &m_cTrQuant, &m_cIntraPred, &m_cInterPred ); +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + m_cCuDecoder.initDecCuReshaper(&m_cReshaper, sps->getChromaFormatIdc()); + } +#endif m_cTrQuant.init( nullptr, sps->getMaxTrSize(), false, false, false, false, false ); // RdCost @@ -1228,20 +1299,71 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl } #endif - if (pcSlice->getSPS()->getSpsNext().getIBCMode() && pcSlice->getEnableTMVPFlag()) +#if JVET_M0483_IBC + if (pcSlice->getSPS()->getIBCFlag() && pcSlice->getEnableTMVPFlag()) +#else + if (pcSlice->getSPS()->getIBCMode() && pcSlice->getEnableTMVPFlag()) +#endif { CHECK(pcSlice->getRefPic(RefPicList(pcSlice->isInterB() ? 1 - pcSlice->getColFromL0Flag() : 0), pcSlice->getColRefIdx())->getPOC() == pcSlice->getPOC(), "curr ref picture cannot be collocated picture"); } +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + m_cReshaper.copySliceReshaperInfo(m_cReshaper.getSliceReshaperInfo(), pcSlice->getReshapeInfo()); + if (pcSlice->getReshapeInfo().getSliceReshapeModelPresentFlag()) + { + m_cReshaper.constructReshaper(); + } + else + { + m_cReshaper.setReshapeFlag(false); + } +#if JVET_M0483_IBC + if ((pcSlice->getSliceType() == I_SLICE) && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) +#else + if ((pcSlice->getSliceType() == I_SLICE || (pcSlice->getSliceType() == P_SLICE && pcSlice->getSPS()->getIBCMode())) && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) +#endif + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(true); + } + else + { + if (m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) + { + m_cReshaper.setCTUFlag(true); + m_cReshaper.setRecReshaped(true); + } + else + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(false); + } + } + } + else + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(false); + } +#endif // Decode a picture +#if JVET_M0055_DEBUG_CTU + m_cSliceDecoder.decompressSlice( pcSlice, &( nalu.getBitstream() ), ( m_pcPic->poc == getDebugPOC() ? getDebugCTU() : -1 ) ); +#else m_cSliceDecoder.decompressSlice( pcSlice, &(nalu.getBitstream()) ); +#endif m_bFirstSliceInPicture = false; - if (pcSlice->getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (pcSlice->getSPS()->getIBCMode()) { pcSlice->getPic()->longTerm = false; } +#endif m_uiSliceSegmentIdx++; return false; diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 687ea822a8f759b03c5cea533c8f7ca244fcb608..ae94530450e6a9402275be64a23afaf6454dd2ba 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -53,14 +53,20 @@ #include "CommonLib/AdaptiveLoopFilter.h" #include "CommonLib/SEI.h" #include "CommonLib/Unit.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "CommonLib/Reshape.h" +#endif class InputNALUnit; //! \ingroup DecoderLib //! \{ -bool tryDecodePicture( Picture* pcPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound = false ); -// ==================================================================================================================== +#if JVET_M0055_DEBUG_CTU +bool tryDecodePicture( Picture* pcPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound = false, int debugCTU = -1, int debugPOC = -1 ); +#else + bool tryDecodePicture( Picture* pcPic, const int expectedPoc, const std::string& bitstreamFileName, bool bDecodeUntilPocFound = false ); +#endif// ==================================================================================================================== // Class definition // ==================================================================================================================== @@ -94,6 +100,9 @@ private: LoopFilter m_cLoopFilter; SampleAdaptiveOffset m_cSAO; AdaptiveLoopFilter m_cALF; +#if JVET_M0427_INLOOP_RESHAPER + Reshape m_cReshaper; ///< reshaper class +#endif // decoder side RD cost computation RdCost m_cRdCost; ///< RD cost computation class #if JVET_J0090_MEMORY_BANDWITH_MEASURE @@ -122,6 +131,10 @@ private: bool m_warningMessageSkipPicture; std::list<InputNALUnit*> m_prefixSEINALUs; /// Buffered up prefix SEI NAL Units. +#if JVET_M0055_DEBUG_CTU + int m_debugPOC; + int m_debugCTU; +#endif public: DecLib(); virtual ~DecLib(); @@ -152,6 +165,12 @@ public: void setDecodedSEIMessageOutputStream(std::ostream *pOpStream) { m_pDecodedSEIOutputStream = pOpStream; } uint32_t getNumberOfChecksumErrorsDetected() const { return m_numberOfChecksumErrorsDetected; } +#if JVET_M0055_DEBUG_CTU + int getDebugCTU( ) const { return m_debugCTU; } + void setDebugCTU( int debugCTU ) { m_debugCTU = debugCTU; } + int getDebugPOC( ) const { return m_debugPOC; }; + void setDebugPOC( int debugPOC ) { m_debugPOC = debugPOC; }; +#endif protected: void xUpdateRasInit(Slice* slice); diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 9f53af255e94362f985c8613ff890863acd4ae89..13be91a5c29412727f28774ed1a5f21893f29a8c 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -70,7 +70,11 @@ void DecSlice::init( CABACDecoder* cabacDecoder, DecCu* pcCuDecoder ) m_pcCuDecoder = pcCuDecoder; } +#if JVET_M0055_DEBUG_CTU +void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int debugCTU ) +#else void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream ) +#endif { //-- For time output for each slice slice->startProcessingTimer(); @@ -231,6 +235,14 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream ) cs.slice->resetMotionLUTs(); } +#if JVET_M0055_DEBUG_CTU + + if( ctuRsAddr == debugCTU ) + { + isLastCtuOfSliceSegment = true; // get out here + break; + } +#endif isLastCtuOfSliceSegment = cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr ); m_pcCuDecoder->decompressCtu( cs, ctuArea ); diff --git a/source/Lib/DecoderLib/DecSlice.h b/source/Lib/DecoderLib/DecSlice.h index 10304cf0e0084c3a9885e85ea9c93856f806f65e..f4a14e5b7dc24b67b2b593106665f8de6056f851 100644 --- a/source/Lib/DecoderLib/DecSlice.h +++ b/source/Lib/DecoderLib/DecSlice.h @@ -77,7 +77,11 @@ public: void create (); void destroy (); +#if JVET_M0055_DEBUG_CTU + void decompressSlice ( Slice* slice, InputBitstream* bitstream, int debugCTU ); +#else void decompressSlice ( Slice* slice, InputBitstream* bitstream ); +#endif }; //! \} diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 8e1725797c1a84d4eb0812d62a0b0356e20d60f7..2f740018f318cc38bd8a342a0df276952a2b4269 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -782,89 +782,62 @@ void HLSyntaxReader::parseHrdParameters(HRD *hrd, bool commonInfPresentFlag, uin } } - -void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) +#if JVET_M0427_INLOOP_RESHAPER +void HLSyntaxReader::parseReshaper(SliceReshapeInfo& info, const SPS* pcSPS, const bool isIntra) { unsigned symbol = 0; - - // tool enabling flags - READ_FLAG( symbol, "large_ctu_flag" ); spsNext.setUseLargeCTU ( symbol != 0 ); - READ_FLAG( symbol, "imv_enable_flag" ); spsNext.setUseIMV ( symbol != 0 ); - READ_FLAG( symbol, "disable_motion_compression_flag" ); spsNext.setDisableMotCompress ( symbol != 0 ); - READ_FLAG( symbol, "lm_chroma_enabled_flag" ); spsNext.setUseLMChroma ( symbol != 0 ); -#if JVET_M0142_CCLM_COLLOCATED_CHROMA - if ( spsNext.getUseLMChroma() && spsNext.getSPS().getChromaFormatIdc() == CHROMA_420 ) - { - READ_FLAG( symbol, "sps_cclm_collocated_chroma_flag" ); spsNext.setCclmCollocatedChromaFlag( symbol != 0 ); - } -#endif -#if JVET_M0464_UNI_MTS - READ_FLAG( symbol, "mts_intra_enabled_flag" ); spsNext.setUseIntraMTS ( symbol != 0 ); - READ_FLAG( symbol, "mts_inter_enabled_flag" ); spsNext.setUseInterMTS ( symbol != 0 ); -#else - READ_FLAG( symbol, "emt_intra_enabled_flag" ); spsNext.setUseIntraEMT ( symbol != 0 ); - READ_FLAG( symbol, "emt_inter_enabled_flag" ); spsNext.setUseInterEMT ( symbol != 0 ); -#endif - READ_FLAG( symbol, "affine_flag" ); spsNext.setUseAffine ( symbol != 0 ); - if ( spsNext.getUseAffine() ) - { - READ_FLAG( symbol, "affine_type_flag" ); spsNext.setUseAffineType ( symbol != 0 ); - } - READ_FLAG( symbol, "gbi_flag" ); spsNext.setUseGBi ( symbol != 0 ); - READ_FLAG( symbol, "ibc_flag"); spsNext.setIBCMode ( symbol != 0 ); - for( int k = 0; k < SPSNext::NumReservedFlags; k++ ) - { - READ_FLAG( symbol, "reserved_flag" ); if( symbol != 0 ) EXIT("Incompatible version: SPSNext reserved flag not equal to zero (bitstream was probably created with newer software version)" ); - } - READ_FLAG( symbol, "mtt_enabled_flag" ); spsNext.setMTTMode ( symbol ); - READ_FLAG( symbol, "mhintra_flag" ); spsNext.setUseMHIntra ( symbol != 0 ); - READ_FLAG( symbol, "triangle_flag" ); spsNext.setUseTriangle ( symbol != 0 ); -#if ENABLE_WPP_PARALLELISM - READ_FLAG( symbol, "next_dqp_enabled_flag" ); spsNext.setUseNextDQP ( symbol != 0 ); -#else - READ_FLAG( symbol, "reserved_flag" ); CHECK( symbol, "reserved flag not 0!" ); -#endif - - if( spsNext.getUseIMV() ) - { - READ_UVLC( symbol, "imv_mode_minus1" ); spsNext.setImvMode( ImvMode( symbol + 1 ) ); - } - if( spsNext.getMTTEnabled() ) - { - READ_UVLC( symbol, "mtt_mode_minus1" ); spsNext.setMTTMode( symbol + 1 ); + READ_FLAG(symbol, "tile_group_reshaper_model_present_flag"); info.setSliceReshapeModelPresentFlag(symbol == 1); + if (info.getSliceReshapeModelPresentFlag()) + { + memset(info.reshaperModelBinCWDelta, 0, PIC_CODE_CW_BINS * sizeof(int)); + READ_UVLC(symbol, "reshaper_model_min_bin_idx"); info.reshaperModelMinBinIdx = symbol; + READ_UVLC(symbol, "reshaper_model_delta_max_bin_idx"); info.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1 - symbol; + READ_UVLC(symbol, "reshaper_model_bin_delta_abs_cw_prec_minus1"); info.maxNbitsNeededDeltaCW = symbol + 1; + assert(info.maxNbitsNeededDeltaCW > 0); + for (uint32_t i = info.reshaperModelMinBinIdx; i <= info.reshaperModelMaxBinIdx; i++) + { + READ_CODE(info.maxNbitsNeededDeltaCW, symbol, "reshaper_model_bin_delta_abs_CW"); + int absCW = symbol; + if (absCW > 0) + { + READ_CODE(1, symbol, "reshaper_model_bin_delta_sign_CW_flag"); + } + int signCW = symbol; + info.reshaperModelBinCWDelta[i] = (1 - 2 * signCW) * absCW; + } } - - -#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - READ_FLAG( symbol, "sps_ladf_enabled_flag" ); spsNext.setLadfEnabled( symbol != 0 ); - if ( spsNext.getLadfEnabled() ) + READ_FLAG(symbol, "tile_group_reshaper_enable_flag"); info.setUseSliceReshaper(symbol == 1); + if (info.getUseSliceReshaper()) { - int signedSymbol = 0; - READ_CODE( 2, symbol, "sps_num_ladf_intervals_minus2"); spsNext.setLadfNumIntervals( symbol + 2 ); - READ_SVLC(signedSymbol, "sps_ladf_lowest_interval_qp_offset" ); spsNext.setLadfQpOffset( signedSymbol, 0 ); - for ( int k = 1; k < spsNext.getLadfNumIntervals(); k++ ) + if (!(pcSPS->getUseDualITree() && isIntra)) + { + READ_FLAG(symbol, "slice_reshaper_ChromaAdj"); info.setSliceReshapeChromaAdj(symbol); + } + else { - READ_SVLC(signedSymbol, "sps_ladf_qp_offset" ); spsNext.setLadfQpOffset( signedSymbol, k ); - READ_UVLC( symbol, "sps_ladf_delta_threshold_minus1"); - spsNext.setLadfIntervalLowerBound(symbol + spsNext.getLadfIntervalLowerBound(k - 1) + 1, k); + info.setSliceReshapeChromaAdj(0); } } -#endif - // ADD_NEW_TOOL : (sps extension parser) read tool enabling flags and associated parameters here } - +#endif void HLSyntaxReader::parseSPS(SPS* pcSPS) { + uint32_t uiCode; + #if ENABLE_TRACING xTraceSPSHeader (); #endif +#if HEVC_VPS + READ_CODE( 4, uiCode, "sps_video_parameter_set_id"); pcSPS->setVPSId ( uiCode ); +#endif + READ_UVLC( uiCode, "sps_seq_parameter_set_id" ); pcSPS->setSPSId( uiCode ); + CHECK(uiCode > 15, "Invalid SPS id signalled"); - uint32_t uiCode; READ_FLAG(uiCode, "intra_only_constraint_flag"); pcSPS->setIntraOnlyConstraintFlag(uiCode > 0 ? true : false); READ_CODE(4, uiCode, "max_bitdepth_constraint_idc"); pcSPS->setMaxBitDepthConstraintIdc(uiCode); READ_CODE(2, uiCode, "max_chroma_format_constraint_idc"); pcSPS->setMaxChromaFormatConstraintIdc(uiCode); - READ_FLAG(uiCode, "frame_constraint_flag"); pcSPS->setFrameConstraintFlag(uiCode > 0 ? true : false); - READ_FLAG(uiCode, "no_qtbtt_dual_tree_intra constraint_flag"); pcSPS->setNoQtbttDualTreeIntraConstraintFlag(uiCode > 0 ? true : false); + READ_FLAG(uiCode, "frame_only_constraint_flag"); pcSPS->setFrameConstraintFlag(uiCode > 0 ? true : false); + READ_FLAG(uiCode, "no_qtbtt_dual_tree_intra_constraint_flag"); pcSPS->setNoQtbttDualTreeIntraConstraintFlag(uiCode > 0 ? true : false); READ_FLAG(uiCode, "no_cclm_constraint_flag"); pcSPS->setNoCclmConstraintFlag(uiCode > 0 ? true : false); READ_FLAG(uiCode, "no_sao_constraint_flag"); pcSPS->setNoSaoConstraintFlag(uiCode > 0 ? true : false); READ_FLAG(uiCode, "no_alf_constraint_flag"); pcSPS->setNoAlfConstraintFlag(uiCode > 0 ? true : false); @@ -877,25 +850,22 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_FLAG(uiCode, "no_ladf_constraint_flag"); pcSPS->setNoLadfConstraintFlag(uiCode > 0 ? true : false); READ_FLAG(uiCode, "no_dep_quant_constraint_flag"); pcSPS->setNoDepQuantConstraintFlag(uiCode > 0 ? true : false); READ_FLAG(uiCode, "no_sign_data_hiding_constraint_flag"); pcSPS->setNoSignDataHidingConstraintFlag(uiCode > 0 ? true : false); -#if HEVC_VPS - READ_CODE( 4, uiCode, "sps_video_parameter_set_id"); pcSPS->setVPSId ( uiCode ); -#endif + + // KJS: Marakech decision: sub-layers added back READ_CODE( 3, uiCode, "sps_max_sub_layers_minus1" ); pcSPS->setMaxTLayers ( uiCode+1 ); CHECK(uiCode > 6, "Invalid maximum number of T-layer signalled"); - READ_FLAG( uiCode, "sps_temporal_id_nesting_flag" ); pcSPS->setTemporalIdNestingFlag ( uiCode > 0 ? true : false ); if ( pcSPS->getMaxTLayers() == 1 ) { // sps_temporal_id_nesting_flag must be 1 when sps_max_sub_layers_minus1 is 0 CHECK( uiCode != 1, "Invalid maximum number of T-layers" ); } - parsePTL(pcSPS->getPTL(), 1, pcSPS->getMaxTLayers() - 1); - READ_UVLC( uiCode, "sps_seq_parameter_set_id" ); pcSPS->setSPSId( uiCode ); - CHECK(uiCode > 15, "Invalid SPS id signalled"); READ_UVLC( uiCode, "chroma_format_idc" ); pcSPS->setChromaFormatIdc( ChromaFormat(uiCode) ); CHECK(uiCode > 3, "Invalid chroma format signalled"); + + // KJS: ENABLE_CHROMA_422 does not exist anymore o.O if( pcSPS->getChromaFormatIdc() == CHROMA_422 ) { EXIT( "Error: 4:2:2 chroma sampling format not supported with current compiler setting." @@ -909,6 +879,8 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_UVLC ( uiCode, "pic_width_in_luma_samples" ); pcSPS->setPicWidthInLumaSamples ( uiCode ); READ_UVLC ( uiCode, "pic_height_in_luma_samples" ); pcSPS->setPicHeightInLumaSamples( uiCode ); + + // KJS: not removing yet READ_FLAG( uiCode, "conformance_window_flag"); if (uiCode != 0) { @@ -933,6 +905,7 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_UVLC( uiCode, "log2_max_pic_order_cnt_lsb_minus4" ); pcSPS->setBitsForPOC( 4 + uiCode ); CHECK(uiCode > 12, "Invalid code"); + // KJS: Marakech decision: sub-layers added back uint32_t subLayerOrderingInfoPresentFlag; READ_FLAG(subLayerOrderingInfoPresentFlag, "sps_sub_layer_ordering_info_present_flag"); @@ -962,8 +935,8 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) unsigned maxBTSize[3] = { 0, 0, 0 }; unsigned maxTTSize[3] = { 0, 0, 0 }; - READ_FLAG(uiCode, "qtbt_dual_intra_tree"); pcSPS->setUseDualITree(uiCode); - READ_UVLC(uiCode, "log2_CTU_size_minus2"); pcSPS->setCTUSize(1 << (uiCode + 2)); + READ_FLAG(uiCode, "qtbtt_dual_tree_intra_flag"); pcSPS->setUseDualITree(uiCode); + READ_UVLC(uiCode, "log2_ctu_size_minus2"); pcSPS->setCTUSize(1 << (uiCode + 2)); pcSPS->setMaxCodingDepth(uiCode); pcSPS->setLog2DiffMaxMinCodingBlockSize(uiCode); pcSPS->setMaxCUWidth(pcSPS->getCTUSize()); @@ -972,33 +945,33 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_UVLC(uiCode, "log2_min_luma_coding_block_size_minus2"); int log2MinCUSize = uiCode + 2; pcSPS->setLog2MinCodingBlockSize(log2MinCUSize); - READ_FLAG(uiCode, "sps_override_partition_constraints_enable_flag"); pcSPS->setSplitConsOverrideEnabledFlag(uiCode); - READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_slice"); minQT[0] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); - READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_slice"); minQT[1] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); - READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_slices"); maxBTD[1] = uiCode; - READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_slices"); maxBTD[0] = uiCode; + READ_FLAG(uiCode, "partition_constraints_override_enabled_flag"); pcSPS->setSplitConsOverrideEnabledFlag(uiCode); + READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_luma"); minQT[0] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); + READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_tile_group"); minQT[1] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); + READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_tile_group"); maxBTD[1] = uiCode; + READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_luma"); maxBTD[0] = uiCode; maxTTSize[0] = maxBTSize[0] = minQT[0]; if (maxBTD[0] != 0) { - READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_slice"); maxBTSize[0] <<= uiCode; - READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_slice"); maxTTSize[0] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_luma"); maxBTSize[0] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_luma"); maxTTSize[0] <<= uiCode; } maxTTSize[1] = maxBTSize[1] = minQT[1]; if (maxBTD[1] != 0) { - READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_inter_slice"); maxBTSize[1] <<= uiCode; - READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_inter_slice"); maxTTSize[1] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_inter_tile_group"); maxBTSize[1] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_inter_tile_group"); maxTTSize[1] <<= uiCode; } if (pcSPS->getUseDualITree()) { - READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_slice_chroma"); minQT[2] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); - READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_slices_chroma"); maxBTD[2] = uiCode; + READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_chroma"); minQT[2] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize()); + READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_chroma"); maxBTD[2] = uiCode; maxTTSize[2] = maxBTSize[2] = minQT[2]; if (maxBTD[2] != 0) { - READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_slice_chroma"); maxBTSize[2] <<= uiCode; - READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_slice_chroma"); maxTTSize[2] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_chroma"); maxBTSize[2] <<= uiCode; + READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_chroma"); maxTTSize[2] <<= uiCode; } } @@ -1011,15 +984,16 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) { CHECK(log2MinCUSize + pcSPS->getLog2DiffMaxMinCodingBlockSize() < 5, "Invalid code"); } - READ_UVLC( uiCode, "log2_min_luma_transform_block_size_minus2" ); pcSPS->setQuadtreeTULog2MinSize( uiCode + 2 ); + // KJS: does not exist anymore -> remove! + READ_UVLC( uiCode, "log2_min_luma_transform_block_size_minus2" ); pcSPS->setQuadtreeTULog2MinSize( uiCode + 2 ); READ_UVLC( uiCode, "log2_diff_max_min_luma_transform_block_size" ); pcSPS->setQuadtreeTULog2MaxSize( uiCode + pcSPS->getQuadtreeTULog2MinSize() ); pcSPS->setMaxTrSize( 1<<(uiCode + pcSPS->getQuadtreeTULog2MinSize()) ); READ_FLAG( uiCode, "sps_sao_enabled_flag" ); pcSPS->setSAOEnabledFlag ( uiCode ? true : false ); READ_FLAG( uiCode, "sps_alf_enabled_flag" ); pcSPS->setALFEnabledFlag ( uiCode ? true : false ); - READ_FLAG( uiCode, "pcm_enabled_flag" ); pcSPS->setPCMEnabledFlag( uiCode ? true : false ); + READ_FLAG( uiCode, "sps_pcm_enabled_flag" ); pcSPS->setPCMEnabledFlag( uiCode ? true : false ); if( pcSPS->getPCMEnabledFlag() ) { READ_CODE( 4, uiCode, "pcm_sample_bit_depth_luma_minus1" ); pcSPS->setPCMBitDepth ( CHANNEL_TYPE_LUMA, 1 + uiCode ); @@ -1036,7 +1010,7 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) } READ_FLAG( uiCode, "sps_temporal_mvp_enabled_flag" ); pcSPS->setSPSTemporalMVPEnabledFlag(uiCode); - + if ( pcSPS->getSPSTemporalMVPEnabledFlag() ) { READ_FLAG( uiCode, "sps_sbtmvp_enabled_flag" ); pcSPS->setSBTMVPEnabledFlag ( uiCode != 0 ); @@ -1046,20 +1020,93 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) pcSPS->setSBTMVPEnabledFlag(false); } - READ_FLAG( uiCode, "sps_bdof_enable_flag" ); pcSPS->setBDOFEnabledFlag ( uiCode != 0 ); + READ_FLAG( uiCode, "sps_amvr_enabled_flag" ); pcSPS->setAMVREnabledFlag ( uiCode != 0 ); + + READ_FLAG( uiCode, "sps_bdof_enabled_flag" ); pcSPS->setBDOFEnabledFlag ( uiCode != 0 ); + +#if JVET_M0246_AFFINE_AMVR + READ_FLAG( uiCode, "sps_affine_amvr_enabled_flag" ); pcSPS->setAffineAmvrEnabledFlag ( uiCode != 0 ); +#endif + +#if JVET_M0147_DMVR + READ_FLAG(uiCode, "sps_dmvr_enable_flag"); pcSPS->setUseDMVR(uiCode != 0); +#endif + + // KJS: sps_cclm_enabled_flag + READ_FLAG( uiCode, "lm_chroma_enabled_flag" ); pcSPS->setUseLMChroma ( uiCode != 0 ); +#if JVET_M0142_CCLM_COLLOCATED_CHROMA + if ( pcSPS->getUseLMChroma() && pcSPS->getChromaFormatIdc() == CHROMA_420 ) + { + READ_FLAG( uiCode, "sps_cclm_collocated_chroma_flag" ); pcSPS->setCclmCollocatedChromaFlag( uiCode != 0 ); + } +#endif + +#if JVET_M0303_IMPLICIT_MTS + READ_FLAG( uiCode, "mts_enabled_flag" ); pcSPS->setUseMTS ( uiCode != 0 ); + if ( pcSPS->getUseMTS() ) + { +#endif +#if JVET_M0464_UNI_MTS + READ_FLAG( uiCode, "mts_intra_enabled_flag" ); pcSPS->setUseIntraMTS ( uiCode != 0 ); + READ_FLAG( uiCode, "mts_inter_enabled_flag" ); pcSPS->setUseInterMTS ( uiCode != 0 ); +#else + READ_FLAG( uiCode, "emt_intra_enabled_flag" ); pcSPS->setUseIntraEMT ( uiCode != 0 ); + READ_FLAG( uiCode, "emt_inter_enabled_flag" ); pcSPS->setUseInterEMT ( uiCode != 0 ); +#endif +#if JVET_M0303_IMPLICIT_MTS + } +#endif + // KJS: sps_affine_enabled_flag + READ_FLAG( uiCode, "affine_flag" ); pcSPS->setUseAffine ( uiCode != 0 ); + if ( pcSPS->getUseAffine() ) + { + READ_FLAG( uiCode, "affine_type_flag" ); pcSPS->setUseAffineType ( uiCode != 0 ); + } + READ_FLAG( uiCode, "gbi_flag" ); pcSPS->setUseGBi ( uiCode != 0 ); +#if JVET_M0483_IBC + READ_FLAG(uiCode, "ibc_flag"); pcSPS->setIBCFlag(uiCode); +#else + READ_FLAG( uiCode, "ibc_flag"); pcSPS->setIBCMode ( uiCode != 0 ); +#endif + // KJS: sps_ciip_enabled_flag + READ_FLAG( uiCode, "mhintra_flag" ); pcSPS->setUseMHIntra ( uiCode != 0 ); + + READ_FLAG( uiCode, "triangle_flag" ); pcSPS->setUseTriangle ( uiCode != 0 ); + + // KJS: not in draft yet +#if JVET_M0255_FRACMMVD_SWITCH + READ_FLAG( uiCode, "sps_fracmmvd_disabled_flag" ); pcSPS->setDisFracMmvdEnabledFlag ( uiCode != 0 ); +#endif + // KJS: not in draft yet +#if JVET_M0140_SBT + READ_FLAG(uiCode, "sbt_enable_flag"); pcSPS->setUseSBT(uiCode != 0); + if( pcSPS->getUseSBT() ) + { + READ_FLAG(uiCode, "max_sbt_size_64_flag"); pcSPS->setMaxSbtSize(uiCode != 0 ? 64 : 32); + } +#endif + // KJS: not in draft yet +#if JVET_M0427_INLOOP_RESHAPER + READ_FLAG(uiCode, "sps_reshaper_enable_flag"); pcSPS->setUseReshaper(uiCode == 1); +#endif -#if HEVC_USE_SCALING_LISTS - READ_FLAG( uiCode, "scaling_list_enabled_flag" ); pcSPS->setScalingListFlag ( uiCode ); - if(pcSPS->getScalingListFlag()) +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + READ_FLAG( uiCode, "sps_ladf_enabled_flag" ); pcSPS->setLadfEnabled( uiCode != 0 ); + if ( pcSPS->getLadfEnabled() ) { - READ_FLAG( uiCode, "sps_scaling_list_data_present_flag" ); pcSPS->setScalingListPresentFlag ( uiCode ); - if(pcSPS->getScalingListPresentFlag ()) + int signedSymbol = 0; + READ_CODE( 2, uiCode, "sps_num_ladf_intervals_minus2"); pcSPS->setLadfNumIntervals( uiCode + 2 ); + READ_SVLC(signedSymbol, "sps_ladf_lowest_interval_qp_offset" ); pcSPS->setLadfQpOffset( signedSymbol, 0 ); + for ( int k = 1; k < pcSPS->getLadfNumIntervals(); k++ ) { - parseScalingList( &(pcSPS->getScalingList()) ); + READ_SVLC(signedSymbol, "sps_ladf_qp_offset" ); pcSPS->setLadfQpOffset( signedSymbol, k ); + READ_UVLC( uiCode, "sps_ladf_delta_threshold_minus1"); + pcSPS->setLadfIntervalLowerBound(uiCode + pcSPS->getLadfIntervalLowerBound(k - 1) + 1, k); } } #endif - + + // KJS: reference picture sets to be replaced READ_UVLC( uiCode, "num_short_term_ref_pic_sets" ); CHECK(uiCode > 64, "Invalid code"); pcSPS->createRPSList(uiCode); @@ -1085,10 +1132,26 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) pcSPS->setUsedByCurrPicLtSPSFlag(k, uiCode?1:0); } } + + // KJS: not found in draft -> does not exist #if HEVC_USE_INTRA_SMOOTHING_T32 || HEVC_USE_INTRA_SMOOTHING_T64 READ_FLAG( uiCode, "strong_intra_smoothing_enable_flag" ); pcSPS->setUseStrongIntraSmoothing(uiCode); +#endif + // KJS: remove scaling lists? +#if HEVC_USE_SCALING_LISTS + READ_FLAG( uiCode, "scaling_list_enabled_flag" ); pcSPS->setScalingListFlag ( uiCode ); + if(pcSPS->getScalingListFlag()) + { + READ_FLAG( uiCode, "sps_scaling_list_data_present_flag" ); pcSPS->setScalingListPresentFlag ( uiCode ); + if(pcSPS->getScalingListPresentFlag ()) + { + parseScalingList( &(pcSPS->getScalingList()) ); + } + } #endif + + // KJS: no VUI defined yet READ_FLAG( uiCode, "vui_parameters_present_flag" ); pcSPS->setVuiParametersPresentFlag(uiCode); if (pcSPS->getVuiParametersPresentFlag()) @@ -1096,7 +1159,7 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) parseVUI(pcSPS->getVuiParameters(), pcSPS); } - + // KJS: no SPS extensions defined yet READ_FLAG( uiCode, "sps_extension_present_flag"); if (uiCode) @@ -1119,11 +1182,6 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) sps_extension_flags[i] = uiCode!=0; } - if( pcSPS->getPTL()->getGeneralPTL()->getProfileIdc() == Profile::NEXT ) - { - pcSPS->getSpsNext().setNextToolsEnabled( true ); - } - bool bSkipTrailingExtensionBits=false; for(int i=0; i<NUM_SPS_EXTENSION_FLAGS; i++) // loop used so that the order is determined by the enum. { @@ -1146,12 +1204,6 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_FLAG( uiCode, "cabac_bypass_alignment_enabled_flag"); spsRangeExtension.setCabacBypassAlignmentEnabledFlag (uiCode != 0); } break; - case SPS_EXT__NEXT: - { - CHECK( !pcSPS->getSpsNext().nextToolsEnabled(), "Got SPS Next extension in non NEXT profile" ); - parseSPSNext( pcSPS->getSpsNext(), pcSPS->getPCMEnabledFlag() ); - break; - } default: bSkipTrailingExtensionBits=true; break; @@ -1166,7 +1218,6 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) } } } - xReadRbspTrailingBits(); } @@ -1748,25 +1799,43 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para } } } + +#if JVET_M0483_IBC + if (!pcSlice->isIntra() || sps->getIBCFlag()) + { + READ_UVLC(uiCode, "six_minus_max_num_merge_cand"); + pcSlice->setMaxNumMergeCand(MRG_MAX_NUM_CANDS - uiCode); + } +#endif + if (!pcSlice->isIntra()) { +#if JVET_M0483_IBC==0 READ_UVLC(uiCode, "six_minus_max_num_merge_cand"); pcSlice->setMaxNumMergeCand(MRG_MAX_NUM_CANDS - uiCode); +#endif - if ( sps->getSBTMVPEnabledFlag() && !sps->getSpsNext().getUseAffine() ) // ATMVP only + if ( sps->getSBTMVPEnabledFlag() && !sps->getUseAffine() ) // ATMVP only { pcSlice->setMaxNumAffineMergeCand( 1 ); } - else if ( !sps->getSBTMVPEnabledFlag() && !sps->getSpsNext().getUseAffine() ) // both off + else if ( !sps->getSBTMVPEnabledFlag() && !sps->getUseAffine() ) // both off { pcSlice->setMaxNumAffineMergeCand( 0 ); } else - if ( sps->getSpsNext().getUseAffine() ) + if ( sps->getUseAffine() ) { READ_UVLC( uiCode, "five_minus_max_num_affine_merge_cand" ); pcSlice->setMaxNumAffineMergeCand( AFFINE_MRG_MAX_NUM_CANDS - uiCode ); } +#if JVET_M0255_FRACMMVD_SWITCH + if ( sps->getDisFracMmvdEnabledFlag() ) + { + READ_FLAG( uiCode, "tile_group_fracmmvd_disabled_flag" ); + pcSlice->setDisFracMMVD( uiCode ? true : false ); + } +#endif } READ_SVLC( iCode, "slice_qp_delta" ); @@ -1857,6 +1926,13 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para uiCode = pps->getLoopFilterAcrossSlicesEnabledFlag()?1:0; } pcSlice->setLFCrossSliceBoundaryFlag( (uiCode==1)?true:false); + +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + parseReshaper(pcSlice->getReshapeInfo(), sps, pcSlice->isIntra()); + } +#endif #if HEVC_DEPENDENT_SLICES } #endif @@ -2335,7 +2411,7 @@ bool HLSyntaxReader::xMoreRbspData() void HLSyntaxReader::alf( AlfSliceParam& alfSliceParam ) { uint32_t code; - READ_FLAG( code, "alf_slice_enable_flag" ); + READ_FLAG( code, "tile_group_alf_enabled_flag" ); alfSliceParam.enabledFlag[COMPONENT_Y] = code ? true : false; if( !code ) @@ -2420,33 +2496,33 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom uint32_t code; if( !isChroma ) { - READ_FLAG( code, "alf_coefficients_delta_flag" ); - alfSliceParam.coeffDeltaFlag = code; + READ_FLAG( code, "alf_luma_coeff_delta_flag" ); + alfSliceParam.alfLumaCoeffDeltaFlag = code; - if( !alfSliceParam.coeffDeltaFlag ) + if( !alfSliceParam.alfLumaCoeffDeltaFlag ) { - std::memset( alfSliceParam.filterCoeffFlag, true, sizeof( alfSliceParam.filterCoeffFlag ) ); + std::memset( alfSliceParam.alfLumaCoeffFlag, true, sizeof( alfSliceParam.alfLumaCoeffFlag ) ); if( alfSliceParam.numLumaFilters > 1 ) { - READ_FLAG( code, "coeff_delta_pred_mode_flag" ); - alfSliceParam.coeffDeltaPredModeFlag = code; + READ_FLAG( code, "alf_luma_coeff_delta_prediction_flag" ); + alfSliceParam.alfLumaCoeffDeltaPredictionFlag = code; } else { - alfSliceParam.coeffDeltaPredModeFlag = 0; + alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; } } else { - alfSliceParam.coeffDeltaPredModeFlag = 0; + alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; } } // derive maxGolombIdx AlfFilterShape alfShape( isChroma ? 5 : 7 ); const int maxGolombIdx = AdaptiveLoopFilter::getMaxGolombIdx( alfShape.filterType ); - READ_UVLC( code, "min_golomb_order" ); + READ_UVLC( code, isChroma ? "alf_chroma_min_eg_order_minus1" : "alf_luma_min_eg_order_minus1" ); int kMin = code + 1; static int kMinTab[MAX_NUM_ALF_COEFF]; @@ -2455,7 +2531,7 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom for( int idx = 0; idx < maxGolombIdx; idx++ ) { - READ_FLAG( code, "golomb_order_increase_flag" ); + READ_FLAG( code, isChroma ? "alf_chroma_eg_order_increase_flag" : "alf_luma_eg_order_increase_flag" ); CHECK( code > 1, "Wrong golomb_order_increase_flag" ); kMinTab[idx] = kMin + code; kMin = kMinTab[idx]; @@ -2463,12 +2539,12 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom if( !isChroma ) { - if( alfSliceParam.coeffDeltaFlag ) + if( alfSliceParam.alfLumaCoeffDeltaFlag ) { for( int ind = 0; ind < alfSliceParam.numLumaFilters; ++ind ) { - READ_FLAG( code, "filter_coefficient_flag[i]" ); - alfSliceParam.filterCoeffFlag[ind] = code; + READ_FLAG( code, "alf_luma_coeff_flag[i]" ); + alfSliceParam.alfLumaCoeffFlag[ind] = code; } } } @@ -2476,7 +2552,7 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.filterCoeffFlag[ind] && alfSliceParam.coeffDeltaFlag ) + if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) { memset( coeff + ind * MAX_NUM_ALF_LUMA_COEFF, 0, sizeof( *coeff ) * alfShape.numCoeff ); continue; diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index 56fc8eb43e5f0d8f2c56c0827c142b7de11a0ef9..b8fa2d66a90a105247e1f3e3cc17bfe53e499de4 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -147,7 +147,6 @@ public: #if HEVC_VPS void parseVPS ( VPS* pcVPS ); #endif - void parseSPSNext ( SPSNext& spsNext, const bool usePCM ); void parseSPS ( SPS* pcSPS ); void parsePPS ( PPS* pcPPS ); void parseVUI ( VUI* pcVUI, SPS* pcSPS ); @@ -163,7 +162,9 @@ public: void parseScalingList ( ScalingList* scalingList ); void decodeScalingList ( ScalingList *scalingList, uint32_t sizeId, uint32_t listId); #endif - +#if JVET_M0427_INLOOP_RESHAPER + void parseReshaper ( SliceReshapeInfo& sliceReshaperInfo, const SPS* pcSPS, const bool isIntra ); +#endif void alf( AlfSliceParam& alfSliceParam ); void alfFilter( AlfSliceParam& alfSliceParam, const bool isChroma ); diff --git a/source/Lib/EncoderLib/BinEncoder.cpp b/source/Lib/EncoderLib/BinEncoder.cpp index c67efa03fc38b80a5da45fd2755993c137c9096f..b80f248043c025257609c5e20cd200f323859972 100644 --- a/source/Lib/EncoderLib/BinEncoder.cpp +++ b/source/Lib/EncoderLib/BinEncoder.cpp @@ -207,7 +207,12 @@ void BinEncoderBase::encodeBinsEP( unsigned bins, unsigned numBins ) void BinEncoderBase::encodeRemAbsEP( unsigned bins, unsigned goRicePar, bool useLimitedPrefixLength, int maxLog2TrDynamicRange ) { - const unsigned threshold = g_auiGoRiceRange[ goRicePar ] << goRicePar; +#if JVET_M0470 + const unsigned threshold = COEF_REMAIN_BIN_REDUCTION << goRicePar; + useLimitedPrefixLength = true; +#else + const unsigned threshold = g_auiGoRiceRange[goRicePar] << goRicePar; +#endif if( bins < threshold ) { const unsigned bitMask = ( 1 << goRicePar ) - 1; @@ -251,7 +256,11 @@ void BinEncoderBase::encodeRemAbsEP( unsigned bins, unsigned goRicePar, bool use bins -= delta; delta = 1 << (++length); } +#if JVET_M0470 + unsigned numBin = COEF_REMAIN_BIN_REDUCTION + length + 1 - goRicePar; +#else unsigned numBin = g_auiGoRiceRange[ goRicePar ] + length + 1 - goRicePar; +#endif encodeBinsEP( ( 1 << numBin ) - 2, numBin ); encodeBinsEP( bins, length ); } @@ -438,7 +447,12 @@ BitEstimatorBase::BitEstimatorBase( const BinProbModel* dummy ) void BitEstimatorBase::encodeRemAbsEP( unsigned bins, unsigned goRicePar, bool useLimitedPrefixLength, int maxLog2TrDynamicRange ) { - const unsigned threshold = g_auiGoRiceRange[ goRicePar ] << goRicePar; +#if JVET_M0470 + const unsigned threshold = COEF_REMAIN_BIN_REDUCTION << goRicePar; + useLimitedPrefixLength = true; +#else + const unsigned threshold = g_auiGoRiceRange[goRicePar] << goRicePar; +#endif if( bins < threshold ) { m_EstFracBits += BinProbModelBase::estFracBitsEP( ( bins >> goRicePar ) + 1 + goRicePar ); @@ -474,7 +488,11 @@ void BitEstimatorBase::encodeRemAbsEP( unsigned bins, unsigned goRicePar, bool u bins -= delta; delta = 1 << (++length); } +#if JVET_M0470 + m_EstFracBits += BinProbModelBase::estFracBitsEP(COEF_REMAIN_BIN_REDUCTION + 1 + (length << 1) - goRicePar); +#else m_EstFracBits += BinProbModelBase::estFracBitsEP( g_auiGoRiceRange[ goRicePar ] + 1 + ( length << 1 ) - goRicePar ); +#endif } } diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index a9795b6dbf2e120a85cfced81944161f270c5930..372cf7ae57367f2f3e144c0b45fbe449962414b7 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -544,7 +544,7 @@ void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& c unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12; DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl ); - + const bool canSplit = canBh || canBv || canTh || canTv || canQt; const bool isNo = split == CU_DONT_SPLIT; @@ -713,7 +713,11 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C } // skip flag +#if JVET_M0483_IBC + if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && cu.Y().valid()) +#else if (!cs.slice->isIntra() && cu.Y().valid()) +#endif { cu_skip_flag( cu ); } @@ -745,6 +749,9 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C extend_ref_line(cu); +#if JVET_M0102_INTRA_SUBPARTITIONS + isp_mode( cu ); +#endif // prediction data ( intra prediction modes / reference indexes + motion vectors ) cu_pred_data( cu ); @@ -766,19 +773,86 @@ void CABACWriter::cu_transquant_bypass_flag( const CodingUnit& cu ) void CABACWriter::cu_skip_flag( const CodingUnit& cu ) { unsigned ctxId = DeriveCtx::CtxSkipFlag( cu ); + +#if JVET_M0483_IBC + if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag()) + { + m_BinEncoder.encodeBin((cu.skip), Ctx::SkipFlag(ctxId)); + DTRACE(g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0); + return; + } +#endif + m_BinEncoder.encodeBin( ( cu.skip ), Ctx::SkipFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 ); +#if JVET_M0483_IBC + if (cu.skip && cu.cs->slice->getSPS()->getIBCFlag()) + { + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + m_BinEncoder.encodeBin(CU::isIBC(cu) ? 1 : 0, Ctx::IBCFlag(ctxidx)); + DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode); + + if (CU::isInter(cu)) + { + m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0)); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0); + } + } + if (cu.skip && !cu.cs->slice->getSPS()->getIBCFlag()) + { + m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0)); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0); + } +#else if (cu.skip) { m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0)); DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0); } +#endif } void CABACWriter::pred_mode( const CodingUnit& cu ) { +#if JVET_M0483_IBC + if (cu.cs->slice->getSPS()->getIBCFlag()) + { +#endif +#if JVET_M0483_IBC + if (cu.cs->slice->isIntra()) + { + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx)); + } + else + { +#if JVET_M0502_PRED_MODE_CTX + m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))); +#else + m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode()); +#endif + if (!CU::isIntra(cu)) + { + unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu); + m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx)); + } + } + } + else + { + if (cu.cs->slice->isIntra()) + { + return; + } +#if JVET_M0502_PRED_MODE_CTX + m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))); +#else + m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode()); +#endif + } +#else if( cu.cs->slice->isIntra() ) { return; @@ -788,6 +862,7 @@ void CABACWriter::pred_mode( const CodingUnit& cu ) #else m_BinEncoder.encodeBin( ( CU::isIntra( cu ) ), Ctx::PredMode() ); #endif +#endif } void CABACWriter::pcm_data( const CodingUnit& cu, Partitioner& partitioner ) @@ -803,7 +878,7 @@ void CABACWriter::pcm_data( const CodingUnit& cu, Partitioner& partitioner ) void CABACWriter::pcm_flag( const CodingUnit& cu, Partitioner& partitioner ) { const SPS& sps = *cu.cs->sps; - if( !sps.getPCMEnabledFlag() || partitioner.currArea().lwidth() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lwidth() < (1 << sps.getPCMLog2MinSize()) + if( !sps.getPCMEnabledFlag() || partitioner.currArea().lwidth() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lwidth() < (1 << sps.getPCMLog2MinSize()) || partitioner.currArea().lheight() > (1 << sps.getPCMLog2MaxSize()) || partitioner.currArea().lheight() < (1 << sps.getPCMLog2MinSize()) ) { return; @@ -830,6 +905,9 @@ void CABACWriter::cu_pred_data( const CodingUnit& cu ) } imv_mode ( cu ); +#if JVET_M0246_AFFINE_AMVR + affine_amvr_mode( cu ); +#endif cu_gbi_flag( cu ); @@ -918,6 +996,10 @@ void CABACWriter::xWriteTruncBinCode(uint32_t symbol, uint32_t maxSymbol) void CABACWriter::extend_ref_line(const PredictionUnit& pu) { +#if !ENABLE_JVET_L0283_MRL + return; +#endif + const CodingUnit& cu = *pu.cu; if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) { @@ -945,6 +1027,10 @@ void CABACWriter::extend_ref_line(const PredictionUnit& pu) void CABACWriter::extend_ref_line(const CodingUnit& cu) { +#if !ENABLE_JVET_L0283_MRL + return; +#endif + if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) { return; @@ -1012,12 +1098,18 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) break; } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#else if (pu->multiRefIdx) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } else - m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() ); + { + m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag()); + } pu = pu->next; } @@ -1083,7 +1175,7 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) // prev_intra_luma_pred_flag const int numMPMs = NUM_MOST_PROBABLE_MODES; unsigned mpm_pred[numMPMs]; - + PU::getIntraMPMs( pu, mpm_pred ); unsigned ipred_mode = pu.intraDir[0]; @@ -1097,12 +1189,18 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) break; } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) ) +#else if (pu.multiRefIdx) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } else - m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() ); + { + m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::IntraLumaMpmFlag()); + } // mpm_idx / rem_intra_luma_pred_mode if( mpm_idx < numMPMs ) @@ -1172,24 +1270,24 @@ void CABACWriter::intra_chroma_lmc_mode( const PredictionUnit& pu ) } CHECK( symbol < 0, "invalid symbol found" ); - unary_max_symbol( symbol, Ctx::IPredMode[1]( 2 ), Ctx::IPredMode[1]( 3 ), maxSymbol - 1 ); + unary_max_symbol(symbol, Ctx::IntraChromaPredMode(1), Ctx::IntraChromaPredMode(2), maxSymbol - 1); } void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu ) { const unsigned intraDir = pu.intraDir[1]; + const bool isDerivedMode = intraDir == DM_CHROMA_IDX; + + m_BinEncoder.encodeBin(isDerivedMode ? 0 : 1, Ctx::IntraChromaPredMode(0)); + + if (isDerivedMode) { - if( intraDir == DM_CHROMA_IDX ) - { - m_BinEncoder.encodeBin( 0, Ctx::IPredMode[1]( 1 ) ); - return; - } - m_BinEncoder.encodeBin( 1, Ctx::IPredMode[1]( 1 ) ); + return; } // LM chroma mode - if( pu.cs->sps->getSpsNext().getUseLMChroma() ) + if( pu.cs->sps->getUseLMChroma() ) { intra_chroma_lmc_mode( pu ); if ( PU::isLMCMode( intraDir ) ) @@ -1221,13 +1319,23 @@ void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu ) void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx ) { +#if JVET_M0483_IBC + if (!CU::isIntra(cu)) +#else if( CU::isInter( cu ) ) +#endif { PredictionUnit& pu = *cu.firstPU; if( !pu.mergeFlag ) { rqt_root_cbf( cu ); } +#if JVET_M0140_SBT + if( cu.rootCbf ) + { + sbt_mode( cu ); + } +#endif if( !cu.rootCbf ) { @@ -1237,7 +1345,19 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C ChromaCbfs chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && isLuma( partitioner.chType ) ) + { + TUIntraSubPartitioner subTuPartitioner( partitioner ); + transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 ); + } + else + { + transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); + } +#else transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); +#endif } void CABACWriter::rqt_root_cbf( const CodingUnit& cu ) @@ -1247,6 +1367,64 @@ void CABACWriter::rqt_root_cbf( const CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "rqt_root_cbf() ctx=0 root_cbf=%d pos=(%d,%d)\n", cu.rootCbf ? 1 : 0, cu.lumaPos().x, cu.lumaPos().y ); } +#if JVET_M0140_SBT +void CABACWriter::sbt_mode( const CodingUnit& cu ) +{ + uint8_t sbtAllowed = cu.checkAllowedSbt(); + if( !sbtAllowed ) + { + return; + } + + SizeType cuWidth = cu.lwidth(); + SizeType cuHeight = cu.lheight(); + uint8_t sbtIdx = cu.getSbtIdx(); + uint8_t sbtPos = cu.getSbtPos(); + + //bin - flag + bool sbtFlag = cu.sbtInfo != 0; + uint8_t ctxIdx = ( cuWidth * cuHeight <= 256 ) ? 1 : 0; + m_BinEncoder.encodeBin( sbtFlag, Ctx::SbtFlag( ctxIdx ) ); + if( !sbtFlag ) + { + return; + } + + bool sbtQuadFlag = sbtIdx == SBT_HOR_QUAD || sbtIdx == SBT_VER_QUAD; + bool sbtHorFlag = sbtIdx == SBT_HOR_HALF || sbtIdx == SBT_HOR_QUAD; + bool sbtPosFlag = sbtPos == SBT_POS1; + + uint8_t sbtVerHalfAllow = CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed ); + uint8_t sbtHorHalfAllow = CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed ); + uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ); + uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ); + //bin - type + if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) ) + { + m_BinEncoder.encodeBin( sbtQuadFlag, Ctx::SbtQuadFlag( 0 ) ); + } + else + { + assert( sbtQuadFlag == 0 ); + } + + //bin - dir + if( ( sbtQuadFlag && sbtVerQuadAllow && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtVerHalfAllow && sbtHorHalfAllow ) ) //both direction allowed + { + uint8_t ctxIdx = ( cuWidth == cuHeight ) ? 0 : ( cuWidth < cuHeight ? 1 : 2 ); + m_BinEncoder.encodeBin( sbtHorFlag, Ctx::SbtHorFlag( ctxIdx ) ); + } + else + { + assert( sbtHorFlag == ( ( sbtQuadFlag && sbtHorQuadAllow ) || ( !sbtQuadFlag && sbtHorHalfAllow ) ) ); + } + + //bin - pos + m_BinEncoder.encodeBin( sbtPosFlag, Ctx::SbtPosFlag( 0 ) ); + + DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo ); +} +#endif void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) { @@ -1310,6 +1488,13 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) } if( pu.mergeFlag ) { +#if JVET_M0483_IBC + if (CU::isIBC(*pu.cu)) + { + merge_idx(pu); + return; + } +#endif subblock_merge_flag( *pu.cu ); MHIntra_flag( pu ); if ( pu.mhIntraFlag ) @@ -1324,8 +1509,19 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) else merge_idx ( pu ); } +#if JVET_M0483_IBC + else if (CU::isIBC(*pu.cu)) + { + ref_idx(pu, REF_PIC_LIST_0); + mvd_coding(pu.mvd[REF_PIC_LIST_0], pu.cu->imv); + mvp_flag(pu, REF_PIC_LIST_0); + } +#endif else { +#if JVET_M0246_AFFINE_AMVR + int8_t affineMvdShift = pu.cu->imv ? ( pu.cu->imv == 1 ? -1 : 1 ) : 0; +#endif inter_pred_idc( pu ); affine_flag ( *pu.cu ); #if JVET_M0444_SMVD @@ -1336,12 +1532,21 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) ref_idx ( pu, REF_PIC_LIST_0 ); if ( pu.cu->affine ) { +#if JVET_M0246_AFFINE_AMVR + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][0], affineMvdShift ); + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][1], affineMvdShift ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][2], affineMvdShift ); + } +#else mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][0], 0); mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][1], 0); if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][2], 0); } +#endif } else { @@ -1360,12 +1565,21 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) { if ( pu.cu->affine ) { +#if JVET_M0246_AFFINE_AMVR + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][0], affineMvdShift ); + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][1], affineMvdShift ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][2], affineMvdShift ); + } +#else mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][0], 0); mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][1], 0); if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][2], 0); } +#endif } else { @@ -1406,7 +1620,7 @@ void CABACWriter::subblock_merge_flag( const CodingUnit& cu ) return; } - if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getSpsNext().getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 ) + if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 ) { unsigned ctxId = DeriveCtx::CtxAffineFlag( cu ); m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) ); @@ -1416,13 +1630,13 @@ void CABACWriter::subblock_merge_flag( const CodingUnit& cu ) void CABACWriter::affine_flag( const CodingUnit& cu ) { - if ( !cu.cs->slice->isIntra() && cu.cs->sps->getSpsNext().getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 ) + if ( !cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 ) { unsigned ctxId = DeriveCtx::CtxAffineFlag( cu ); m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "affine_flag() affine=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y ); - if ( cu.affine && cu.cs->sps->getSpsNext().getUseAffineType() ) + if ( cu.affine && cu.cs->sps->getUseAffineType() ) { unsigned ctxId = 0; m_BinEncoder.encodeBin( cu.affineType, Ctx::AffineType( ctxId ) ); @@ -1436,6 +1650,14 @@ void CABACWriter::merge_flag( const PredictionUnit& pu ) m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() ); DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height ); + +#if JVET_M0483_IBC + if (pu.mergeFlag && CU::isIBC(*pu.cu)) + { + return; + } +#endif + if (pu.mergeFlag) { m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0)); @@ -1445,12 +1667,18 @@ void CABACWriter::merge_flag( const PredictionUnit& pu ) void CABACWriter::imv_mode( const CodingUnit& cu ) { - const SPSNext& spsNext = cu.cs->sps->getSpsNext(); + const SPS *sps = cu.cs->sps; - if( !spsNext.getUseIMV() ) + if( !sps->getAMVREnabledFlag() ) { return; } +#if JVET_M0246_AFFINE_AMVR + if ( cu.affine ) + { + return; + } +#endif bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu ); if( !bNonZeroMvd ) @@ -1459,11 +1687,15 @@ void CABACWriter::imv_mode( const CodingUnit& cu ) } unsigned ctxId = DeriveCtx::CtxIMVFlag( cu ); +#if JVET_M0483_IBC + if (CU::isIBC(cu) == false) +#else if (!(cu.firstPU->interDir == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, cu.firstPU->refIdx[REF_PIC_LIST_0])->getPOC() == cu.cs->slice->getPOC())) // the first bin of IMV flag does need to be signaled in IBC block +#endif m_BinEncoder.encodeBin( ( cu.imv > 0 ), Ctx::ImvFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), ctxId ); - if( spsNext.getImvMode() == IMV_4PEL && cu.imv > 0 ) + if( sps->getAMVREnabledFlag() && cu.imv > 0 ) { m_BinEncoder.encodeBin( ( cu.imv > 1 ), Ctx::ImvFlag( 3 ) ); DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", ( cu.imv > 1 ), 3 ); @@ -1472,6 +1704,33 @@ void CABACWriter::imv_mode( const CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv ); } +#if JVET_M0246_AFFINE_AMVR +void CABACWriter::affine_amvr_mode( const CodingUnit& cu ) +{ + const SPS* sps = cu.slice->getSPS(); + + if( !sps->getAffineAmvrEnabledFlag() || !cu.affine ) + { + return; + } + + if ( !CU::hasSubCUNonZeroAffineMVd( cu ) ) + { + return; + } + + m_BinEncoder.encodeBin( ( cu.imv > 0 ), Ctx::ImvFlag( 4 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 0 ), 4 ); + + if( cu.imv > 0 ) + { + m_BinEncoder.encodeBin( ( cu.imv > 1 ), Ctx::ImvFlag( 5 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 1 ), 5 ); + } + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv ); +} +#endif + void CABACWriter::merge_idx( const PredictionUnit& pu ) { @@ -1488,18 +1747,24 @@ void CABACWriter::merge_idx( const PredictionUnit& pu ) } else { +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX bool useExtCtx = pu.cs->sps->getSBTMVPEnabledFlag(); +#endif m_BinEncoder.encodeBin( 1, Ctx::AffMergeIdx() ); for ( unsigned idx = 1; idx < numCandminus1; idx++ ) { +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX if ( useExtCtx ) { m_BinEncoder.encodeBin( pu.mergeIdx == idx ? 0 : 1, Ctx::AffMergeIdx( std::min<int>( idx, NUM_MERGE_IDX_EXT_CTX - 1 ) ) ); } else { +#endif m_BinEncoder.encodeBinEP( pu.mergeIdx == idx ? 0 : 1 ); +#if !JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX } +#endif if ( pu.mergeIdx == idx ) { break; @@ -1513,6 +1778,38 @@ void CABACWriter::merge_idx( const PredictionUnit& pu ) { if( pu.cu->triangle ) { +#if JVET_M0883_TRIANGLE_SIGNALING + bool splitDir = pu.triangleSplitDir; + uint8_t candIdx0 = pu.triangleMergeIdx0; + uint8_t candIdx1 = pu.triangleMergeIdx1; + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_split_dir=%d\n", splitDir ); + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx0=%d\n", candIdx0 ); + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx1=%d\n", candIdx1 ); + candIdx1 -= candIdx1 < candIdx0 ? 0 : 1; + auto encodeOneIdx = [this](uint8_t mrgIdx, int numCandminus1) + { + if(mrgIdx == 0) + { + this->m_BinEncoder.encodeBin( 0, Ctx::MergeIdx() ); + return; + } + else + { + this->m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() ); + for( unsigned idx = 1; idx < numCandminus1; idx++ ) + { + this->m_BinEncoder.encodeBinEP( mrgIdx == idx ? 0 : 1 ); + if( mrgIdx == idx ) + { + break; + } + } + } + }; + m_BinEncoder.encodeBinEP(splitDir); + encodeOneIdx(candIdx0, TRIANGLE_MAX_NUM_UNI_CANDS - 1); + encodeOneIdx(candIdx1, TRIANGLE_MAX_NUM_UNI_CANDS - 2); +#else if( pu.mergeIdx < 2 ) { m_BinEncoder.encodeBin( 0, Ctx::TriangleIdx() ); @@ -1525,6 +1822,7 @@ void CABACWriter::merge_idx( const PredictionUnit& pu ) } DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx=%d\n", pu.mergeIdx ); +#endif return; } int numCandminus1 = int( pu.cs->slice->getMaxNumMergeCand() ) - 1; @@ -1645,6 +1943,15 @@ void CABACWriter::ref_idx( const PredictionUnit& pu, RefPicList eRefList ) #endif int numRef = pu.cs->slice->getNumRefIdx(eRefList); + +#if JVET_M0483_IBC + if (eRefList == REF_PIC_LIST_0 && pu.cs->sps->getIBCFlag()) + { + if (CU::isIBC(*pu.cu)) + return; + } +#endif + if( numRef <= 1 ) { return; @@ -1686,7 +1993,7 @@ void CABACWriter::mvp_flag( const PredictionUnit& pu, RefPicList eRefList ) void CABACWriter::MHIntra_flag(const PredictionUnit& pu) { - if (!pu.cs->sps->getSpsNext().getUseMHIntra()) + if (!pu.cs->sps->getUseMHIntra()) { CHECK(pu.mhIntraFlag == true, "invalid MHIntra SPS"); return; @@ -1777,7 +2084,7 @@ void CABACWriter::MHIntra_luma_pred_modes(const CodingUnit& cu) void CABACWriter::triangle_mode( const CodingUnit& cu ) { - if( !cu.cs->slice->getSPS()->getSpsNext().getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) + if( !cu.cs->slice->getSPS()->getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) { return; } @@ -1843,29 +2150,92 @@ void CABACWriter::pcm_samples( const TransformUnit& tu ) // bool cbf_comp ( cbf, area, depth ) //================================================================================ +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx ) +#else void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ) +#endif { +#if JVET_M0140_SBT + ChromaCbfs chromaCbfsLastDepth; + chromaCbfsLastDepth.Cb = chromaCbfs.Cb; + chromaCbfsLastDepth.Cr = chromaCbfs.Cr; +#endif const UnitArea& area = partitioner.currArea(); +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; + const TransformUnit& tu = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType, subTuIdx ); +#else const TransformUnit& tu = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType ); +#endif const CodingUnit& cu = *tu.cu; const unsigned trDepth = partitioner.currTrDepth; const bool split = ( tu.depth > trDepth ); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split; +#endif // split_transform_flag if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { CHECK( !split, "transform split implied" ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + CHECK( !split, "transform split implied - sbt" ); + } +#endif else +#if JVET_M0102_INTRA_SUBPARTITIONS + CHECK( split && !cu.ispMode, "transform split not allowed with QTBT" ); +#else CHECK( split, "transform split not allowed with QTBT" ); +#endif + // cbf_cb & cbf_cr +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) ) +#endif { { +#if JVET_M0102_INTRA_SUBPARTITIONS + unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; + if( trDepth == 0 || chromaCbfs.Cb || chromaCbfISP ) + { + chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && trDepth == 1 ) ) +#endif + cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth ); + } + else + { + CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, cbfDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" ); + } + + if( trDepth == 0 || chromaCbfs.Cr || chromaCbfISP ) + { + chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && trDepth == 1 ) ) +#endif + cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb ); + } + else + { + CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, cbfDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" ); + } +#else if( trDepth == 0 || chromaCbfs.Cb ) { chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && trDepth == 1 ) ) +#endif cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], trDepth ); } else @@ -1876,12 +2246,16 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit if( trDepth == 0 || chromaCbfs.Cr ) { chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && trDepth == 1 ) ) +#endif cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb ); } else { CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" ); } +#endif } } else if( CS::isDualITree( cs ) ) @@ -1897,7 +2271,11 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); } #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( trDepth == 0 && !cu.ispMode ) emt_cu_flag( cu ); +#else if( trDepth == 0 ) emt_cu_flag( cu ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -1909,13 +2287,30 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit #endif partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); + } +#endif else THROW( "Implicit TU split not available" ); do { ChromaCbfs subChromaCbfs = chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + transform_tree( cs, partitioner, cuCtx, subChromaCbfs, ispType, subTuCounter ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else transform_tree( cs, partitioner, cuCtx, subChromaCbfs ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -1930,9 +2325,51 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit { CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be true for inter units with no chroma coeffs" ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && tu.noResidual ) + { + CHECK( TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be false for inter sbt no-residual tu" ); + } + else if( cu.sbtInfo && !chromaCbfsLastDepth.sigChroma( area.chromaFormat ) ) + { + assert( !tu.noResidual ); + CHECK( !TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), "Luma cbf must be true for inter sbt residual tu" ); + } +#endif else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool rootCbfSoFar = false; + bool lastCbfIsInferred = false; + if( cu.ispMode ) + { + uint32_t nTus = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[tu.lheight()] : cu.lwidth() >> g_aucLog2[tu.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = cu.firstTU; + for( int tuIdx = 0; tuIdx < subTuCounter; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, trDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( tu, COMPONENT_Y, partitioner.currTrDepth ); + } + } + if( !lastCbfIsInferred ) + { + cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth, previousCbf, cu.ispMode ); + } +#else cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth ); +#endif } } @@ -1944,9 +2381,15 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf, const bool useISP ) +{ + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, useISP && isLuma(area.compID) ); +#else void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf ) { const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf ); +#endif const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) ); @@ -1962,12 +2405,19 @@ void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& //-------------------------------------------------------------------------------- // void mvd_coding( pu, refList ) //================================================================================ - +#if JVET_M0246_AFFINE_AMVR +void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv ) +#else void CABACWriter::mvd_coding( const Mv &rMvd, uint8_t imv ) +#endif { int horMvd = rMvd.getHor(); int verMvd = rMvd.getVer(); +#if JVET_M0246_AFFINE_AMVR + if ( imv > 0 ) +#else if( imv ) +#endif { CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" ); horMvd >>= 2; @@ -2035,7 +2485,11 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC bool cbfLuma = ( cbf[ COMPONENT_Y ] != 0 ); bool cbfChroma = false; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !lumaOnly ) +#else if( cu.chromaFormat != CHROMA_400 ) +#endif { if( tu.blocks[COMPONENT_Cb].valid() ) { @@ -2195,19 +2649,48 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) cctx.setScanPosLast(scanPosLast); // code last coeff position +#if JVET_M0297_32PT_MTS_ZERO_OUT + last_sig_coeff( cctx, tu, compID ); +#else last_sig_coeff( cctx ); +#endif // code subblocks const int stateTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 ); int state = 0; #if !JVET_M0464_UNI_MTS - bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); + bool useEmt = ( cu.cs->sps->getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + useEmt = useEmt && !cu.ispMode; +#endif #endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId, sigGroupFlags[subSetId] ); +#if JVET_M0297_32PT_MTS_ZERO_OUT +#if JVET_M0140_SBT +#if JVET_M0464_UNI_MTS + if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#else +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#endif + { + if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) ) + || ( tu.blocks[ compID ].width == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth() ) ) ) + { + continue; + } + } +#endif residual_coding_subblock( cctx, coeff, stateTab, state ); #if !JVET_M0464_UNI_MTS @@ -2284,7 +2767,11 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) #else void CABACWriter::transform_skip_flag( const TransformUnit& tu, ComponentID compID ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag(*tu.cs, tu.blocks[compID]) || (isLuma(compID) && tu.cu->emtFlag) || (tu.cu->ispMode && isLuma(compID))) +#else if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) ) +#endif { return; } @@ -2317,9 +2804,19 @@ void CABACWriter::emt_tu_index( const TransformUnit& tu ) //void CABACWriter::emt_cu_flag(const CodingUnit& cu, uint32_t depth, bool codeCuFlag, const int tuWidth,const int tuHeight) void CABACWriter::emt_cu_flag( const CodingUnit& cu ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( CU::isIntra( cu ) && cu.ispMode ) + { + return; + } +#endif const CodingStructure& cs = *cu.cs; - if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) +#if JVET_M0483_IBC + if (!((cs.sps->getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getUseInterEMT() && !CU::isIntra(cu))) || isChroma(cu.chType)) +#else + if( !( ( cs.sps->getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) +#endif { return; } @@ -2345,6 +2842,33 @@ void CABACWriter::emt_cu_flag( const CodingUnit& cu ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::isp_mode( const CodingUnit& cu ) +{ + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx ) + { + CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "error: cu.intraSubPartitions != 0" ); + return; + } + const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); + if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) return; + + if( cu.ispMode == NOT_INTRA_SUBPARTITIONS ) + { + m_BinEncoder.encodeBin( 0, Ctx::ISPMode( 0 ) ); + } + else + { + m_BinEncoder.encodeBin( 1, Ctx::ISPMode( 0 ) ); + + if( allowedSplits == CAN_USE_VER_AND_HORL_SPLITS ) + { + m_BinEncoder.encodeBin( cu.ispMode - 1, Ctx::ISPMode( 1 ) ); + } + } + DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); +} +#endif void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID compID ) { @@ -2373,7 +2897,11 @@ void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID comp } +#if JVET_M0297_32PT_MTS_ZERO_OUT +void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx, const TransformUnit& tu, ComponentID compID ) +#else void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx ) +#endif { unsigned blkPos = cctx.blockPos( cctx.scanPosLast() ); unsigned posX, posY; @@ -2394,11 +2922,38 @@ void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx ) unsigned GroupIdxX = g_uiGroupIdx[ posX ]; unsigned GroupIdxY = g_uiGroupIdx[ posY ]; +#if JVET_M0297_32PT_MTS_ZERO_OUT + unsigned maxLastPosX = cctx.maxLastPosX(); + unsigned maxLastPosY = cctx.maxLastPosY(); + +#if JVET_M0140_SBT +#if JVET_M0464_UNI_MTS + if( ( tu.mtsIdx > 1 || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( ( ( tu.cu->emtFlag && !tu.transformSkip[ compID ] ) || ( tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#else +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx > 1 && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#else + if( tu.cu->emtFlag && !tu.transformSkip[ compID ] && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif +#endif + { + maxLastPosX = ( tu.blocks[compID].width == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX; + maxLastPosY = ( tu.blocks[compID].height == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosY; + } +#endif + for( CtxLast = 0; CtxLast < GroupIdxX; CtxLast++ ) { m_BinEncoder.encodeBin( 1, cctx.lastXCtxId( CtxLast ) ); } +#if JVET_M0297_32PT_MTS_ZERO_OUT + if( GroupIdxX < maxLastPosX ) +#else if( GroupIdxX < cctx.maxLastPosX() ) +#endif { m_BinEncoder.encodeBin( 0, cctx.lastXCtxId( CtxLast ) ); } @@ -2406,7 +2961,11 @@ void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx ) { m_BinEncoder.encodeBin( 1, cctx.lastYCtxId( CtxLast ) ); } +#if JVET_M0297_32PT_MTS_ZERO_OUT + if( GroupIdxY < maxLastPosY ) +#else if( GroupIdxY < cctx.maxLastPosY() ) +#endif { m_BinEncoder.encodeBin( 0, cctx.lastYCtxId( CtxLast ) ); } diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 10c97e26f7796ea71d546d39521533b9f4fa2c19..ab7ebb08f54bb6a40e53a65456baa0aa6c5ba64f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -107,6 +107,9 @@ public: void intra_chroma_pred_mode ( const PredictionUnit& pu ); void cu_residual ( const CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); void rqt_root_cbf ( const CodingUnit& cu ); +#if JVET_M0140_SBT + void sbt_mode ( const CodingUnit& cu ); +#endif void end_of_ctu ( const CodingUnit& cu, CUCtx& cuCtx ); // prediction unit (clause 7.3.8.6) @@ -117,6 +120,9 @@ public: void merge_idx ( const PredictionUnit& pu ); void mmvd_merge_idx(const PredictionUnit& pu); void imv_mode ( const CodingUnit& cu ); +#if JVET_M0246_AFFINE_AMVR + void affine_amvr_mode ( const CodingUnit& cu ); +#endif void inter_pred_idc ( const PredictionUnit& pu ); void ref_idx ( const PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( const PredictionUnit& pu, RefPicList eRefList ); @@ -132,12 +138,20 @@ public: void pcm_samples ( const TransformUnit& tu ); // transform tree (clause 7.3.8.8) +#if JVET_M0102_INTRA_SUBPARTITIONS + void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); + void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); +#else void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false ); +#endif // mvd coding (clause 7.3.8.9) +#if JVET_M0246_AFFINE_AMVR + void mvd_coding ( const Mv &rMvd, int8_t imv ); +#else void mvd_coding ( const Mv &rMvd, uint8_t imv ); - +#endif // transform unit (clause 7.3.8.10) void transform_unit ( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); void cu_qp_delta ( const CodingUnit& cu, int predQP, const int8_t qp ); @@ -151,10 +165,17 @@ public: void transform_skip_flag ( const TransformUnit& tu, ComponentID compID ); void emt_tu_index ( const TransformUnit& tu ); void emt_cu_flag ( const CodingUnit& cu ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + void isp_mode ( const CodingUnit& cu ); #endif void explicit_rdpcm_mode ( const TransformUnit& tu, ComponentID compID ); +#if JVET_M0297_32PT_MTS_ZERO_OUT + void last_sig_coeff ( CoeffCodingContext& cctx, const TransformUnit& tu, ComponentID compID ); +#else void last_sig_coeff ( CoeffCodingContext& cctx ); - void residual_coding_subblock ( CoeffCodingContext& cctx, const TCoeff* coeff, const int stateTransTable, int& state ); +#endif + void residual_coding_subblock ( CoeffCodingContext& cctx, const TCoeff* coeff, const int stateTransTable, int& state ); // cross component prediction (clause 7.3.8.12) void cross_comp_pred ( const TransformUnit& tu, ComponentID compID ); diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index f8a713d34689c63d76e8badcb55ca89fb2f01fe0..a160fe70993d3eb6c9f7d9988480609f3929e9a0 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -40,6 +40,9 @@ #include "CommonLib/CodingStructure.h" #define AlfCtx(c) SubCtx( Ctx::ctbAlfFlag, c ) +#if JVET_M0427_INLOOP_RESHAPER +std::vector<double> EncAdaptiveLoopFilter::m_lumaLevelToWeightPLUT; +#endif EncAdaptiveLoopFilter::EncAdaptiveLoopFilter() : m_CABACEstimator( nullptr ) @@ -55,6 +58,10 @@ EncAdaptiveLoopFilter::EncAdaptiveLoopFilter() m_filterCoeffQuant = nullptr; m_filterCoeffSet = nullptr; m_diffFilterCoeff = nullptr; + +#if JVET_M0427_INLOOP_RESHAPER + m_alfWSSD = 0; +#endif } void EncAdaptiveLoopFilter::create( const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ) @@ -515,7 +522,7 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double uiSliceFlag = lengthTruncatedUnary(alfChromaIdc, 3); } - double rate = uiCoeffBits + uiSliceFlag; + double rate = uiCoeffBits + uiSliceFlag; m_CABACEstimator->resetBits(); m_CABACEstimator->codeAlfCtuEnableFlags( cs, channel, &m_alfSliceParamTemp); rate += FracBitsScale * (double)m_CABACEstimator->getEstFracBits(); @@ -528,7 +535,7 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh if( !isChroma ) { iBits++; // alf_coefficients_delta_flag - if( !alfSliceParam.coeffDeltaFlag ) + if( !alfSliceParam.alfLumaCoeffDeltaFlag ) { if( alfSliceParam.numLumaFilters > 1 ) { @@ -546,7 +553,7 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh // vlc for all for( int ind = 0; ind < numFilters; ++ind ) { - if( isChroma || !alfSliceParam.coeffDeltaFlag || alfSliceParam.filterCoeffFlag[ind] ) + if( isChroma || !alfSliceParam.alfLumaCoeffDeltaFlag || alfSliceParam.alfLumaCoeffFlag[ind] ) { for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { @@ -576,7 +583,7 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh if( !isChroma ) { - if( alfSliceParam.coeffDeltaFlag ) + if( alfSliceParam.alfLumaCoeffDeltaFlag ) { iBits += numFilters; //filter_coefficient_flag[i] } @@ -585,7 +592,7 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.filterCoeffFlag[ind] && alfSliceParam.coeffDeltaFlag ) + if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) { continue; } @@ -652,7 +659,7 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, dist = deriveFilterCoeffs( covFrame, covMerged, alfShape, m_filterIndices[numFilters - 1], numFilters, errorForce0CoeffTab ); // filter coeffs are stored in m_filterCoeffSet distForce0 = getDistForce0( alfShape, numFilters, errorForce0CoeffTab, codedVarBins ); - coeffBits = deriveFilterCoefficientsPredictionMode( alfShape, m_filterCoeffSet, m_diffFilterCoeff, numFilters, predMode ); + coeffBits = deriveFilterCoefficientsPredictionMode( alfShape, m_filterCoeffSet, m_diffFilterCoeff, numFilters, predMode ); coeffBitsForce0 = getCostFilterCoeffForce0( alfShape, m_filterCoeffSet, numFilters, codedVarBins ); cost = dist + m_lambda[COMPONENT_Y] * coeffBits; @@ -685,17 +692,17 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, if (cost <= cost0) { distReturn = dist; - alfSliceParam.coeffDeltaFlag = 0; + alfSliceParam.alfLumaCoeffDeltaFlag = 0; uiCoeffBits = coeffBits; - alfSliceParam.coeffDeltaPredModeFlag = bestPredMode; + alfSliceParam.alfLumaCoeffDeltaPredictionFlag = bestPredMode; } else { distReturn = distForce0; - alfSliceParam.coeffDeltaFlag = 1; + alfSliceParam.alfLumaCoeffDeltaFlag = 1; uiCoeffBits = coeffBitsForce0; - memcpy( alfSliceParam.filterCoeffFlag, codedVarBins, sizeof( codedVarBins ) ); - alfSliceParam.coeffDeltaPredModeFlag = 0; + memcpy( alfSliceParam.alfLumaCoeffFlag, codedVarBins, sizeof( codedVarBins ) ); + alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; for( int varInd = 0; varInd < numFiltersBest; varInd++ ) { @@ -710,7 +717,7 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, { for( int i = 0; i < alfShape.numCoeff; i++ ) { - if( alfSliceParam.coeffDeltaPredModeFlag ) + if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) { alfSliceParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_diffFilterCoeff[ind][i]; } @@ -1146,7 +1153,7 @@ double EncAdaptiveLoopFilter::deriveCoeffQuant( int *filterCoeffQuant, double ** filterCoeffQuant[numCoeff - 1] = -quantCoeffSum; filterCoeff[numCoeff - 1] = filterCoeffQuant[numCoeff - 1] / double(factor); - + //Restrict the range of the center coefficient int max_value_center = (2 * factor - 1) - factor; int min_value_center = 0 - factor; @@ -1472,16 +1479,44 @@ void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariace, const AlfF classIdx = cl.classIdx; } +#if JVET_M0427_INLOOP_RESHAPER + double weight = 1.0; + if (m_alfWSSD) + { + weight = m_lumaLevelToWeightPLUT[org[j]]; + } +#endif int yLocal = org[j] - rec[j]; calcCovariance( ELocal, rec + j, recStride, shape.pattern.data(), shape.filterLength >> 1, transposeIdx ); for( int k = 0; k < shape.numCoeff; k++ ) { for( int l = k; l < shape.numCoeff; l++ ) { +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].E[k][l] += weight * (double)(ELocal[k] * ELocal[l]); + } + else +#endif alfCovariace[classIdx].E[k][l] += ELocal[k] * ELocal[l]; } +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].y[k] += weight * (double)(ELocal[k] * yLocal); + } + else +#endif alfCovariace[classIdx].y[k] += ELocal[k] * yLocal; } +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].pixAcc += weight * (double)(yLocal * yLocal); + } + else +#endif alfCovariace[classIdx].pixAcc += yLocal * yLocal; } org += orgStride; diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index da36a50e59e89898e8c54a547238fcf818ee80b7..1a0a67a4326c062232722c0b7e1dc9583756a6cc 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -151,6 +151,12 @@ class EncAdaptiveLoopFilter : public AdaptiveLoopFilter public: static constexpr int m_MAX_SCAN_VAL = 11; static constexpr int m_MAX_EXP_GOLOMB = 16; +#if JVET_M0427_INLOOP_RESHAPER + int m_alfWSSD; + inline void setAlfWSSD(int alfWSSD) { m_alfWSSD = alfWSSD; } + static std::vector<double> m_lumaLevelToWeightPLUT; + inline std::vector<double>& getLumaLevelWeightTable() { return m_lumaLevelToWeightPLUT; } +#endif private: AlfCovariance*** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][classIdx] diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 0fdf461193b496844a0114d1dc5da9f382ac02bf..6a89a07fd3a2aba71fa58e5d17e24ef28b5b8d31 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -215,17 +215,17 @@ protected: int m_FastIntraEMT; int m_FastInterEMT; #endif - bool m_LargeCTU; +#if JVET_M0303_IMPLICIT_MTS + int m_ImplicitMTS; +#endif +#if JVET_M0140_SBT + bool m_SBT; ///< Sub-Block Transform for inter blocks +#endif int m_SubPuMvpMode; bool m_Affine; bool m_AffineType; bool m_BIO; - bool m_DisableMotionCompression; - unsigned m_MTTMode; -#if ENABLE_WPP_PARALLELISM - bool m_AltDQPCoding; -#endif bool m_compositeRefEnabled; //composite reference bool m_GBi; bool m_GBiFast; @@ -238,7 +238,21 @@ protected: bool m_MHIntra; bool m_Triangle; - +#if JVET_M0255_FRACMMVD_SWITCH + bool m_allowDisFracMMVD; +#endif +#if JVET_M0246_AFFINE_AMVR + bool m_AffineAmvr; +#endif +#if JVET_M0253_HASH_ME + bool m_HashME; +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + bool m_AffineAmvrEncOpt; +#endif +#if JVET_M0147_DMVR + bool m_DMVR; +#endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; unsigned m_IBCLocalSearchRangeY; @@ -246,12 +260,17 @@ protected: unsigned m_IBCHashSearchMaxCand; unsigned m_IBCHashSearchRange4SmallBlk; unsigned m_IBCFastMethod; - + bool m_wrapAround; unsigned m_wrapAroundOffset; // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + bool m_lumaReshapeEnable; + unsigned m_reshapeSignalType; + unsigned m_intraCMD; + ReshapeCW m_reshapeCW; +#endif bool m_useFastLCTU; bool m_useFastMrg; bool m_usePbIntraFast; @@ -302,8 +321,8 @@ protected: int m_chromaCbQpOffset; // Chroma Cb QP Offset (0:default) int m_chromaCrQpOffset; // Chroma Cr Qp Offset (0:default) - int m_chromaCbQpOffsetDualTree; // Chroma Cb QP Offset for dual tree - int m_chromaCrQpOffsetDualTree; // Chroma Cr Qp Offset for dual tree + int m_chromaCbQpOffsetDualTree; // Chroma Cb QP Offset for dual tree + int m_chromaCrQpOffsetDualTree; // Chroma Cr Qp Offset for dual tree #if ER_CHROMA_QP_WCG_PPS WCGChromaQPControl m_wcgChromaQpControl; ///< Wide-colour-gamut chroma QP control. #endif @@ -547,6 +566,9 @@ protected: int m_switchDQP; ///< dqp applied to switchPOC and subsequent pictures. int m_fastForwardToPOC; ///< bool m_stopAfterFFtoPOC; ///< +#if JVET_M0055_DEBUG_CTU + int m_debugCTU; ///< dbg ctu +#endif bool m_bs2ModPOCAndType; @@ -678,9 +700,6 @@ public: void setDualITree ( bool b ) { m_dualITree = b; } bool getDualITree () const { return m_dualITree; } - void setLargeCTU ( bool b ) { m_LargeCTU = b; } - bool getLargeCTU () const { return m_LargeCTU; } - void setUseLMChroma ( int n ) { m_LMChroma = n; } int getUseLMChroma() const { return m_LMChroma; } #if JVET_M0142_CCLM_COLLOCATED_CHROMA @@ -697,16 +716,6 @@ public: bool getAffineType() const { return m_AffineType; } void setBIO(bool b) { m_BIO = b; } bool getBIO() const { return m_BIO; } - void setDisableMotionCompression ( bool b ) { m_DisableMotionCompression = b; } - bool getDisableMotionCompression () const { return m_DisableMotionCompression; } - - - void setMTTMode ( unsigned u ) { m_MTTMode = u; } - unsigned getMTTMode () const { return m_MTTMode; } -#if ENABLE_WPP_PARALLELISM - void setUseAltDQPCoding ( bool b ) { m_AltDQPCoding = b; } - bool getUseAltDQPCoding () const { return m_AltDQPCoding; } -#endif #if JVET_M0464_UNI_MTS void setIntraMTSMaxCand ( unsigned u ) { m_IntraMTSMaxCand = u; } @@ -727,9 +736,14 @@ public: void setInterEMT ( bool b ) { m_InterEMT = b; } bool getInterEMT () const { return m_InterEMT; } #endif - - - +#if JVET_M0303_IMPLICIT_MTS + void setImplicitMTS ( bool b ) { m_ImplicitMTS = b; } + bool getImplicitMTS () const { return m_ImplicitMTS; } +#endif +#if JVET_M0140_SBT + void setUseSBT ( bool b ) { m_SBT = b; } + bool getUseSBT () const { return m_SBT; } +#endif void setUseCompositeRef (bool b) { m_compositeRefEnabled = b; } bool getUseCompositeRef () const { return m_compositeRefEnabled; } @@ -754,7 +768,26 @@ public: bool getUseMHIntra () const { return m_MHIntra; } void setUseTriangle ( bool b ) { m_Triangle = b; } bool getUseTriangle () const { return m_Triangle; } - +#if JVET_M0255_FRACMMVD_SWITCH + void setAllowDisFracMMVD ( bool b ) { m_allowDisFracMMVD = b; } + bool getAllowDisFracMMVD () const { return m_allowDisFracMMVD; } +#endif +#if JVET_M0253_HASH_ME + void setUseHashME ( bool b ) { m_HashME = b; } + bool getUseHashME () const { return m_HashME; } +#endif +#if JVET_M0246_AFFINE_AMVR + void setUseAffineAmvr ( bool b ) { m_AffineAmvr = b; } + bool getUseAffineAmvr () const { return m_AffineAmvr; } +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + void setUseAffineAmvrEncOpt ( bool b ) { m_AffineAmvrEncOpt = b; } + bool getUseAffineAmvrEncOpt () const { return m_AffineAmvrEncOpt; } +#endif +#if JVET_M0147_DMVR + void setDMVR ( bool b ) { m_DMVR = b; } + bool getDMVR () const { return m_DMVR; } +#endif void setIBCMode (unsigned n) { m_IBCMode = n; } unsigned getIBCMode () const { return m_IBCMode; } @@ -778,7 +811,16 @@ public: // ADD_NEW_TOOL : (encoder lib) add access functions here - +#if JVET_M0427_INLOOP_RESHAPER + void setReshaper ( bool b ) { m_lumaReshapeEnable = b; } + bool getReshaper () const { return m_lumaReshapeEnable; } + void setReshapeSignalType ( uint32_t signalType ) { m_reshapeSignalType = signalType; } + uint32_t getReshapeSignalType () const { return m_reshapeSignalType; } + void setReshapeIntraCMD (uint32_t intraCMD) { m_intraCMD = intraCMD; } + uint32_t getReshapeIntraCMD () { return m_intraCMD; } + void setReshapeCW (const ReshapeCW &reshapeCW) { m_reshapeCW = reshapeCW; } + const ReshapeCW& getReshapeCW () { return m_reshapeCW; } +#endif void setMaxCUWidth ( uint32_t u ) { m_maxCUWidth = u; } uint32_t getMaxCUWidth () const { return m_maxCUWidth; } void setMaxCUHeight ( uint32_t u ) { m_maxCUHeight = u; } @@ -1420,7 +1462,10 @@ public: bool getStopAfterFFtoPOC() const { return m_stopAfterFFtoPOC; } void setBs2ModPOCAndType( bool b ) { m_bs2ModPOCAndType = b; } bool getBs2ModPOCAndType() const { return m_bs2ModPOCAndType; } - +#if JVET_M0055_DEBUG_CTU + void setDebugCTU( int i ) { m_debugCTU = i; } + int getDebugCTU() const { return m_debugCTU; } +#endif #if ENABLE_SPLIT_PARALLELISM void setNumSplitThreads( int n ) { m_numSplitThreads = n; } @@ -1441,5 +1486,5 @@ public: }; //! \} - + #endif // !defined(AFX_TENCCFG_H__6B99B797_F4DA_4E46_8E78_7656339A6C41__INCLUDED_) diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 2b41fcb861b2322aa96914164e4b886e52868414..e26650fdcb7264ce6a71245a40fd37f26762f365 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -64,6 +64,19 @@ extern std::recursive_mutex g_cache_mutex; // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== +#if JVET_M0883_TRIANGLE_SIGNALING +const TriangleMotionInfo EncCu::m_triangleModeTest[TRIANGLE_MAX_NUM_CANDS] = +{ + TriangleMotionInfo( 0, 1, 0 ), TriangleMotionInfo( 1, 0, 1 ), TriangleMotionInfo( 1, 0, 2 ), TriangleMotionInfo( 0, 0, 1 ), TriangleMotionInfo( 0, 2, 0 ), + TriangleMotionInfo( 1, 0, 3 ), TriangleMotionInfo( 1, 0, 4 ), TriangleMotionInfo( 1, 1, 0 ), TriangleMotionInfo( 0, 3, 0 ), TriangleMotionInfo( 0, 4, 0 ), + TriangleMotionInfo( 0, 0, 2 ), TriangleMotionInfo( 0, 1, 2 ), TriangleMotionInfo( 1, 1, 2 ), TriangleMotionInfo( 0, 0, 4 ), TriangleMotionInfo( 0, 0, 3 ), + TriangleMotionInfo( 0, 1, 3 ), TriangleMotionInfo( 0, 1, 4 ), TriangleMotionInfo( 1, 1, 4 ), TriangleMotionInfo( 1, 1, 3 ), TriangleMotionInfo( 1, 2, 1 ), + TriangleMotionInfo( 1, 2, 0 ), TriangleMotionInfo( 0, 2, 1 ), TriangleMotionInfo( 0, 4, 3 ), TriangleMotionInfo( 1, 3, 0 ), TriangleMotionInfo( 1, 3, 2 ), + TriangleMotionInfo( 1, 3, 4 ), TriangleMotionInfo( 1, 4, 0 ), TriangleMotionInfo( 1, 3, 1 ), TriangleMotionInfo( 1, 2, 3 ), TriangleMotionInfo( 1, 4, 1 ), + TriangleMotionInfo( 0, 4, 1 ), TriangleMotionInfo( 0, 2, 3 ), TriangleMotionInfo( 1, 4, 2 ), TriangleMotionInfo( 0, 3, 2 ), TriangleMotionInfo( 1, 4, 3 ), + TriangleMotionInfo( 0, 3, 1 ), TriangleMotionInfo( 0, 2, 4 ), TriangleMotionInfo( 1, 2, 4 ), TriangleMotionInfo( 0, 4, 2 ), TriangleMotionInfo( 0, 3, 4 ), +}; +#endif void EncCu::create( EncCfg* encCfg ) { @@ -103,6 +116,22 @@ void EncCu::create( EncCfg* encCfg ) m_pTempMotLUTs[w][h] = new LutMotionCand ; m_pBestMotLUTs[w][h] = new LutMotionCand ; m_pSplitTempMotLUTs[w][h] = new LutMotionCand; +#if JVET_M0483_IBC + m_pSplitTempMotLUTs[w][h]->currCnt = 0; + m_pSplitTempMotLUTs[w][h]->currCntIBC = 0; + m_pSplitTempMotLUTs[w][h]->motionCand = nullptr; + m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2]; + + m_pTempMotLUTs[w][h]->currCnt = 0; + m_pTempMotLUTs[w][h]->currCntIBC = 0; + m_pTempMotLUTs[w][h]->motionCand = nullptr; + m_pTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2]; + + m_pBestMotLUTs[w][h]->currCnt = 0; + m_pBestMotLUTs[w][h]->currCntIBC = 0; + m_pBestMotLUTs[w][h]->motionCand = nullptr; + m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2]; +#else m_pSplitTempMotLUTs[w][h]->currCnt = 0; m_pSplitTempMotLUTs[w][h]->motionCand = nullptr; m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; @@ -114,6 +143,7 @@ void EncCu::create( EncCfg* encCfg ) m_pBestMotLUTs[w][h]->currCnt = 0; m_pBestMotLUTs[w][h]->motionCand = nullptr; m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; +#endif } else { @@ -147,6 +177,20 @@ void EncCu::create( EncCfg* encCfg ) { m_acRealMergeBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight)); } +#if JVET_M0883_TRIANGLE_SIGNALING + for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_UNI_CANDS; ui++ ) + { + for( unsigned uj = 0; uj < TRIANGLE_MAX_NUM_UNI_CANDS; uj++ ) + { + if(ui == uj) + continue; + uint8_t idxBits0 = ui + (ui == TRIANGLE_MAX_NUM_UNI_CANDS - 1 ? 0 : 1); + uint8_t candIdx1Enc = uj - (uj > ui ? 1 : 0); + uint8_t idxBits1 = candIdx1Enc + (candIdx1Enc == TRIANGLE_MAX_NUM_UNI_CANDS - 2 ? 0 : 1); + m_triangleIdxBins[1][ui][uj] = m_triangleIdxBins[0][ui][uj] = 1 + idxBits0 + idxBits1; + } + } +#endif for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ ) { m_acTriangleWeightedBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) ); @@ -205,6 +249,14 @@ void EncCu::destroy() delete[] m_pBestMotLUTs; m_pBestMotLUTs = nullptr; delete[] m_pTempMotLUTs; m_pTempMotLUTs = nullptr; +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + if (m_tmpStorageLCU) + { + m_tmpStorageLCU->destroy(); + delete m_tmpStorageLCU; m_tmpStorageLCU = nullptr; + } +#endif + #if REUSE_CU_RESULTS m_modeCtrl->destroy(); @@ -288,11 +340,18 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) ) m_modeCtrl->init( m_pcEncCfg, m_pcRateCtrl, m_pcRdCost ); m_pcInterSearch->setModeCtrl( m_modeCtrl ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcIntraSearch->setModeCtrl( m_modeCtrl ); +#endif ::memset(m_subMergeBlkSize, 0, sizeof(m_subMergeBlkSize)); ::memset(m_subMergeBlkNum, 0, sizeof(m_subMergeBlkNum)); m_prevPOC = MAX_UINT; +#if JVET_M0255_FRACMMVD_SWITCH + if ( ( m_pcEncCfg->getIBCHashSearch() && m_pcEncCfg->getIBCMode() ) || m_pcEncCfg->getAllowDisFracMMVD() ) +#else if (m_pcEncCfg->getIBCHashSearch() && m_pcEncCfg->getIBCMode()) +#endif { m_ibcHashMap.init(m_pcEncCfg->getSourceWidth(), m_pcEncCfg->getSourceHeight()); } @@ -304,10 +363,20 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) ) void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] ) { - if (m_pcEncCfg->getIBCHashSearch() && ctuRsAddr == 0 && cs.slice->getSPS()->getSpsNext().getIBCMode()) +#if !JVET_M0255_FRACMMVD_SWITCH + if (m_pcEncCfg->getIBCHashSearch() && ctuRsAddr == 0 && cs.slice->getSPS()->getIBCMode()) { +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getSPS()->getUseReshaper() && m_pcReshape->getCTUFlag()) + cs.picture->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); +#endif m_ibcHashMap.rebuildPicHashMap(cs.picture->getOrigBuf()); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getSPS()->getUseReshaper() && m_pcReshape->getCTUFlag()) + cs.picture->getOrigBuf().copyFrom(cs.picture->getTrueOrigBuf()); +#endif } +#endif m_modeCtrl->initCTUEncoding( *cs.slice ); #if ENABLE_SPLIT_PARALLELISM @@ -331,6 +400,10 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign partitioner->initCtu( area, CH_L, *cs.slice ); if (m_pcEncCfg->getIBCMode()) { + if (area.lx() == 0 && area.ly() == 0) + { + m_pcInterSearch->resetIbcSearch(); + } m_pcInterSearch->resetCtuRecord(); m_ctuIbcSearchRangeX = m_pcEncCfg->getIBCLocalSearchRangeX(); m_ctuIbcSearchRangeY = m_pcEncCfg->getIBCLocalSearchRangeY(); @@ -343,7 +416,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign m_ctuIbcSearchRangeX >>= 1; m_ctuIbcSearchRangeY >>= 1; } +#if JVET_M0483_IBC + if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 0) +#else if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 1) +#endif { m_ctuIbcSearchRangeX >>= 1; m_ctuIbcSearchRangeY >>= 1; @@ -371,7 +448,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign ); // all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS +#if JVET_M0427_INLOOP_RESHAPER + const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1; +#else const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; +#endif cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); cs.slice->copyMotionLUTs(bestMotCandLUTs, cs.slice->getMotionLUTs()); @@ -392,7 +473,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign , bestMotCandLUTs ); +#if JVET_M0427_INLOOP_RESHAPER + const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1; +#else const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; +#endif cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); } @@ -620,7 +705,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth() ); const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture ); +#if JVET_M0483_IBC + if (m_pImvTempCS && (!slice.isIntra() || slice.getSPS()->getIBCFlag())) +#else if( m_pImvTempCS && !slice.isIntra() ) +#endif { tempCS->initSubStructure( *m_pImvTempCS[wIdx], partitioner.chType, partitioner.currArea(), false ); } @@ -628,6 +717,15 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par tempCS->chType = partitioner.chType; bestCS->chType = partitioner.chType; m_modeCtrl->initCULevel( partitioner, *tempCS ); +#if JVET_M0140_SBT + if( partitioner.currQtDepth == 0 && partitioner.currMtDepth == 0 && !tempCS->slice->isIntra() && ( sps.getUseSBT() || sps.getUseInterMTS() ) ) + { + auto slsSbt = dynamic_cast<SaveLoadEncInfoSbt*>( m_modeCtrl ); + int maxSLSize = sps.getUseSBT() ? tempCS->slice->getSPS()->getMaxSbtSize() : MTS_INTER_MAX_CU_SIZE; + slsSbt->resetSaveloadSbt( maxSLSize ); + } + m_sbtCostSave[0] = m_sbtCostSave[1] = MAX_DOUBLE; +#endif m_CurrCtx->start = m_CABACEstimator->getCtx(); @@ -645,7 +743,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par m_modeCtrl->finishCULevel( partitioner ); return; } +#if JVET_M0483_IBC + if ((!slice.isIntra() || slice.getSPS()->getIBCFlag()) +#else if (!slice.isIntra() +#endif && tempCS->chType == CHANNEL_TYPE_LUMA ) { @@ -662,6 +764,9 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par #if JVET_M0170_MRG_SHARELIST int startShareThisLevel = 0; #endif +#if JVET_M0246_AFFINE_AMVR + m_pcInterSearch->resetSavedAffineMotion(); +#endif do { @@ -673,9 +778,8 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, tempCS->area.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, tempCS->area.chromaFormat)); const CodingStructure* baseCS = bestCS->picture->cs; const CodingUnit* colLumaCu = baseCS->getCU(lumaRefPos, CHANNEL_TYPE_LUMA); - const TransformUnit* tu = baseCS->getTU(lumaRefPos, CHANNEL_TYPE_LUMA); - if (colLumaCu && tu) + if (colLumaCu) { currTestMode.qp = colLumaCu->qp; } @@ -707,14 +811,32 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par { if( ( currTestMode.opts & ETO_IMV ) != 0 ) { +#if JVET_M0246_AFFINE_AMVR + tempCS->bestCS = bestCS; + xCheckRDCostInterIMV( tempCS, bestCS, partitioner, currTestMode ); + tempCS->bestCS = nullptr; +#else xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode); +#endif } else { +#if JVET_M0246_AFFINE_AMVR + tempCS->bestCS = bestCS; xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode ); + tempCS->bestCS = nullptr; +#else + xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode ); +#endif } } +#if JVET_M0253_HASH_ME + else if (currTestMode.type == ETM_HASH_INTER) + { + xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode ); + } +#endif else if( currTestMode.type == ETM_AFFINE ) { xCheckRDCostAffineMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode ); @@ -794,14 +916,25 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par // QP from last processed CU for further processing bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp; - if (!slice.isIntra() +#if JVET_M0483_IBC + if ((!slice.isIntra() || slice.getSPS()->getIBCFlag()) +#else + if (!slice.isIntra() +#endif && bestCS->chType == CHANNEL_TYPE_LUMA - && bestCS->cus.size() == 1 && bestCS->cus.back()->predMode == MODE_INTER +#if JVET_M0483_IBC + && bestCS->cus.size() == 1 && (bestCS->cus.back()->predMode == MODE_INTER || bestCS->cus.back()->predMode == MODE_IBC) +#else + && bestCS->cus.size() == 1 && bestCS->cus.back()->predMode == MODE_INTER +#endif && bestCS->area.Y() == (*bestCS->cus.back()).Y() ) { bestCS->slice->updateMotionLUTs(bestMotCandLUTs, (*bestCS->cus.back())); } +#if JVET_M0427_INLOOP_RESHAPER + bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea)); +#endif bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) ); m_modeCtrl->finishCULevel( partitioner ); @@ -904,7 +1037,10 @@ void EncCu::updateLambda (Slice* slice, const int dQP, const bool updateRdCostLa #else m_pcTrQuant->setLambda (newLambda); #endif - if (updateRdCostLambda) m_pcRdCost->setLambda (newLambda, slice->getSPS()->getBitDepths()); + if (updateRdCostLambda) + { + m_pcRdCost->setLambda (newLambda, slice->getSPS()->getBitDepths()); + } #endif } #endif @@ -1183,6 +1319,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CurrCtx++; tempCS->getRecoBuf().fill( 0 ); + +#if JVET_M0427_INLOOP_RESHAPER + tempCS->getPredBuf().fill(0); +#endif AffineMVInfo tmpMVInfo; bool isAffMVInfoSaved; m_pcInterSearch->savePrevAffMVInfo(0, tmpMVInfo, isAffMVInfoSaved); @@ -1257,7 +1397,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, partitioner.exitCurrSplit(); -#if JVET_M0170_MRG_SHARELIST +#if JVET_M0170_MRG_SHARELIST if (startShareThisLevel == 1) { m_shareState = NO_SHARE; @@ -1366,7 +1506,11 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, if (isAffMVInfoSaved) m_pcInterSearch->addAffMVInfo(tmpMVInfo); +#if JVET_M0483_IBC + if ((!slice.isIntra() || slice.getSPS()->getIBCFlag()) +#else if (!slice.isIntra() +#endif && tempCS->chType == CHANNEL_TYPE_LUMA ) { @@ -1395,9 +1539,16 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC #if !JVET_M0464_UNI_MTS const CodingUnit *bestCU = bestCS->getCU( partitioner.chType ); const int maxSizeEMT = EMT_INTRA_MAX_CU_WITH_QTBT; - uint8_t considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0; + uint8_t considerEmtSecondPass = ( sps.getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + bool useIntraSubPartitions = false; + double maxCostAllowedForChroma = MAX_DOUBLE; +#if JVET_M0464_UNI_MTS + const CodingUnit *bestCU = bestCS->getCU( partitioner.chType ); +#endif +#endif Distortion interHad = m_modeCtrl->getInterHad(); @@ -1438,6 +1589,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC #if !JVET_M0464_UNI_MTS cu.emtFlag = emtCuFlag; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + cu.ispMode = NOT_INTRA_SUBPARTITIONS; +#endif CU::addPUs( cu ); @@ -1445,7 +1599,24 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( isLuma( partitioner.chType ) ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + //the Intra SubPartitions mode uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary lines + const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; + m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar ); + + useIntraSubPartitions = cu.ispMode != NOT_INTRA_SUBPARTITIONS; + if( !CS::isDualITree( *tempCS ) ) + { + tempCS->lumaCost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); + if( useIntraSubPartitions ) + { + //the difference between the best cost so far and the current luma cost is stored to avoid testing the Cr component if the cost of luma + Cb is larger than the best cost + maxCostAllowedForChroma = bestCS->cost < MAX_DOUBLE ? bestCS->cost - tempCS->lumaCost : MAX_DOUBLE; + } + } +#else m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner ); +#endif if (m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == std::numeric_limits<Distortion>::max() && tempCS->interHad == 0) @@ -1463,12 +1634,29 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( !CS::isDualITree( *tempCS ) ) { cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) ); +#if JVET_M0427_INLOOP_RESHAPER + cu.cs->picture->getPredBuf(cu.Y()).copyFrom(cu.cs->getPredBuf(COMPONENT_Y)); +#endif } } if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + TUIntraSubPartitioner subTuPartitioner( partitioner ); + m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( CS::isDualITree( *cu.cs ) && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma ); + if( useIntraSubPartitions && !cu.ispMode ) + { + //At this point the temp cost is larger than the best cost. Therefore, we can already skip the remaining calculations +#if JVET_M0464_UNI_MTS + return; +#else + continue; +#endif + } +#else m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner ); +#endif } cu.rootCbf = false; @@ -1486,7 +1674,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC m_CABACEstimator->cu_transquant_bypass_flag( cu ); } - if( !cu.cs->slice->isIntra() +#if JVET_M0483_IBC + if ((!cu.cs->slice->isIntra() || cu.cs->slice->getSPS()->getIBCFlag()) +#else + if( !cu.cs->slice->isIntra() +#endif && cu.Y().valid() ) { @@ -1494,6 +1686,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC } m_CABACEstimator->pred_mode ( cu ); m_CABACEstimator->extend_ref_line( cu ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->isp_mode ( cu ); +#endif m_CABACEstimator->cu_pred_data ( cu ); m_CABACEstimator->pcm_data ( cu, partitioner ); @@ -1506,10 +1701,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC tempCS->fracBits = m_CABACEstimator->getEstFracBits(); tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist); +#if JVET_M0102_INTRA_SUBPARTITIONS +#if !JVET_M0464_UNI_MTS + double bestIspCost = cu.ispMode ? CS::isDualITree(*tempCS) ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE; +#endif + const double tmpCostWithoutSplitFlags = tempCS->cost; +#endif xEncodeDontSplit( *tempCS, partitioner ); xCheckDQP( *tempCS, partitioner ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( tempCS->cost < bestCS->cost ) + { + m_modeCtrl->setBestCostWithoutSplitFlags( tmpCostWithoutSplitFlags ); + } +#endif #if !JVET_M0464_UNI_MTS // we save the cost of the modes for the first EMT pass if( !emtCuFlag ) static_cast< double& >( costSize2Nx2NemtFirstPass ) = tempCS->cost; @@ -1523,6 +1730,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + //we decide to skip the second emt pass or not according to the ISP results + if (considerEmtSecondPass && cu.ispMode && !emtCuFlag && tempCS->slice->isIntra()) + { + double bestCostDct2NoIsp = m_modeCtrl->getEmtFirstPassNoIspCost(); + CHECKD(bestCostDct2NoIsp <= bestIspCost, "wrong cost!"); + double nSamples = (double)(cu.lwidth() << g_aucLog2[cu.lheight()]); + double threshold = 1 + 1.4 / sqrt(nSamples); + if (bestCostDct2NoIsp > bestIspCost*threshold) + { + skipSecondEmtPass = true; + m_modeCtrl->setSkipSecondEMTPass(true); + break; + } + } +#endif //now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && m_pcEncCfg->getFastInterEMT() ) { @@ -1572,7 +1795,11 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P m_CABACEstimator->cu_transquant_bypass_flag( cu ); } - if( !cu.cs->slice->isIntra() +#if JVET_M0483_IBC + if ((!cu.cs->slice->isIntra() || cu.cs->slice->getSPS()->getIBCFlag()) +#else + if( !cu.cs->slice->isIntra() +#endif && cu.Y().valid() ) { @@ -1692,7 +1919,58 @@ void EncCu::xFillPCMBuffer( CodingUnit &cu ) } } } +#if JVET_M0253_HASH_ME +void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) +{ + bool isPerfectMatch = false; + + tempCS->initStructData(encTestMode.qp, encTestMode.lossless); + m_pcInterSearch->resetBufferedUniMotions(); + m_pcInterSearch->setAffineModeSelected(false); + CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType); + partitioner.setCUData(cu); + cu.slice = tempCS->slice; + cu.skip = false; + cu.predMode = MODE_INTER; + cu.transQuantBypass = encTestMode.lossless; + cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; + cu.qp = encTestMode.qp; +#if !JVET_M0483_IBC + cu.ibc = false; +#endif + CU::addPUs(cu); + cu.mmvdSkip = false; + cu.firstPU->mmvdMergeFlag = false; + + if (m_pcInterSearch->predInterHashSearch(cu, partitioner, isPerfectMatch)) + { + const unsigned wIdx = gp_sizeIdxInfo->idxFrom(tempCS->area.lwidth()); + double equGBiCost = MAX_DOUBLE; + +#if JVET_M0464_UNI_MTS + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL + , 0 + , &equGBiCost +#else + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL + , 1 + , 0 + , &equGBiCost +#endif + ); + } + tempCS->initStructData(encTestMode.qp, encTestMode.lossless); + + if (cu.lwidth() != 64) + { + isPerfectMatch = false; + } + m_modeCtrl->setIsHashPerfectMatch(isPerfectMatch); +} +#endif void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) { @@ -1711,6 +1989,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize ); } +#if JVET_M0147_DMVR + Mv refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS]; +#endif setMergeBestSATDCost( MAX_DOUBLE ); { @@ -1777,12 +2058,12 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList2; // store the Intra mode for Intrainter RdModeList2.clear(); - bool isIntrainterEnabled = sps.getSpsNext().getUseMHIntra(); + bool isIntrainterEnabled = sps.getUseMHIntra(); if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE) { isIntrainterEnabled = false; } - bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode + bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++) { isTestSkipMerge[idx] = false; @@ -1798,7 +2079,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ) { - if (slice.getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC + if (slice.getSPS()->getIBCFlag()) +#else + if (slice.getSPS()->getIBCMode()) +#endif { ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx(); bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU; @@ -1848,27 +2133,55 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& m_pcRdCost->setDistParam (distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth (CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) ); +#if JVET_M0483_IBC==0 uint32_t ibcCand = 0; uint32_t numValidMv = mergeCtx.numValidMergeCand; +#endif for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ ) { +#if JVET_M0483_IBC==0 if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC()) { ibcCand++; numValidMv--; continue; } +#endif mergeCtx.setMergeInfo( pu, uiMergeCand ); PU::spanMotionInfo( pu, mergeCtx ); +#if JVET_M0147_DMVR + pu.mvRefine = true; +#endif distParam.cur = singleMergeTempBuffer->Y(); m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea); acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer); +#if JVET_M0147_DMVR + pu.mvRefine = false; +#endif if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N ) { mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv = pu.mv[0]; mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1]; +#if JVET_M0147_DMVR + { + int dx, dy, i, j, num = 0; + dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT); + dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH); + if (PU::checkDMVRCondition(pu)) + { + for (i = 0; i < (pu.lumaSize().height); i += dy) + { + for (j = 0; j < (pu.lumaSize().width); j += dx) + { + refinedMvdL0[num][uiMergeCand] = pu.mvdL0SubPu[num]; + num++; + } + } + } + } +#endif } Distortion uiSad = distParam.distFunc(distParam); @@ -1896,13 +2209,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]); } } +#if JVET_M0483_IBC==0 CHECK(std::min(uiMergeCand + 1 - ibcCand, uiNumMrgSATDCand) != RdModeList.size(), ""); +#else + CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), ""); +#endif } +#if JVET_M0483_IBC==0 if (numValidMv < uiNumMrgSATDCand) uiNumMrgSATDCand = numValidMv; if (numValidMv == 0) return; - +#endif if (isIntrainterEnabled) { @@ -1919,11 +2237,19 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& // save the to-be-tested merge candidates uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND]; +#if JVET_M0483_IBC==0 for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++) +#else + for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++) +#endif { MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt]; } +#if JVET_M0483_IBC==0 for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++) +#else + for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++) +#endif { uint32_t mergeCand = MHIntraMergeCand[mergeCnt]; acMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea); @@ -1963,11 +2289,29 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); } pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); // calculate cost +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getInvLUT()); + } +#endif distParam.cur = pu.cs->getPredBuf(pu).Y(); Distortion sadValue = distParam.distFunc(distParam); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode); uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA); double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra; @@ -1996,7 +2340,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.mmvdSkip = true; int tempNum = 0; tempNum = MMVD_ADD_NUM; +#if !JVET_M0823_MMVD_ENCOPT bool allowDirection[4] = { true, true, true, true }; +#endif for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++) { const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand; @@ -2006,9 +2352,12 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& int bitsCand = 0; int baseIdx; int refineStep; +#if !JVET_M0823_MMVD_ENCOPT int direction; +#endif baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM; refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4; +#if !JVET_M0823_MMVD_ENCOPT direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4; if (refineStep == 0) { @@ -2018,6 +2367,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& { continue; } +#endif bitsBaseIdx = baseIdx + 1; if (baseIdx == MMVD_BASE_MV_NUM - 1) { @@ -2036,14 +2386,29 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand); PU::spanMotionInfo(pu, mergeCtx); +#if JVET_M0147_DMVR + pu.mvRefine = true; +#endif distParam.cur = singleMergeTempBuffer->Y(); +#if JVET_M0823_MMVD_ENCOPT + pu.mmvdEncOptMode = (refineStep > 2 ? 2 : 1); + CHECK(!pu.mmvdMergeFlag, "MMVD merge should be set"); + // Don't do chroma MC here + m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, false); + pu.mmvdEncOptMode = 0; +#else m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); - +#endif +#if JVET_M0147_DMVR // store the refined MV + pu.mvRefine = false; +#endif Distortion uiSad = distParam.distFunc(distParam); double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass; +#if !JVET_M0823_MMVD_ENCOPT allowDirection[direction] = cost > 1.3 * candCostList[0] ? 0 : 1; +#endif insertPos = -1; updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos); if (insertPos != -1) @@ -2106,21 +2471,37 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } } +#if !JVET_M0253_HASH_ME const uint32_t iteration = encTestMode.lossless ? 1 : 2; // 2. Pass: check candidates using full RD test for( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ ) +#else + uint32_t iteration; + uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0; + if (encTestMode.lossless) + { + iteration = 1; + iterationBegin = 0; + } + else + { + iteration = 2; + } + for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass) +#endif { for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ ) { uint32_t uiMergeCand = RdModeList[uiMrgHADIdx]; - +#if JVET_M0483_IBC==0 if(uiMergeCand < mergeCtx.numValidMergeCand) if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC()) { continue; } +#endif if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode { @@ -2181,11 +2562,35 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& if( mrgTempBufSet ) { +#if JVET_M0147_DMVR + { + int dx, dy, i, j, num = 0; + dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT); + dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH); + if (PU::checkDMVRCondition(pu)) + { + for (i = 0; i < (pu.lumaSize().height); i += dy) + { + for (j = 0; j < (pu.lumaSize().width); j += dx) + { + pu.mvdL0SubPu[num] = refinedMvdL0[num][uiMergeCand]; + num++; + } + } + } + } +#endif if (pu.mhIntraFlag) { uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0]; PelBuf tmpBuf = tempCS->getPredBuf(pu).Y(); tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y()); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + tmpBuf.rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx)); tmpBuf = tempCS->getPredBuf(pu).Cb(); tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb()); @@ -2196,6 +2601,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } else { +#if JVET_M0823_MMVD_ENCOPT + if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM) { + pu.mmvdEncOptMode = 0; + m_pcInterSearch->motionCompensation(pu); + } + else +#endif if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) { tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]); @@ -2208,8 +2620,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } else { +#if JVET_M0147_DMVR + pu.mvRefine = true; +#endif m_pcInterSearch->motionCompensation( pu ); - +#if JVET_M0147_DMVR + pu.mvRefine = false; +#endif } if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0) { @@ -2272,9 +2689,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru const SPS &sps = *tempCS->sps; CHECK( slice.getSliceType() != B_SLICE, "Triangle mode is only applied to B-slices" ); - + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); - + bool trianglecandHasNoResidual[TRIANGLE_MAX_NUM_CANDS]; for( int mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_CANDS; mergeCand++ ) { @@ -2331,7 +2748,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru triangleBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea); triangleMrgCtx.setMergeInfo( pu, mergeCand ); PU::spanMotionInfo( pu, triangleMrgCtx ); - + m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] ); } } @@ -2348,7 +2765,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru else { CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType ); - + partitioner.setCUData( cu ); cu.slice = tempCS->slice; #if HEVC_TILES_WPP @@ -2364,7 +2781,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru cu.GBiIdx = GBI_DEFAULT; PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType ); - + if( abs(g_aucLog2[cu.lwidth()] - g_aucLog2[cu.lheight()]) >= 2 ) { numTriangleCandidate = 30; @@ -2376,23 +2793,42 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru for( uint8_t mergeCand = 0; mergeCand < numTriangleCandidate; mergeCand++ ) { +#if JVET_M0883_TRIANGLE_SIGNALING + bool splitDir = m_triangleModeTest[mergeCand].m_splitDir; + uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0; + uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1; +#else bool splitDir = g_triangleCombination[mergeCand][0]; uint8_t candIdx0 = g_triangleCombination[mergeCand][1]; uint8_t candIdx1 = g_triangleCombination[mergeCand][2]; +#endif +#if JVET_M0883_TRIANGLE_SIGNALING + pu.triangleSplitDir = splitDir; + pu.triangleMergeIdx0 = candIdx0; + pu.triangleMergeIdx1 = candIdx1; +#else pu.mergeIdx = mergeCand; +#endif pu.mergeFlag = true; triangleWeightedBuffer[mergeCand] = m_acTriangleWeightedBuffer[mergeCand].getBuf( localUnitArea ); triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea ); triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea ); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); +#else m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); - +#endif distParam.cur = triangleWeightedBuffer[mergeCand].Y(); Distortion uiSad = distParam.distFunc( distParam ); +#if JVET_M0883_TRIANGLE_SIGNALING + uint32_t uiBitsCand = m_triangleIdxBins[splitDir][candIdx0][candIdx1]; +#else uint32_t uiBitsCand = g_triangleIdxBins[mergeCand]; +#endif double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; @@ -2401,7 +2837,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru , *nullList, -1 , triangleNumMrgSATDCand ); } - + // limit number of candidates using SATD-costs for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ ) { @@ -2416,22 +2852,53 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ ) { uint8_t mergeCand = triangleRdModeList[i]; +#if JVET_M0883_TRIANGLE_SIGNALING + bool splitDir = m_triangleModeTest[mergeCand].m_splitDir; + uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0; + uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1; +#else bool splitDir = g_triangleCombination[mergeCand][0]; uint8_t candIdx0 = g_triangleCombination[mergeCand][1]; uint8_t candIdx1 = g_triangleCombination[mergeCand][2]; - +#endif + +#if JVET_M0883_TRIANGLE_SIGNALING + pu.triangleSplitDir = splitDir; + pu.triangleMergeIdx0 = candIdx0; + pu.triangleMergeIdx1 = candIdx1; +#else pu.mergeIdx = mergeCand; +#endif pu.mergeFlag = true; - + +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); +#else m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); +#endif } tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); } { +#if !JVET_M0253_HASH_ME const uint8_t iteration = encTestMode.lossless ? 1 : 2; for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ ) +#else + uint8_t iteration; + uint8_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0; + if (encTestMode.lossless) + { + iteration = 1; + iterationBegin = 0; + } + else + { + iteration = 2; + } + for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass) +#endif { for( uint8_t mrgHADIdx = 0; mrgHADIdx < triangleNumMrgSATDCand; mrgHADIdx++ ) { @@ -2443,9 +2910,15 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru continue; } +#if JVET_M0883_TRIANGLE_SIGNALING + bool splitDir = m_triangleModeTest[mergeCand].m_splitDir; + uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0; + uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1; +#else bool splitDir = g_triangleCombination[mergeCand][0]; uint8_t candIdx0 = g_triangleCombination[mergeCand][1]; uint8_t candIdx1 = g_triangleCombination[mergeCand][2]; +#endif CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType); @@ -2464,10 +2937,20 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru cu.GBiIdx = GBI_DEFAULT; PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType); +#if JVET_M0883_TRIANGLE_SIGNALING + pu.triangleSplitDir = splitDir; + pu.triangleMergeIdx0 = candIdx0; + pu.triangleMergeIdx1 = candIdx1; +#else pu.mergeIdx = mergeCand; +#endif pu.mergeFlag = true; +#if JVET_M0883_TRIANGLE_SIGNALING + PU::spanTriangleMotionInfo(pu, triangleMrgCtx, splitDir, candIdx0, candIdx1 ); +#else PU::spanTriangleMotionInfo(pu, triangleMrgCtx, mergeCand, splitDir, candIdx0, candIdx1 ); +#endif if( tempBufSet ) { @@ -2478,9 +2961,13 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea ); triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea ); PelUnitBuf predBuf = tempCS->getPredBuf(); +#if JVET_M0328_KEEP_ONE_WEIGHT_GROUP + m_pcInterSearch->weightedTriangleBlk( pu, splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); +#else m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); +#endif } - + #if JVET_M0464_UNI_MTS xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, ( noResidualPass == 0 ? &trianglecandHasNoResidual[mergeCand] : NULL ) ); #else @@ -2493,7 +2980,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru } tempCS->initStructData(encTestMode.qp, encTestMode.lossless); }// end loop mrgHADIdx - } + } } } @@ -2644,9 +3131,9 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct uiBitsCand--; } double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; - static_vector<int, AFFINE_MRG_MAX_NUM_CANDS> * nullList = nullptr; + static_vector<int, AFFINE_MRG_MAX_NUM_CANDS> emptyList; updateCandList( uiMergeCand, cost, RdModeList, candCostList - , *nullList, -1 + , emptyList, -1 , uiNumMrgSATDCand ); CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" ); @@ -2670,10 +3157,25 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct } } +#if !JVET_M0253_HASH_ME const uint32_t iteration = encTestMode.lossless ? 1 : 2; // 2. Pass: check candidates using full RD test for ( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ ) +#else + uint32_t iteration; + uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0; + if (encTestMode.lossless) + { + iteration = 1; + iterationBegin = 0; + } + else + { + iteration = 2; + } + for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass) +#endif { for ( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ ) { @@ -2803,8 +3305,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct // first get merge candidates CodingUnit cu(tempCS->area); cu.cs = tempCS; +#if JVET_M0483_IBC + cu.predMode = MODE_IBC; +#else cu.predMode = MODE_INTER; cu.ibc = true; +#endif cu.slice = tempCS->slice; #if HEVC_TILES_WPP cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); @@ -2819,9 +3325,13 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct pu.shareParentPos = tempCS->sharedBndPos; pu.shareParentSize = tempCS->sharedBndSize; #endif +#if JVET_M0483_IBC + PU::getIBCMergeCandidates(pu, mergeCtx); +#else PU::getInterMergeCandidates(pu, mergeCtx , 0 ); +#endif } int candHasNoResidual[MRG_MAX_NUM_CANDS]; @@ -2852,8 +3362,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); #endif cu.skip = false; +#if JVET_M0483_IBC + cu.predMode = MODE_IBC; +#else cu.predMode = MODE_INTER; cu.ibc = true; +#endif cu.transQuantBypass = encTestMode.lossless; cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; @@ -2866,12 +3380,25 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct Picture* refPic = pu.cu->slice->getPic(); const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]); const Pel* piRefSrch = refBuf.buf; +#if JVET_M0427_INLOOP_RESHAPER + if (tempCS->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea); + tmpLuma.copyFrom(tempCS->getOrgBuf().Y()); + tmpLuma.rspSignal(m_pcReshape->getFwdLUT()); + m_pcRdCost->setDistParam(distParam, tmpLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); + } + else +#endif m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); int refStride = refBuf.stride; const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height)); int numValidBv = mergeCtx.numValidMergeCand; for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++) { +#if JVET_M0483_IBC==0 if (mergeCtx.interDirNeighbours[mergeCand] != 1) { numValidBv--; @@ -2882,6 +3409,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct numValidBv--; continue; } +#endif mergeCtx.setMergeInfo(pu, mergeCand); // set bv info in merge mode const int cuPelX = pu.Y().x; const int cuPelY = pu.Y().y; @@ -2951,6 +3479,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++) { unsigned int mergeCand = RdModeList[mrgHADIdx]; +#if JVET_M0483_IBC==0 if (mergeCtx.interDirNeighbours[mergeCand] != 1) { continue; @@ -2959,6 +3488,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct { continue; } +#endif if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1)) { if (!(bestIsSkip && (numResidualPass == 0))) @@ -2989,14 +3519,21 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); #endif cu.skip = false; +#if JVET_M0483_IBC + cu.predMode = MODE_IBC; +#else cu.predMode = MODE_INTER; cu.ibc = true; +#endif cu.transQuantBypass = encTestMode.lossless; cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; #if !JVET_M0464_UNI_MTS cu.emtFlag = false; #endif +#if JVET_M0140_SBT + cu.sbtInfo = 0; +#endif PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu); pu.intraDir[0] = DC_IDX; // set intra pred for ibc block @@ -3062,6 +3599,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode) { + if (tempCS->area.lwidth() > IBC_MAX_CAND_SIZE || tempCS->area.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip + { + return; + } + tempCS->initStructData(encTestMode.qp, encTestMode.lossless); CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType); @@ -3072,12 +3614,21 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); #endif cu.skip = false; +#if JVET_M0483_IBC + cu.predMode = MODE_IBC; +#else cu.predMode = MODE_INTER; +#endif cu.transQuantBypass = encTestMode.lossless; cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; +#if JVET_M0483_IBC==0 cu.ibc = true; +#endif cu.imv = 0; +#if JVET_M0140_SBT + cu.sbtInfo = 0; +#endif CU::addPUs(cu); @@ -3089,8 +3640,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block pu.interDir = 1; // use list 0 for IBC mode +#if JVET_M0483_IBC + pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; // last idx in the list +#else pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list - +#endif if (partitioner.chType == CHANNEL_TYPE_LUMA) { @@ -3254,7 +3808,7 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC { tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); - + m_pcInterSearch->setAffineModeSelected(false); if( tempCS->slice->getCheckLDC() ) @@ -3265,7 +3819,7 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC m_pcInterSearch->resetBufferedUniMotions(); int gbiLoopNum = (tempCS->slice->isInterB() ? GBI_NUM : 1); - gbiLoopNum = (tempCS->sps->getSpsNext().getUseGBi() ? gbiLoopNum : 1); + gbiLoopNum = (tempCS->sps->getUseGBi() ? gbiLoopNum : 1); if( tempCS->area.lwidth() * tempCS->area.lheight() < GBI_SIZE_CONSTRAINT ) { @@ -3403,13 +3957,16 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be m_pcInterSearch->resetBufferedUniMotions(); int gbiLoopNum = (tempCS->slice->isInterB() ? GBI_NUM : 1); gbiLoopNum = (pcCUInfo2Reuse != NULL ? 1 : gbiLoopNum); - gbiLoopNum = (tempCS->slice->getSPS()->getSpsNext().getUseGBi() ? gbiLoopNum : 1); + gbiLoopNum = (tempCS->slice->getSPS()->getUseGBi() ? gbiLoopNum : 1); if( tempCS->area.lwidth() * tempCS->area.lheight() < GBI_SIZE_CONSTRAINT ) { gbiLoopNum = 1; } +#if JVET_M0246_AFFINE_AMVR + bool validMode = false; +#endif double curBestCost = bestCS->cost; double equGBiCost = MAX_DOUBLE; @@ -3481,7 +4038,10 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be bool testGbi; uint8_t gbiIdx; - +#if JVET_M0246_AFFINE_AMVR + bool affineAmvrEanbledFlag = cu.slice->getSPS()->getAffineAmvrEnabledFlag(); +#endif + if( pcCUInfo2Reuse != nullptr ) { // reuse the motion info from pcCUInfo2Reuse @@ -3491,7 +4051,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be gbiIdx = CU::getValidGbiIdx(cu); testGbi = (gbiIdx != GBI_DEFAULT); +#if JVET_M0246_AFFINE_AMVR + if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) ) +#else if( !CU::hasSubCUNonZeroMVd( cu ) ) +#endif { if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner)) { @@ -3499,7 +4063,19 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be // store temp best CI for next CU coding m_CurrCtx->best = m_CABACEstimator->getCtx(); } +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEanbledFlag ) + { + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + continue; + } + else + { + return false; + } +#else return false; +#endif } else { @@ -3512,9 +4088,24 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be gbiIdx = cu.GBiIdx; testGbi = (gbiIdx != GBI_DEFAULT); +#if JVET_M0246_AFFINE_AMVR + cu.firstPU->interDir = 10; +#endif + m_pcInterSearch->predInterSearch( cu, partitioner ); +#if JVET_M0246_AFFINE_AMVR + if ( cu.firstPU->interDir <= 3 ) + { + gbiIdx = CU::getValidGbiIdx(cu); + } + else + { + return false; + } +#else gbiIdx = CU::getValidGbiIdx(cu); +#endif } if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni. @@ -3533,7 +4124,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be } } +#if JVET_M0246_AFFINE_AMVR + if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) ) +#else if( !CU::hasSubCUNonZeroMVd( cu ) ) +#endif { if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner)) { @@ -3541,7 +4136,19 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be // store temp best CI for next CU coding m_CurrCtx->best = m_CABACEstimator->getCtx(); } +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEanbledFlag ) + { + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + continue; + } + else + { + return false; + } +#else return false; +#endif } #if JVET_M0464_UNI_MTS @@ -3578,9 +4185,16 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be { break; } +#if JVET_M0246_AFFINE_AMVR + validMode = true; +#endif } // for( UChar gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ ) +#if JVET_M0246_AFFINE_AMVR + return tempCS->slice->getSPS()->getAffineAmvrEnabledFlag() ? validMode : true; +#else return true; +#endif } #if JVET_M0464_UNI_MTS @@ -3609,6 +4223,11 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be CodingUnit* cu = tempCS->getCU( partitioner.chType ); double bestCostInternal = MAX_DOUBLE; double bestCost = bestCS->cost; +#if JVET_M0140_SBT + double bestCostBegin = bestCS->cost; + CodingUnit* prevBestCU = bestCS->getCU( partitioner.chType ); + uint8_t prevBestSbt = ( prevBestCU == nullptr ) ? 0 : prevBestCU->sbtInfo; +#endif #if !JVET_M0464_UNI_MTS const SPS& sps = *tempCS->sps; const int maxSizeEMT = EMT_INTER_MAX_CU_WITH_QTBT; @@ -3616,7 +4235,7 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be bool swapped = false; // avoid unwanted data copy bool reloadCU = false; #if !JVET_M0464_UNI_MTS - const bool considerEmtSecondPass = emtMode && sps.getSpsNext().getUseInterEMT() && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT; + const bool considerEmtSecondPass = emtMode && sps.getUseInterEMT() && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT; int minEMTMode = 0; int maxEMTMode = (considerEmtSecondPass?1:0); @@ -3649,6 +4268,51 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be } } } +#if JVET_M0140_SBT + const bool mtsAllowed = tempCS->sps->getUseInterMTS() && partitioner.currArea().lwidth() <= MTS_INTER_MAX_CU_SIZE && partitioner.currArea().lheight() <= MTS_INTER_MAX_CU_SIZE; + uint8_t sbtAllowed = cu->checkAllowedSbt(); + uint8_t numRDOTried = 0; + Distortion sbtOffDist = 0; + bool sbtOffRootCbf = 0; + double sbtOffCost = MAX_DOUBLE; + double currBestCost = MAX_DOUBLE; + bool doPreAnalyzeResi = ( sbtAllowed || mtsAllowed ) && residualPass == 0; + + m_pcInterSearch->initTuAnalyzer(); + if( doPreAnalyzeResi ) + { + m_pcInterSearch->calcMinDistSbt( *tempCS, *cu, sbtAllowed ); + } + + auto slsSbt = dynamic_cast<SaveLoadEncInfoSbt*>( m_modeCtrl ); + int slShift = 4 + std::min( (int)gp_sizeIdxInfo->idxFrom( cu->lwidth() ) + (int)gp_sizeIdxInfo->idxFrom( cu->lheight() ), 9 ); + Distortion curPuSse = m_pcInterSearch->getEstDistSbt( NUMBER_SBT_MODE ); + uint8_t currBestSbt = 0; + uint8_t currBestTrs = MAX_UCHAR; + uint8_t histBestSbt = MAX_UCHAR; + uint8_t histBestTrs = MAX_UCHAR; + m_pcInterSearch->setHistBestTrs( MAX_UCHAR, MAX_UCHAR ); + if( doPreAnalyzeResi ) + { + if( m_pcInterSearch->getSkipSbtAll() && !mtsAllowed ) //emt is off + { + histBestSbt = 0; //try DCT2 + m_pcInterSearch->setHistBestTrs( histBestSbt, histBestTrs ); + } + else + { + assert( curPuSse != std::numeric_limits<uint64_t>::max() ); + uint16_t compositeSbtTrs = slsSbt->findBestSbt( cu->cs->area, (uint32_t)( curPuSse >> slShift ) ); + histBestSbt = ( compositeSbtTrs >> 0 ) & 0xff; + histBestTrs = ( compositeSbtTrs >> 8 ) & 0xff; + if( m_pcInterSearch->getSkipSbtAll() && CU::isSbtMode( histBestSbt ) ) //special case, skip SBT when loading SBT + { + histBestSbt = 0; //try DCT2 + } + m_pcInterSearch->setHistBestTrs( histBestSbt, histBestTrs ); + } + } +#endif #if !JVET_M0464_UNI_MTS if( emtMode == 2 ) @@ -3692,14 +4356,24 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be #if !JVET_M0464_UNI_MTS cu->emtFlag = curEmtMode; #endif +#if JVET_M0140_SBT + cu->sbtInfo = 0; +#endif const bool skipResidual = residualPass == 1; +#if JVET_M0140_SBT // skip DCT-2 and EMT if historical best transform mode is SBT + if( skipResidual || histBestSbt == MAX_UCHAR || !CU::isSbtMode( histBestSbt ) ) + { +#endif m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual ); - +#if JVET_M0140_SBT + numRDOTried += mtsAllowed ? 2 : 1; +#endif xEncodeDontSplit( *tempCS, partitioner ); xCheckDQP( *tempCS, partitioner ); +#if !JVET_M0140_SBT //harmonize with GBI fast algorithm (move the code to the end of this function) if( ETM_INTER_ME == encTestMode.type ) { if( equGBiCost != NULL ) @@ -3729,6 +4403,7 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be } } } +#endif #if !JVET_M0464_UNI_MTS double emtFirstPassCost = tempCS->cost; @@ -3756,6 +4431,18 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be return; } } +#if JVET_M0140_SBT + currBestCost = tempCS->cost; + sbtOffCost = tempCS->cost; + sbtOffDist = tempCS->dist; + sbtOffRootCbf = cu->rootCbf; + currBestSbt = CU::getSbtInfo( cu->firstTU->mtsIdx > 1 ? SBT_OFF_MTS : SBT_OFF_DCT, 0 ); + currBestTrs = cu->firstTU->mtsIdx; + if( cu->lwidth() <= MAX_TU_SIZE_FOR_PROFILE && cu->lheight() <= MAX_TU_SIZE_FOR_PROFILE ) + { + CHECK( tempCS->tus.size() != 1, "tu must be only one" ); + } +#endif #if WCG_EXT DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) ); @@ -3773,13 +4460,205 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be const bool bCond3 = emtFirstPassCost > ( bestCost * thresholdToSkipEmtSecondPass ); - if( m_pcEncCfg->getFastInterEMT() && (bCond1 || bCond3 ) ) + if( m_pcEncCfg->getFastInterEMT() && (bCond1 || bCond3 ) ) { maxEMTMode = 0; // do not test EMT } } +#endif +#if JVET_M0140_SBT // skip DCT-2 and EMT + } +#endif + +#if JVET_M0140_SBT //RDO for SBT + uint8_t numSbtRdo = CU::numSbtModeRdo( sbtAllowed ); + //early termination if all SBT modes are not allowed + //normative + if( !sbtAllowed || skipResidual ) + { + numSbtRdo = 0; + } + //fast algorithm + if( ( histBestSbt != MAX_UCHAR && !CU::isSbtMode( histBestSbt ) ) || m_pcInterSearch->getSkipSbtAll() ) + { + numSbtRdo = 0; + } + if( bestCost != MAX_DOUBLE && sbtOffCost != MAX_DOUBLE ) + { + double th = 1.07; + if( !( prevBestSbt == 0 || m_sbtCostSave[0] == MAX_DOUBLE ) ) + { + assert( m_sbtCostSave[1] <= m_sbtCostSave[0] ); + th *= ( m_sbtCostSave[0] / m_sbtCostSave[1] ); + } + if( sbtOffCost > bestCost * th ) + { + numSbtRdo = 0; + } + } + if( !sbtOffRootCbf && sbtOffCost != MAX_DOUBLE ) + { + double th = Clip3( 0.05, 0.55, ( 27 - cu->qp ) * 0.02 + 0.35 ); + if( sbtOffCost < m_pcRdCost->calcRdCost( ( cu->lwidth() * cu->lheight() ) << SCALE_BITS, 0 ) * th ) + { + numSbtRdo = 0; + } + } + + if( histBestSbt != MAX_UCHAR && numSbtRdo != 0 ) + { + numSbtRdo = 1; + m_pcInterSearch->initSbtRdoOrder( CU::getSbtMode( CU::getSbtIdx( histBestSbt ), CU::getSbtPos( histBestSbt ) ) ); + } + + for( int sbtModeIdx = 0; sbtModeIdx < numSbtRdo; sbtModeIdx++ ) + { + uint8_t sbtMode = m_pcInterSearch->getSbtRdoOrder( sbtModeIdx ); + uint8_t sbtIdx = CU::getSbtIdxFromSbtMode( sbtMode ); + uint8_t sbtPos = CU::getSbtPosFromSbtMode( sbtMode ); + + //fast algorithm (early skip, save & load) + if( histBestSbt == MAX_UCHAR ) + { + uint8_t skipCode = m_pcInterSearch->skipSbtByRDCost( cu->lwidth(), cu->lheight(), cu->mtDepth, sbtIdx, sbtPos, bestCS->cost, sbtOffDist, sbtOffCost, sbtOffRootCbf ); + if( skipCode != MAX_UCHAR ) + { + continue; + } + + if( sbtModeIdx > 0 ) + { + uint8_t prevSbtMode = m_pcInterSearch->getSbtRdoOrder( sbtModeIdx - 1 ); + //make sure the prevSbtMode is the same size as the current SBT mode (otherwise the estimated dist may not be comparable) + if( CU::isSameSbtSize( prevSbtMode, sbtMode ) ) + { + Distortion currEstDist = m_pcInterSearch->getEstDistSbt( sbtMode ); + Distortion prevEstDist = m_pcInterSearch->getEstDistSbt( prevSbtMode ); + if( currEstDist > prevEstDist * 1.15 ) + { + continue; + } + } + } + } + + //init tempCS and TU + if( bestCost == bestCS->cost ) //The first EMT pass didn't become the bestCS, so we clear the TUs generated + { + tempCS->clearTUs(); + } + else if( false == swapped ) + { + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + tempCS->copyStructure( *bestCS, partitioner.chType ); + tempCS->getPredBuf().copyFrom( bestCS->getPredBuf() ); + bestCost = bestCS->cost; + cu = tempCS->getCU( partitioner.chType ); + swapped = true; + } + else + { + tempCS->clearTUs(); + bestCost = bestCS->cost; + cu = tempCS->getCU( partitioner.chType ); + } + + //we need to restart the distortion for the new tempCS, the bit count and the cost + tempCS->dist = 0; + tempCS->fracBits = 0; + tempCS->cost = MAX_DOUBLE; + cu->skip = false; + + //set SBT info + cu->setSbtIdx( sbtIdx ); + cu->setSbtPos( sbtPos ); + + //try residual coding + m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual ); + numRDOTried++; + + xEncodeDontSplit( *tempCS, partitioner ); + + xCheckDQP( *tempCS, partitioner ); + + if( imvCS && ( tempCS->cost < imvCS->cost ) ) + { + if( imvCS->cost != MAX_DOUBLE ) + { + imvCS->initStructData( encTestMode.qp, encTestMode.lossless ); + } + imvCS->copyStructure( *tempCS, partitioner.chType ); + } + + if( NULL != bestHasNonResi && ( bestCostInternal > tempCS->cost ) ) + { + bestCostInternal = tempCS->cost; + if( !( tempCS->getPU( partitioner.chType )->mhIntraFlag ) ) + *bestHasNonResi = !cu->rootCbf; + } + + if( tempCS->cost < currBestCost ) + { + currBestSbt = cu->sbtInfo; + currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx; + assert( currBestTrs == 0 || currBestTrs == 1 ); + currBestCost = tempCS->cost; + } + +#if WCG_EXT + DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) ); +#else + DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() ); +#endif + xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); + } + + if( bestCostBegin != bestCS->cost ) + { + m_sbtCostSave[0] = sbtOffCost; + m_sbtCostSave[1] = currBestCost; + } #endif } //end emt loop + +#if JVET_M0140_SBT + if( histBestSbt == MAX_UCHAR && doPreAnalyzeResi && numRDOTried > 1 ) + { + slsSbt->saveBestSbt( cu->cs->area, (uint32_t)( curPuSse >> slShift ), currBestSbt, currBestTrs ); + } +#endif +#if JVET_M0140_SBT //harmonize with GBI fast algorithm (move the code here) + tempCS->cost = currBestCost; + if( ETM_INTER_ME == encTestMode.type ) + { + if( equGBiCost != NULL ) + { + if( tempCS->cost < ( *equGBiCost ) && cu->GBiIdx == GBI_DEFAULT ) + { + ( *equGBiCost ) = tempCS->cost; + } + } + else + { + CHECK( equGBiCost == NULL, "equGBiCost == NULL" ); + } + if( tempCS->slice->getCheckLDC() && !cu->imv && cu->GBiIdx != GBI_DEFAULT && tempCS->cost < m_bestGbiCost[1] ) + { + if( tempCS->cost < m_bestGbiCost[0] ) + { + m_bestGbiCost[1] = m_bestGbiCost[0]; + m_bestGbiCost[0] = tempCS->cost; + m_bestGbiIdx[1] = m_bestGbiIdx[0]; + m_bestGbiIdx[0] = cu->GBiIdx; + } + else + { + m_bestGbiCost[1] = tempCS->cost; + m_bestGbiIdx[1] = cu->GBiIdx; + } + } + } +#endif } @@ -3851,9 +4730,26 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best CPelBuf org = tempCS->getOrgBuf ( compID ); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (tempCS->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = tempCS->getOrgBuf(tempCS->area.blocks[COMPONENT_Y]); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())) + { + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU->getBuf(tmpArea); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); } else diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index b239ed8baf3e9351f980d0f2c13265898150f27e..bbc3156010ccb34efb75c2b097f3683848304310 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -68,6 +68,16 @@ class EncSlice; // ==================================================================================================================== /// CU encoder class +#if JVET_M0883_TRIANGLE_SIGNALING +struct TriangleMotionInfo +{ + uint8_t m_splitDir; + uint8_t m_candIdx0; + uint8_t m_candIdx1; + + TriangleMotionInfo ( uint8_t splitDir, uint8_t candIdx0, uint8_t candIdx1 ): m_splitDir(splitDir), m_candIdx0(candIdx0), m_candIdx1(candIdx1) { } +}; +#endif class EncCu #if REUSE_CU_RESULTS : DecCu @@ -135,14 +145,23 @@ private: #endif int m_bestGbiIdx[2]; double m_bestGbiCost[2]; +#if JVET_M0883_TRIANGLE_SIGNALING + static const TriangleMotionInfo m_triangleModeTest[TRIANGLE_MAX_NUM_CANDS]; + uint8_t m_triangleIdxBins[2][TRIANGLE_MAX_NUM_UNI_CANDS][TRIANGLE_MAX_NUM_UNI_CANDS]; +#endif #if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU void updateLambda ( Slice* slice, const int dQP, const bool updateRdCostLambda ); #endif +#if JVET_M0140_SBT + double m_sbtCostSave[2]; +#endif public: /// copy parameters from encoder class void init ( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int jId = 0 ) ); - +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + void setDecCuReshaperInEncCU(EncReshape* pcReshape, ChromaFormat chromaFormatIDC) { initDecCuReshaper((Reshape*) pcReshape, chromaFormatIDC); } +#endif /// create internal buffers void create ( EncCfg* encCfg ); @@ -159,6 +178,10 @@ public: void setMergeBestSATDCost(double cost) { m_mergeBestSATDCost = cost; } double getMergeBestSATDCost() { return m_mergeBestSATDCost; } +#if JVET_M0255_FRACMMVD_SWITCH + IbcHashMap& getIbcHashMap() { return m_ibcHashMap; } + EncCfg* getEncCfg() const { return m_pcEncCfg; } +#endif #if JVET_M0170_MRG_SHARELIST Position shareParentPos; @@ -192,6 +215,9 @@ protected: void xCheckDQP ( CodingStructure& cs, Partitioner& partitioner, bool bKeepCtx = false); void xFillPCMBuffer ( CodingUnit &cu); +#if JVET_M0253_HASH_ME + void xCheckRDCostHashInter ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); +#endif void xCheckRDCostAffineMerge2Nx2N ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ); void xCheckRDCostInter ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 0872980a6a75910484f743ffbbd9bd40ef719c8f..fc134aa842f6f4341494d6f4a505b9d481e4a213 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -178,8 +178,33 @@ void EncGOP::init ( EncLib* pcEncLib ) m_AUWriterIf = pcEncLib->getAUWriterIf(); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcCfg->getReshaper()) + { + pcEncLib->getRdCost()->setReshapeInfo(m_pcCfg->getReshapeSignalType(), m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA)); + pcEncLib->getRdCost()->initLumaLevelToWeightTableReshape(); + } + else if (m_pcCfg->getLumaLevelToDeltaQPMapping().mode) + { + pcEncLib->getRdCost()->setReshapeInfo(RESHAPE_SIGNAL_PQ, m_pcCfg->getBitDepth(CHANNEL_TYPE_LUMA)); + pcEncLib->getRdCost()->initLumaLevelToWeightTableReshape(); +#else pcEncLib->getRdCost()->initLumaLevelToWeightTable(); #endif +#if JVET_M0427_INLOOP_RESHAPER + } + pcEncLib->getALF()->getLumaLevelWeightTable() = pcEncLib->getRdCost()->getLumaLevelWeightTable(); + int alfWSSD = 0; + if (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ ) + { + alfWSSD = 1; + } + pcEncLib->getALF()->setAlfWSSD(alfWSSD); +#endif +#endif +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshaper = pcEncLib->getReshaper(); +#endif } #if HEVC_VPS @@ -1207,11 +1232,29 @@ void trySkipOrDecodePicture( bool& decPic, bool& encPic, const EncCfg& cfg, Pict else { // update decode decision +#if JVET_M0055_DEBUG_CTU + bool dbgCTU = cfg.getDebugCTU() != -1 && cfg.getSwitchPOC() == pcPic->getPOC(); + + if( ( bDecode1stPart = ( cfg.getSwitchPOC() != pcPic->getPOC() ) || dbgCTU ) && ( bDecode1stPart = tryDecodePicture( pcPic, pcPic->getPOC(), cfg.getDecodeBitstream( 0 ), false, cfg.getDebugCTU(), cfg.getSwitchPOC() ) ) ) + { + if( dbgCTU ) + { + encPic = true; + decPic = false; + bDecode1stPart = false; + + return; + } + decPic = bDecode1stPart; + return; + } +#else if( ( bDecode1stPart = ( cfg.getSwitchPOC() != pcPic->getPOC() )) && ( bDecode1stPart = tryDecodePicture( pcPic, pcPic->getPOC(), cfg.getDecodeBitstream( 0 ), false ) ) ) { decPic = bDecode1stPart; return; } +#endif else if( pcPic->getPOC() ) { // reset decoder if used and not required any further @@ -1456,10 +1499,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, { pcSlice->setSliceType(I_SLICE); } - if (pcSlice->getSliceType() == I_SLICE && pcSlice->getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC ==0 + if (pcSlice->getSliceType() == I_SLICE && pcSlice->getSPS()->getIBCMode()) { pcSlice->setSliceType(P_SLICE); } +#endif // Set the nal unit type pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField)); if(pcSlice->getTemporalLayerNonReferenceFlag()) @@ -1504,7 +1549,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, setNewestBgPOC(pocCurr); setLastLTRefPoc(pocCurr); } - else if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && getLastLTRefPoc() >= 0 && getEncodedLTRef()==false && !getPicBg()->getSpliceFull() && (pocCurr - getLastLTRefPoc()) > (m_pcCfg->getFrameRate() * 2)) + else if (pcPic->cs->sps->getUseCompositeRef() && getLastLTRefPoc() >= 0 && getEncodedLTRef()==false && !getPicBg()->getSpliceFull() && (pocCurr - getLastLTRefPoc()) > (m_pcCfg->getFrameRate() * 2)) { setUseLTRef(false); setPrepareLTRef(false); @@ -1513,7 +1558,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, setLastLTRefPoc(-1); } - if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && m_picBg->getSpliceFull() && getUseLTRef()) + if (pcPic->cs->sps->getUseCompositeRef() && m_picBg->getSpliceFull() && getUseLTRef()) { m_pcEncLib->selectReferencePictureSet(pcSlice, pocCurr, iGOPid, m_bgPOC); } @@ -1627,10 +1672,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcSlice->setNumRefIdx(REF_PIC_LIST_0, std::min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive, pcSlice->getRPS()->getNumberOfPictures())); pcSlice->setNumRefIdx(REF_PIC_LIST_1, std::min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive, pcSlice->getRPS()->getNumberOfPictures())); } - if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && getPrepareLTRef()) { + if (pcPic->cs->sps->getUseCompositeRef() && getPrepareLTRef()) { arrangeCompositeReference(pcSlice, rcListPic, pocCurr); } - if (pcSlice->getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (pcSlice->getSPS()->getIBCMode()) { if (m_pcCfg->getIntraPeriod() > 0 && pcSlice->getPOC() % m_pcCfg->getIntraPeriod() == 0) { @@ -1640,9 +1686,78 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcSlice->setNumRefIdx(REF_PIC_LIST_0, pcSlice->getNumRefIdx(REF_PIC_LIST_0) + 1); } +#endif // Set reference list pcSlice->setRefPicList ( rcListPic ); +#if JVET_M0253_HASH_ME + if (m_pcCfg->getUseHashME()) + { + PicList::iterator iterPic = rcListPic.begin(); + while (iterPic != rcListPic.end()) + { + Picture* refPic = *(iterPic++); + + if (refPic->poc != pcPic->poc && refPic->referenced) + { + if (!refPic->getHashMap()->isInitial()) + { + if (refPic->getPOC() == 0) + { + Pel* picSrc = refPic->getOrigBuf().get(COMPONENT_Y).buf; + int stridePic = refPic->getOrigBuf().get(COMPONENT_Y).stride; + int picWidth = pcSlice->getSPS()->getPicWidthInLumaSamples(); + int picHeight = pcSlice->getSPS()->getPicHeightInLumaSamples(); + int blockSize = 4; + int allNum = 0; + int simpleNum = 0; + for (int j = 0; j <= picHeight - blockSize; j += blockSize) + { + for (int i = 0; i <= picWidth - blockSize; i += blockSize) + { + Pel* curBlock = picSrc + j * stridePic + i; + bool isHorSame = true; + for (int m = 0; m < blockSize&&isHorSame; m++) + { + for (int n = 1; n < blockSize&&isHorSame; n++) + { + if (curBlock[m*stridePic] != curBlock[m*stridePic + n]) + { + isHorSame = false; + } + } + } + bool isVerSame = true; + for (int m = 1; m < blockSize&&isVerSame; m++) + { + for (int n = 0; n < blockSize&&isVerSame; n++) + { + if (curBlock[n] != curBlock[m*stridePic + n]) + { + isVerSame = false; + } + } + } + allNum++; + if (isHorSame || isVerSame) + { + simpleNum++; + } + } + } + + if (simpleNum < 0.3*allNum) + { + m_pcCfg->setUseHashME(false); + break; + } + } + refPic->addPictureToHashMapForInter(); + } + } + } + } +#endif if( m_pcCfg->getUseAMaxBT() ) { if( !pcSlice->isIRAP() ) @@ -1696,10 +1811,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, { pcSlice->setSliceType ( P_SLICE ); } - if (pcSlice->getSPS()->getSpsNext().getIBCMode() && pcSlice->getNumRefIdx(REF_PIC_LIST_0) == 1) +#if JVET_M0483_IBC==0 + if (pcSlice->getSPS()->getIBCMode() && pcSlice->getNumRefIdx(REF_PIC_LIST_0) == 1) { m_pcSliceEncoder->setEncCABACTableIdx(P_SLICE); } +#endif xUpdateRasInit( pcSlice ); // Do decoding refresh marking if any @@ -1786,7 +1903,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } // disable TMVP when current picture is the only ref picture - if (pcSlice->isIRAP() && pcSlice->getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC + if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCFlag()) +#else + if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCMode()) +#endif { pcSlice->setEnableTMVPFlag(0); } @@ -1800,7 +1921,8 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, bool bGPBcheck=false; if ( pcSlice->getSliceType() == B_SLICE) { - if (pcSlice->getSPS()->getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (pcSlice->getSPS()->getIBCMode()) { if (pcSlice->getNumRefIdx(RefPicList(0)) - 1 == pcSlice->getNumRefIdx(RefPicList(1))) { @@ -1816,6 +1938,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } } else +#endif if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) ) { bGPBcheck=true; @@ -2096,6 +2219,109 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcSlice->setSliceChromaQpDelta(COMPONENT_Cr, m_pcCfg->getChromaCrQpOffsetDualTree()); m_pcSliceEncoder->setUpLambda(pcSlice, pcSlice->getLambdas()[0], pcSlice->getSliceQp()); } +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + m_pcReshaper->getReshapeCW()->rspTid = pcSlice->getTLayer() + (pcSlice->isIntra() ? 0 : 1); + m_pcReshaper->getReshapeCW()->rspSliceQP = pcSlice->getSliceQp(); + + m_pcReshaper->setSrcReshaped(false); + m_pcReshaper->setRecReshaped(true); + + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) + { +#if JVET_M0483_IBC + m_pcReshaper->preAnalyzerHDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree()); +#else + m_pcReshaper->preAnalyzerHDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree(), m_pcCfg->getIBCMode()); +#endif + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { +#if JVET_M0483_IBC + m_pcReshaper->preAnalyzerSDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree()); +#else + m_pcReshaper->preAnalyzerSDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree(), m_pcCfg->getIBCMode()); +#endif + } + else + { + THROW("Reshaper for other signal currently not defined!"); + } + +#if JVET_M0483_IBC + if (pcSlice->getSliceType() == I_SLICE ) +#else + if (pcSlice->getSliceType() == I_SLICE || (pcSlice->getSliceType() == P_SLICE && m_pcCfg->getIBCMode())) +#endif + { + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) + { + m_pcReshaper->initLUTfromdQPModel(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTableChromaMD(m_pcReshaper->getInvLUT()); + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { + if (m_pcReshaper->getReshapeFlag()) + { + m_pcReshaper->constructReshaperSDR(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight()); + } + } + else + { + THROW("Reshaper for other signal currently not defined!"); + } + + m_pcReshaper->setCTUFlag(false); + + //reshape original signal + if (m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()) + { + pcPic->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getFwdLUT()); + m_pcReshaper->setSrcReshaped(true); + m_pcReshaper->setRecReshaped(true); + } + } + else + { + if (!m_pcReshaper->getReshapeFlag()) + { + m_pcReshaper->setCTUFlag(false); + } + else + m_pcReshaper->setCTUFlag(true); + + m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(false); + + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) + { + m_pcEncLib->getRdCost()->restoreReshapeLumaLevelToWeightTable(); + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { + int modIP = pcPic->getPOC() - pcPic->getPOC() / m_pcCfg->getReshapeCW().rspFpsToIp * m_pcCfg->getReshapeCW().rspFpsToIp; + if (m_pcReshaper->getReshapeFlag() && m_pcCfg->getReshapeCW().rspIntraPeriod == -1 && modIP == 0) // for LDB, update reshaping curve every second + { + m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(true); + m_pcReshaper->constructReshaperSDR(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight()); + } + } + else + { + THROW("Reshaper for other signal currently not defined!"); + } + } + + m_pcReshaper->copySliceReshaperInfo(pcSlice->getReshapeInfo(), m_pcReshaper->getSliceReshaperInfo()); + } + else + { + m_pcReshaper->setCTUFlag(false); + } +#endif + if( encPic ) // now compress (trial encode) the various slice segments (slices, and dependent slices) { @@ -2169,6 +2395,17 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, CodingStructure& cs = *pcPic->cs; pcSlice = pcPic->slices[0]; +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper() && m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()) + { + CHECK((m_pcReshaper->getRecReshaped() == false), "Rec picture is not reshaped!"); + pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getInvLUT()); + m_pcReshaper->setRecReshaped(false); + + pcPic->getOrigBuf().copyFrom(pcPic->getTrueOrigBuf()); + } +#endif + // SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas if( pcSlice->getSPS()->getSAOEnabledFlag() && m_pcCfg->getSaoCtuBoundary() ) { @@ -2194,6 +2431,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, m_pcLoopFilter->loopFilterPic( cs ); +#if JVET_M0147_DMVR + CS::setRefinedMotionField(cs); +#endif DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) ); if( pcSlice->getSPS()->getSAOEnabledFlag() ) @@ -2235,7 +2475,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcPic->slices[s]->setAlfSliceParam( alfSliceParam ); } } - if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && getPrepareLTRef()) + if (pcPic->cs->sps->getUseCompositeRef() && getPrepareLTRef()) { updateCompositeReference(pcSlice, rcListPic, pocCurr); } @@ -2506,10 +2746,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) ); pcPic->reconstructed = true; +#if JVET_M0483_IBC ==0 pcPic->longTerm = false; +#endif m_bFirst = false; m_iNumPicCoded++; - if (!(pcPic->cs->sps->getSpsNext().getUseCompositeRef() && isEncodeLtRef)) + if (!(pcPic->cs->sps->getUseCompositeRef() && isEncodeLtRef)) m_totalCoded ++; /* logging: insert a newline at end of picture period */ @@ -2535,7 +2777,11 @@ void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool const bool useWPSNR = m_pcEncLib->getUseWPSNR(); #endif #if WCG_WPSNR +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif #endif if( m_pcCfg->getDecodeBitstream(0).empty() && m_pcCfg->getDecodeBitstream(1).empty() && !m_pcCfg->useFastForwardToPOC() ) @@ -2574,7 +2820,7 @@ void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool msg( DETAILS,"\n\nB Slices--------------------------------------------------------\n" ); m_gcAnalyzeB.printOut('b', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths); - + #if WCG_WPSNR if (useLumaWPSNR) { @@ -2876,7 +3122,11 @@ uint64_t EncGOP::xFindDistortionPlane(const CPelBuf& pic0, const CPelBuf& pic1, double EncGOP::xFindDistortionPlaneWPSNR(const CPelBuf& pic0, const CPelBuf& pic1, const uint32_t rshift, const CPelBuf& picLuma0, ComponentID compID, const ChromaFormat chfmt ) { +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif if (!useLumaWPSNR) { return 0; @@ -3009,13 +3259,21 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni const CPelUnitBuf& pic = cPicD; CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error"); // const CPelUnitBuf& org = (conversion != IPCOLOURSPACE_UNCHANGED) ? pcPic->getPicYuvTrueOrg()->getBuf() : pcPic->getPicYuvOrg()->getBuf(); +#if JVET_M0427_INLOOP_RESHAPER + const CPelUnitBuf& org = sps.getUseReshaper() ? pcPic->getTrueOrigBuf() : pcPic->getOrigBuf(); +#else const CPelUnitBuf& org = pcPic->getOrigBuf(); +#endif #if ENABLE_QPA const bool useWPSNR = m_pcEncLib->getUseWPSNR(); #endif double dPSNR[MAX_NUM_COMPONENT]; #if WCG_WPSNR +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif double dPSNRWeighted[MAX_NUM_COMPONENT]; double MSEyuvframeWeighted[MAX_NUM_COMPONENT]; #endif diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index ca212145176f7fcf46f251e54abe39d7bfd6de05..e2c11c170105b077021b497b661030ac06930798 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -47,6 +47,9 @@ #include "CommonLib/NAL.h" #include "EncSampleAdaptiveOffset.h" #include "EncAdaptiveLoopFilter.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif #include "EncSlice.h" #include "VLCWriter.h" #include "CABACWriter.h" @@ -139,6 +142,9 @@ private: //--Adaptive Loop filter EncSampleAdaptiveOffset* m_pcSAO; EncAdaptiveLoopFilter* m_pcALF; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshaper; +#endif RateCtrl* m_pcRateCtrl; // indicate sequence first bool m_bSeqFirst; diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 56f49fc8620590b9f275d78e319747df63f7f826..a418140860f7cc143c41f56887269fb1213a1488 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -84,9 +84,9 @@ void EncLib::create () { // initialize global variables initROM(); - - - +#if JVET_M0253_HASH_ME + TComHash::initBlockSizeToIndex(); +#endif m_iPOCLast = m_compositeRefEnabled ? -2 : -1; // create processing unit classes m_cGOPEncoder. create( ); @@ -136,6 +136,12 @@ void EncLib::create () m_cEncALF.create( getSourceWidth(), getSourceHeight(), m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, m_bitDepth, m_inputBitDepth ); } +#if JVET_M0427_INLOOP_RESHAPER + if (m_lumaReshapeEnable) + { + m_cReshaper.createEnc( getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight, m_bitDepth[COMPONENT_Y]); + } +#endif if ( m_RCEnableRateControl ) { m_cRateCtrl.init(m_framesToBeEncoded, m_RCTargetBitrate, (int)((double)m_iFrameRate / m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_iSourceWidth, m_iSourceHeight, @@ -165,6 +171,9 @@ void EncLib::destroy () m_cEncSAO. destroy(); m_cLoopFilter. destroy(); m_cRateCtrl. destroy(); +#if JVET_M0427_INLOOP_RESHAPER + m_cReshaper. destroy(); +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { @@ -215,7 +224,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) omp_set_nested( true ); #endif - if (sps0.getSpsNext().getUseCompositeRef()) + if (sps0.getUseCompositeRef()) { sps0.setLongTermRefsPresent(true); } @@ -246,7 +255,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) xInitPPS(pps1, sps0); } #endif - if (sps0.getSpsNext().getUseCompositeRef()) + if (sps0.getUseCompositeRef()) { PPS &pps2 = *(m_ppsMap.allocatePS(2)); xInitPPS(pps2, sps0); @@ -318,13 +327,21 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) &m_cTrQuant, &m_cRdCost, cabacEstimator, - getCtxCache(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth ); + getCtxCache(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , &m_cReshaper +#endif + ); m_cInterSearch.init( this, &m_cTrQuant, m_iSearchRange, m_bipredSearchRange, m_motionEstimationSearchMethod, - m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost, cabacEstimator, getCtxCache() ); + m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost, cabacEstimator, getCtxCache() +#if JVET_M0427_INLOOP_RESHAPER + , &m_cReshaper +#endif + ); // link temporary buffets from intra search with inter search to avoid unneccessary memory overhead m_cInterSearch.setTempBuffers( m_cIntraSearch.getSplitCSBuf(), m_cIntraSearch.getFullCSBuf(), m_cIntraSearch.getSaveCSBuf() ); @@ -348,7 +365,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) #if ENABLE_WPP_PARALLELISM m_entropyCodingSyncContextStateVec.resize( pps0.pcv->heightInCtus ); #endif - if (sps0.getSpsNext().getUseCompositeRef()) + if (sps0.getUseCompositeRef()) { Picture *picBg = new Picture; picBg->create(sps0.getChromaFormatIdc(), Size(sps0.getPicWidthInLumaSamples(), sps0.getPicHeightInLumaSamples()), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false); @@ -551,6 +568,9 @@ void EncLib::encode( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYuvTru const SPS *pSPS=m_spsMap.getPS(pPPS->getSPSId()); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg ); +#if JVET_M0427_INLOOP_RESHAPER + pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL).swap(*cPicYuvTrueOrg); +#endif pcPicCurr->finalInit( *pSPS, *pPPS ); } @@ -756,6 +776,9 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict rpcPic->setBorderExtension( false ); rpcPic->reconstructed = false; rpcPic->referenced = true; +#if JVET_M0253_HASH_ME + rpcPic->getHashMap()->clearAll(); +#endif m_iPOCLast += (m_compositeRefEnabled ? 2 : 1); m_iNumPicRcvd++; @@ -798,9 +821,17 @@ void EncLib::xInitSPS(SPS &sps) sps.setNoAmvrConstraintFlag(!m_bNoAmvrConstraintFlag); sps.setNoAffineMotionConstraintFlag(!m_Affine); #if JVET_M0464_UNI_MTS +#if JVET_M0303_IMPLICIT_MTS + sps.setNoMtsConstraintFlag((m_IntraMTS || m_InterMTS || m_ImplicitMTS) ? false : true); +#else sps.setNoMtsConstraintFlag((m_IntraMTS || m_InterMTS) ? false : true); +#endif +#else +#if JVET_M0303_IMPLICIT_MTS + sps.setNoMtsConstraintFlag((m_IntraEMT || m_InterEMT || m_ImplicitMTS) ? false : true); #else sps.setNoMtsConstraintFlag((m_IntraEMT || m_InterEMT) ? false : true); +#endif #endif sps.setNoLadfConstraintFlag(!m_LadfEnabled); sps.setNoDepQuantConstraintFlag(!m_DepQuantEnabledFlag); @@ -844,60 +875,79 @@ void EncLib::xInitSPS(SPS &sps) sps.setChromaFormatIdc ( m_chromaFormatIDC ); sps.setLog2DiffMaxMinCodingBlockSize(m_log2DiffMaxMinCodingBlockSize); - sps.getSpsNext().setNextToolsEnabled ( m_profile == Profile::NEXT ); sps.setCTUSize ( m_CTUSize ); sps.setSplitConsOverrideEnabledFlag ( m_useSplitConsOverride ); sps.setMinQTSizes ( m_uiMinQT ); - sps.getSpsNext().setUseLargeCTU ( m_LargeCTU ); sps.setMaxBTDepth ( m_uiMaxBTDepth, m_uiMaxBTDepthI, m_uiMaxBTDepthIChroma ); sps.setUseDualITree ( m_dualITree ); sps.setSBTMVPEnabledFlag ( m_SubPuMvpMode ); - sps.getSpsNext().setImvMode ( ImvMode(m_ImvMode) ); - sps.getSpsNext().setUseIMV ( m_ImvMode != IMV_OFF ); + sps.setAMVREnabledFlag ( m_ImvMode != IMV_OFF ); sps.setBDOFEnabledFlag ( m_BIO ); - sps.getSpsNext().setUseAffine ( m_Affine ); - sps.getSpsNext().setUseAffineType ( m_AffineType ); - sps.getSpsNext().setDisableMotCompress ( m_DisableMotionCompression ); - sps.getSpsNext().setMTTMode ( m_MTTMode ); - sps.getSpsNext().setUseLMChroma ( m_LMChroma ? true : false ); + sps.setUseAffine ( m_Affine ); + sps.setUseAffineType ( m_AffineType ); + sps.setUseLMChroma ( m_LMChroma ? true : false ); #if JVET_M0142_CCLM_COLLOCATED_CHROMA - sps.getSpsNext().setCclmCollocatedChromaFlag( m_cclmCollocatedChromaFlag ); -#endif -#if ENABLE_WPP_PARALLELISM - sps.getSpsNext().setUseNextDQP ( m_AltDQPCoding ); + sps.setCclmCollocatedChromaFlag( m_cclmCollocatedChromaFlag ); #endif #if JVET_M0464_UNI_MTS - sps.getSpsNext().setUseIntraMTS ( m_IntraMTS ); - sps.getSpsNext().setUseInterMTS ( m_InterMTS ); +#if JVET_M0303_IMPLICIT_MTS + sps.setUseMTS ( m_IntraMTS || m_InterMTS || m_ImplicitMTS ); +#endif + sps.setUseIntraMTS ( m_IntraMTS ); + sps.setUseInterMTS ( m_InterMTS ); #else - sps.getSpsNext().setUseIntraEMT ( m_IntraEMT ); - sps.getSpsNext().setUseInterEMT ( m_InterEMT ); +#if JVET_M0303_IMPLICIT_MTS + sps.setUseMTS ( m_IntraEMT || m_InterEMT || m_ImplicitMTS ); +#endif + sps.setUseIntraEMT ( m_IntraEMT ); + sps.setUseInterEMT ( m_InterEMT ); #endif - sps.getSpsNext().setUseCompositeRef ( m_compositeRefEnabled ); - sps.getSpsNext().setUseGBi ( m_GBi ); +#if JVET_M0140_SBT + sps.setUseSBT ( m_SBT ); + if( sps.getUseSBT() ) + { + sps.setMaxSbtSize ( m_iSourceWidth >= 1920 ? 64 : 32 ); + } +#endif + sps.setUseCompositeRef ( m_compositeRefEnabled ); + sps.setUseGBi ( m_GBi ); #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - sps.getSpsNext().setLadfEnabled ( m_LadfEnabled ); + sps.setLadfEnabled ( m_LadfEnabled ); if ( m_LadfEnabled ) { - sps.getSpsNext().setLadfNumIntervals ( m_LadfNumIntervals ); + sps.setLadfNumIntervals ( m_LadfNumIntervals ); for ( int k = 0; k < m_LadfNumIntervals; k++ ) { - sps.getSpsNext().setLadfQpOffset( m_LadfQpOffset[k], k ); - sps.getSpsNext().setLadfIntervalLowerBound( m_LadfIntervalLowerBound[k], k ); + sps.setLadfQpOffset( m_LadfQpOffset[k], k ); + sps.setLadfIntervalLowerBound( m_LadfIntervalLowerBound[k], k ); } CHECK( m_LadfIntervalLowerBound[0] != 0, "abnormal value set to LadfIntervalLowerBound[0]" ); } #endif - sps.getSpsNext().setUseMHIntra ( m_MHIntra ); - sps.getSpsNext().setUseTriangle ( m_Triangle ); - - sps.getSpsNext().setIBCMode ( m_IBCMode ); + sps.setUseMHIntra ( m_MHIntra ); + sps.setUseTriangle ( m_Triangle ); +#if JVET_M0255_FRACMMVD_SWITCH + sps.setDisFracMmvdEnabledFlag ( m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + sps.setAffineAmvrEnabledFlag ( m_AffineAmvr ); +#endif +#if JVET_M0147_DMVR + sps.setUseDMVR ( m_DMVR ); +#endif +#if JVET_M0483_IBC + sps.setIBCFlag ( m_IBCMode); +#else + sps.setIBCMode (m_IBCMode); +#endif sps.setWrapAroundEnabledFlag ( m_wrapAround ); sps.setWrapAroundOffset ( m_wrapAroundOffset ); // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + sps.setUseReshaper ( m_lumaReshapeEnable ); +#endif int minCUSize = sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize(); int log2MinCUSize = 0; while(minCUSize > 1) @@ -1324,7 +1374,7 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setSliceChromaQpFlag(bChromaDeltaQPEnabled); #endif if ( - !pps.getSliceChromaQpFlag() && sps.getUseDualITree() + !pps.getSliceChromaQpFlag() && sps.getUseDualITree() && (getChromaFormatIdc() != CHROMA_400)) { pps.setSliceChromaQpFlag(m_chromaCbQpOffsetDualTree != 0 || m_chromaCrQpOffsetDualTree != 0); @@ -1395,11 +1445,13 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) } } CHECK(!(bestPos <= 15), "Unspecified error"); - if (sps.getSpsNext().getIBCMode()) +#if JVET_M0483_IBC==0 + if (sps.getIBCMode()) { pps.setNumRefIdxL0DefaultActive(bestPos + 1); } else +#endif pps.setNumRefIdxL0DefaultActive(bestPos); pps.setNumRefIdxL1DefaultActive(bestPos); pps.setTransquantBypassEnabledFlag(getTransquantBypassEnabledFlag()); diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index 07109efcd1b51da2883577204cfb82538855da4c..f966d8277a5ac70b0fda79da0cb912d01994c61d 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -53,6 +53,9 @@ #include "InterSearch.h" #include "IntraSearch.h" #include "EncSampleAdaptiveOffset.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif #include "EncAdaptiveLoopFilter.h" #include "RateCtrl.h" @@ -98,6 +101,10 @@ private: CABACEncoder m_CABACEncoder; #endif +#if JVET_M0427_INLOOP_RESHAPER + EncReshape m_cReshaper; ///< reshaper class +#endif + // processing unit EncGOP m_cGOPEncoder; ///< GOP encoder EncSlice m_cSliceEncoder; ///< slice encoder @@ -219,6 +226,9 @@ public: int getNumCuEncStacks() const { return m_numCuEncStacks; } #endif +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* getReshaper() { return &m_cReshaper; } +#endif // ------------------------------------------------------------------------------------------------------------------- // encoder function // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index c9a6863301a9e2c439e7fafdb209a4f9ce99ee2d..9fc58805e972734397b41227ca75408626c3d97d 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -191,7 +191,7 @@ void EncModeCtrl::xGetMinMaxQP( int& minQP, int& maxQP, const CodingStructure& c if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && (!CS::isDualITree (cs) || isLuma (partitioner.chType))) { - minQP = Clip3 (-sps.getQpBDOffset (CHANNEL_TYPE_LUMA), MAX_QP, baseQP - m_lumaQPOffset); + minQP = Clip3( -sps.getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, baseQP - m_lumaQPOffset ); maxQP = minQP; } #endif @@ -251,7 +251,7 @@ int EncModeCtrl::calculateLumaDQP( const CPelBuf& rcOrg ) #endif { // Use average luma value - avg = (double) rcOrg.mean(); + avg = (double) rcOrg.computeAvg(); } #if !WCG_EXT else @@ -505,6 +505,106 @@ bool CacheBlkInfoCtrl::getMv( const UnitArea& area, const RefPicList refPicList, return m_codedCUInfo[idx1][idx2][idx3][idx4]->validMv[refPicList][iRefIdx]; } +#if JVET_M0140_SBT +void SaveLoadEncInfoSbt::init( const Slice &slice ) +{ + m_sliceSbt = &slice; +} + +void SaveLoadEncInfoSbt::create() +{ + int numSizeIdx = gp_sizeIdxInfo->idxFrom( SBT_MAX_SIZE ) - MIN_CU_LOG2 + 1; + int numPosIdx = MAX_CU_SIZE >> MIN_CU_LOG2; + + m_saveLoadSbt = new SaveLoadStructSbt***[numPosIdx]; + + for( int xIdx = 0; xIdx < numPosIdx; xIdx++ ) + { + m_saveLoadSbt[xIdx] = new SaveLoadStructSbt**[numPosIdx]; + for( int yIdx = 0; yIdx < numPosIdx; yIdx++ ) + { + m_saveLoadSbt[xIdx][yIdx] = new SaveLoadStructSbt*[numSizeIdx]; + for( int wIdx = 0; wIdx < numSizeIdx; wIdx++ ) + { + m_saveLoadSbt[xIdx][yIdx][wIdx] = new SaveLoadStructSbt[numSizeIdx]; + } + } + } +} + +void SaveLoadEncInfoSbt::destroy() +{ + int numSizeIdx = gp_sizeIdxInfo->idxFrom( SBT_MAX_SIZE ) - MIN_CU_LOG2 + 1; + int numPosIdx = MAX_CU_SIZE >> MIN_CU_LOG2; + + for( int xIdx = 0; xIdx < numPosIdx; xIdx++ ) + { + for( int yIdx = 0; yIdx < numPosIdx; yIdx++ ) + { + for( int wIdx = 0; wIdx < numSizeIdx; wIdx++ ) + { + delete[] m_saveLoadSbt[xIdx][yIdx][wIdx]; + } + delete[] m_saveLoadSbt[xIdx][yIdx]; + } + delete[] m_saveLoadSbt[xIdx]; + } + delete[] m_saveLoadSbt; +} + +uint16_t SaveLoadEncInfoSbt::findBestSbt( const UnitArea& area, const uint32_t curPuSse ) +{ + unsigned idx1, idx2, idx3, idx4; + getAreaIdx( area.Y(), *m_sliceSbt->getPPS()->pcv, idx1, idx2, idx3, idx4 ); + SaveLoadStructSbt* pSbtSave = &m_saveLoadSbt[idx1][idx2][idx3 - MIN_CU_LOG2][idx4 - MIN_CU_LOG2]; + + for( int i = 0; i < pSbtSave->numPuInfoStored; i++ ) + { + if( curPuSse == pSbtSave->puSse[i] ) + { + return pSbtSave->puSbt[i] + ( pSbtSave->puTrs[i] << 8 ); + } + } + + return MAX_UCHAR + ( MAX_UCHAR << 8 ); +} + +bool SaveLoadEncInfoSbt::saveBestSbt( const UnitArea& area, const uint32_t curPuSse, const uint8_t curPuSbt, const uint8_t curPuTrs ) +{ + unsigned idx1, idx2, idx3, idx4; + getAreaIdx( area.Y(), *m_sliceSbt->getPPS()->pcv, idx1, idx2, idx3, idx4 ); + SaveLoadStructSbt* pSbtSave = &m_saveLoadSbt[idx1][idx2][idx3 - MIN_CU_LOG2][idx4 - MIN_CU_LOG2]; + + if( pSbtSave->numPuInfoStored == SBT_NUM_SL ) + { + return false; + } + + pSbtSave->puSse[pSbtSave->numPuInfoStored] = curPuSse; + pSbtSave->puSbt[pSbtSave->numPuInfoStored] = curPuSbt; + pSbtSave->puTrs[pSbtSave->numPuInfoStored] = curPuTrs; + pSbtSave->numPuInfoStored++; + return true; +} + +void SaveLoadEncInfoSbt::resetSaveloadSbt( int maxSbtSize ) +{ + int numSizeIdx = gp_sizeIdxInfo->idxFrom( maxSbtSize ) - MIN_CU_LOG2 + 1; + int numPosIdx = MAX_CU_SIZE >> MIN_CU_LOG2; + + for( int xIdx = 0; xIdx < numPosIdx; xIdx++ ) + { + for( int yIdx = 0; yIdx < numPosIdx; yIdx++ ) + { + for( int wIdx = 0; wIdx < numSizeIdx; wIdx++ ) + { + memset( m_saveLoadSbt[xIdx][yIdx][wIdx], 0, numSizeIdx * sizeof( SaveLoadStructSbt ) ); + } + } + } +} +#endif + bool CacheBlkInfoCtrl::getInter(const UnitArea& area) { unsigned idx1, idx2, idx3, idx4; @@ -557,7 +657,7 @@ static bool isTheSameNbHood( const CodingUnit &cu, const CodingStructure& cs, co bool sharedListReuseMode = true; if( pu.mergeFlag == true && - cu.affine == false && + cu.affine == false && cu.predMode == MODE_INTER ) { @@ -628,9 +728,17 @@ void BestEncInfoCache::create( const ChromaFormat chFmt ) const UnitArea area( chFmt, Area( 0, 0, w, h ) ); - m_bestEncInfo[x][y][wIdx][hIdx]->cu.UnitArea::operator=( area ); - m_bestEncInfo[x][y][wIdx][hIdx]->pu.UnitArea::operator=( area ); - m_bestEncInfo[x][y][wIdx][hIdx]->tu.UnitArea::operator=( area ); + new ( &m_bestEncInfo[x][y][wIdx][hIdx]->cu ) CodingUnit ( area ); + new ( &m_bestEncInfo[x][y][wIdx][hIdx]->pu ) PredictionUnit( area ); +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + m_bestEncInfo[x][y][wIdx][hIdx]->numTus = 0; + for( int i = 0; i < MAX_NUM_TUS; i++ ) + { + new ( &m_bestEncInfo[x][y][wIdx][hIdx]->tus[i] ) TransformUnit( area ); + } +#else + new ( &m_bestEncInfo[x][y][wIdx][hIdx]->tu ) TransformUnit( area ); +#endif m_bestEncInfo[x][y][wIdx][hIdx]->poc = -1; m_bestEncInfo[x][y][wIdx][hIdx]->testMode = EncTestMode(); @@ -689,14 +797,14 @@ void BestEncInfoCache::init( const Slice &slice ) m_slice_bencinf = &slice; if( isInitialized ) return; - + const unsigned numPos = MAX_CU_SIZE >> MIN_CU_LOG2; m_numWidths = gp_sizeIdxInfo->numWidths(); m_numHeights = gp_sizeIdxInfo->numHeights(); size_t numCoeff = 0; - + for( unsigned x = 0; x < numPos; x++ ) { for( unsigned y = 0; y < numPos; y++ ) @@ -717,8 +825,13 @@ void BestEncInfoCache::init( const Slice &slice ) } } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + m_pCoeff = new TCoeff[numCoeff*MAX_NUM_TUS]; + m_pPcmBuf = new Pel [numCoeff*MAX_NUM_TUS]; +#else m_pCoeff = new TCoeff[numCoeff]; m_pPcmBuf = new Pel [numCoeff]; +#endif TCoeff *coeffPtr = m_pCoeff; Pel *pcmPtr = m_pPcmBuf; @@ -738,6 +851,22 @@ void BestEncInfoCache::init( const Slice &slice ) TCoeff *coeff[MAX_NUM_TBLOCKS] = { 0, }; Pel *pcmbf[MAX_NUM_TBLOCKS] = { 0, }; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + for( int i = 0; i < MAX_NUM_TUS; i++ ) + { + TransformUnit &tu = m_bestEncInfo[x][y][wIdx][hIdx]->tus[i]; + const UnitArea &area = tu; + + for( int i = 0; i < area.blocks.size(); i++ ) + { + coeff[i] = coeffPtr; coeffPtr += area.blocks[i].area(); + pcmbf[i] = pcmPtr; pcmPtr += area.blocks[i].area(); + } + + tu.cs = &m_dummyCS; + tu.init(coeff, pcmbf); + } +#else const UnitArea &area = m_bestEncInfo[x][y][wIdx][hIdx]->tu; for( int i = 0; i < area.blocks.size(); i++ ) @@ -748,6 +877,7 @@ void BestEncInfoCache::init( const Slice &slice ) m_bestEncInfo[x][y][wIdx][hIdx]->tu.cs = &m_dummyCS; m_bestEncInfo[x][y][wIdx][hIdx]->tu.init( coeff, pcmbf ); +#endif } } } @@ -757,7 +887,11 @@ void BestEncInfoCache::init( const Slice &slice ) bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const Partitioner& partitioner ) { +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + if( cs.cus.size() != 1 || cs.pus.size() != 1 ) +#else if( cs.cus.size() != 1 || cs.tus.size() != 1 || cs.pus.size() != 1 ) +#endif { return false; } @@ -770,13 +904,32 @@ bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const Partitioner& encInfo.poc = cs.picture->poc; encInfo.cu.repositionTo( *cs.cus.front() ); encInfo.pu.repositionTo( *cs.pus.front() ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS encInfo.tu.repositionTo( *cs.tus.front() ); +#endif encInfo.cu = *cs.cus.front(); encInfo.pu = *cs.pus.front(); +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + int tuIdx = 0; + for( auto tu : cs.tus ) + { + encInfo.tus[tuIdx].repositionTo( *tu ); + encInfo.tus[tuIdx].resizeTo( *tu ); + for( auto &blk : tu->blocks ) + { + if( blk.valid() ) + encInfo.tus[tuIdx].copyComponentFrom( *tu, blk.compID ); + } + tuIdx++; + } + CHECKD( cs.tus.size() > MAX_NUM_TUS, "Exceeding tus array boundaries" ); + encInfo.numTus = cs.tus.size(); +#else for( auto &blk : cs.tus.front()->blocks ) { if( blk.valid() ) encInfo.tu.copyComponentFrom( *cs.tus.front(), blk.compID ); } +#endif encInfo.testMode = getCSEncMode( cs ); return true; @@ -795,8 +948,13 @@ bool BestEncInfoCache::isValid( const CodingStructure& cs, const Partitioner& pa #if JVET_M0170_MRG_SHARELIST , encInfo.pu, (cs.picture->Y().width), (cs.picture->Y().height) #endif -) +) +#if JVET_M0483_IBC + || CU::isIBC(encInfo.cu) +#else || encInfo.cu.ibc +#endif + || partitioner.currDepth <= cs.pps->getMaxCuDQPDepth() || cs.currQP[partitioner.chType] != encInfo.cu.qp ) { return false; @@ -814,29 +972,48 @@ bool BestEncInfoCache::setCsFrom( CodingStructure& cs, EncTestMode& testMode, co BestEncodingInfo& encInfo = *m_bestEncInfo[idx1][idx2][idx3][idx4]; - if( cs.picture->poc != encInfo.poc || CS::getArea( cs, cs.area, partitioner.chType ) != CS::getArea( cs, encInfo.cu, partitioner.chType ) || !isTheSameNbHood( encInfo.cu, cs, partitioner + if( cs.picture->poc != encInfo.poc || CS::getArea( cs, cs.area, partitioner.chType ) != CS::getArea( cs, encInfo.cu, partitioner.chType ) || !isTheSameNbHood( encInfo.cu, cs, partitioner #if JVET_M0170_MRG_SHARELIST , encInfo.pu, (cs.picture->Y().width), (cs.picture->Y().height) #endif -) ) + ) + || partitioner.currDepth <= cs.pps->getMaxCuDQPDepth() || cs.currQP[partitioner.chType] != encInfo.cu.qp + ) { return false; } CodingUnit &cu = cs.addCU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); PredictionUnit &pu = cs.addPU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS TransformUnit &tu = cs.addTU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); +#endif cu .repositionTo( encInfo.cu ); pu .repositionTo( encInfo.pu ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS tu .repositionTo( encInfo.tu ); +#endif cu = encInfo.cu; pu = encInfo.pu; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + CHECKD( !( encInfo.numTus > 0 ), "Empty tus array" ); + for( int i = 0; i < encInfo.numTus; i++ ) + { + TransformUnit &tu = cs.addTU( encInfo.tus[i], partitioner.chType ); + + for( auto &blk : tu.blocks ) + { + if( blk.valid() ) tu.copyComponentFrom( encInfo.tus[i], blk.compID ); + } + } +#else for( auto &blk : tu.blocks ) { if( blk.valid() ) tu.copyComponentFrom( encInfo.tu, blk.compID ); } +#endif testMode = encInfo.testMode; @@ -873,12 +1050,18 @@ void EncModeCtrlMTnoRQT::create( const EncCfg& cfg ) { CacheBlkInfoCtrl::create(); BestEncInfoCache::create( cfg.getChromaFormatIdc() ); +#if JVET_M0140_SBT + SaveLoadEncInfoSbt::create(); +#endif } void EncModeCtrlMTnoRQT::destroy() { CacheBlkInfoCtrl::destroy(); BestEncInfoCache::destroy(); +#if JVET_M0140_SBT + SaveLoadEncInfoSbt::destroy(); +#endif } #endif @@ -888,6 +1071,9 @@ void EncModeCtrlMTnoRQT::initCTUEncoding( const Slice &slice ) #if REUSE_CU_RESULTS BestEncInfoCache::init( slice ); #endif +#if JVET_M0140_SBT + SaveLoadEncInfoSbt::init( slice ); +#endif CHECK( !m_ComprCUCtxList.empty(), "Mode list is not empty at the beginning of a CTU" ); @@ -968,8 +1154,8 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru cuECtx.set( BEST_HORZ_SPLIT_COST, MAX_DOUBLE ); cuECtx.set( BEST_TRIH_SPLIT_COST, MAX_DOUBLE ); cuECtx.set( BEST_TRIV_SPLIT_COST, MAX_DOUBLE ); - cuECtx.set( DO_TRIH_SPLIT, cs.sps->getSpsNext().getMTTMode() & 1 ); - cuECtx.set( DO_TRIV_SPLIT, cs.sps->getSpsNext().getMTTMode() & 1 ); + cuECtx.set( DO_TRIH_SPLIT, 1 ); + cuECtx.set( DO_TRIV_SPLIT, 1 ); cuECtx.set( BEST_IMV_COST, MAX_DOUBLE * .5 ); cuECtx.set( BEST_NO_IMV_COST, MAX_DOUBLE * .5 ); cuECtx.set( QT_BEFORE_BT, qtBeforeBt ); @@ -983,7 +1169,7 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru { if (m_pcEncCfg->getUseAdaptiveQP()) { - baseQP = Clip3(-cs.sps->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, baseQP + xComputeDQP (cs, partitioner)); + baseQP = Clip3(-cs.sps->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, baseQP + xComputeDQP(cs, partitioner)); } #if ENABLE_QPA_SUB_CTU else if (m_pcEncCfg->getUsePerceptQPA() && !m_pcEncCfg->getUseRateCtrl() && cs.pps->getUseDQP() && cs.pps->getMaxCuDQPDepth() > 0) @@ -1020,7 +1206,7 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru switch (ibcLumaCoverage) { case IBC_LUMA_COVERAGE_FULL: - // check IBC + // check IBC break; case IBC_LUMA_COVERAGE_PARTIAL: // do not check IBC @@ -1139,7 +1325,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru m_ComprCUCtxList.back().testModes.push_back( { ETM_IPCM, ETO_STANDARD, qp, lossless } ); m_ComprCUCtxList.back().testModes.push_back( { ETM_INTRA, ETO_STANDARD, qp, lossless } ); // add ibc mode to intra path - if (cs.sps->getSpsNext().getIBCMode() && checkIbc ) +#if JVET_M0483_IBC + if (cs.sps->getIBCFlag() && checkIbc) +#else + if (cs.sps->getIBCMode() && checkIbc ) +#endif { m_ComprCUCtxList.back().testModes.push_back({ ETM_IBC, ETO_STANDARD, qp, lossless }); if (cs.chType == CHANNEL_TYPE_LUMA) @@ -1156,25 +1346,25 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru { const int qp = std::max( qpLoop, lowestQP ); const bool lossless = useLossless && qpLoop == minQP; - +#if JVET_M0246_AFFINE_AMVR + if( m_pcEncCfg->getIMV() || m_pcEncCfg->getUseAffineAmvr() ) +#else if( m_pcEncCfg->getIMV() ) +#endif { - if( m_pcEncCfg->getIMV() == IMV_4PEL ) - { - int imv = m_pcEncCfg->getIMV4PelFast() ? 3 : 2; - m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, EncTestModeOpts( imv << ETO_IMV_SHIFT ), qp, lossless } ); - } + int imv = m_pcEncCfg->getIMV4PelFast() ? 3 : 2; + m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, EncTestModeOpts( imv << ETO_IMV_SHIFT ), qp, lossless } ); m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, EncTestModeOpts( 1 << ETO_IMV_SHIFT ), qp, lossless } ); } // add inter modes if( m_pcEncCfg->getUseEarlySkipDetection() ) { - if( cs.sps->getSpsNext().getUseTriangle() && cs.slice->isInterB() ) + if( cs.sps->getUseTriangle() && cs.slice->isInterB() ) { m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, ETO_STANDARD, qp, lossless } ); } m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP, ETO_STANDARD, qp, lossless } ); - if ( cs.sps->getSpsNext().getUseAffine() || cs.sps->getSBTMVPEnabledFlag() ) + if ( cs.sps->getUseAffine() || cs.sps->getSBTMVPEnabledFlag() ) { m_ComprCUCtxList.back().testModes.push_back( { ETM_AFFINE, ETO_STANDARD, qp, lossless } ); } @@ -1183,16 +1373,25 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru else { m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, ETO_STANDARD, qp, lossless } ); - if( cs.sps->getSpsNext().getUseTriangle() && cs.slice->isInterB() ) + if( cs.sps->getUseTriangle() && cs.slice->isInterB() ) { m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, ETO_STANDARD, qp, lossless } ); } m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP, ETO_STANDARD, qp, lossless } ); - if ( cs.sps->getSpsNext().getUseAffine() || cs.sps->getSBTMVPEnabledFlag() ) + if ( cs.sps->getUseAffine() || cs.sps->getSBTMVPEnabledFlag() ) { m_ComprCUCtxList.back().testModes.push_back( { ETM_AFFINE, ETO_STANDARD, qp, lossless } ); } } +#if JVET_M0253_HASH_ME + if (m_pcEncCfg->getUseHashME()) + { + if ((cs.area.lwidth() == cs.area.lheight() && cs.area.lwidth() <= 64 && cs.area.lwidth() >= 4) || (cs.area.lwidth() == 4 && cs.area.lheight() == 8) || (cs.area.lwidth() == 8 && cs.area.lheight() == 4)) + { + m_ComprCUCtxList.back().testModes.push_back({ ETM_HASH_INTER, ETO_STANDARD, qp, lossless }); + } + } +#endif } } @@ -1216,6 +1415,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt ComprCUCtx& cuECtx = m_ComprCUCtxList.back(); // Fast checks, partitioning depended +#if JVET_M0253_HASH_ME + if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_AFFINE && encTestmode.type != ETM_MERGE_TRIANGLE) + { + return false; + } +#endif // if early skip detected, skip all modes checking but the splits if( cuECtx.earlySkip && m_pcEncCfg->getUseEarlySkipDetection() && !isModeSplit( encTestmode ) && !( isModeInter( encTestmode ) ) ) @@ -1297,18 +1502,30 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt return false; } +#if JVET_M0483_IBC + if (m_pcEncCfg->getUsePbIntraFast() && (!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && !interHadActive(cuECtx) && cuECtx.bestCU && !CU::isIntra(*cuECtx.bestCU)) +#else if( m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && !interHadActive( cuECtx ) && cuECtx.bestCU && CU::isInter( *cuECtx.bestCU ) ) +#endif { return false; } // INTRA MODES - if (cs.sps->getSpsNext().getIBCMode() && !cuECtx.bestTU) +#if JVET_M0483_IBC + if (cs.sps->getIBCFlag() && !cuECtx.bestTU) +#else + if (cs.sps->getIBCMode() && !cuECtx.bestTU) +#endif return true; CHECK( !slice.isIntra() && !cuECtx.bestTU, "No possible non-intra encoding for a P- or B-slice found" ); - if( !( slice.isIRAP() || bestMode.type == ETM_INTRA || - ( ( !m_pcEncCfg->getDisableIntraPUsInInterSlices() ) && !relatedCU.isInter && ( + if( !( slice.isIRAP() || bestMode.type == ETM_INTRA || +#if JVET_M0483_IBC + ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (!relatedCU.isInter || !relatedCU.isIBC) && ( +#else + ( ( !m_pcEncCfg->getDisableIntraPUsInInterSlices() ) && !relatedCU.isInter && ( +#endif ( cuECtx.bestTU->cbf[0] != 0 ) || ( ( numComp > COMPONENT_Cb ) && cuECtx.bestTU->cbf[1] != 0 ) || ( ( numComp > COMPONENT_Cr ) && cuECtx.bestTU->cbf[2] != 0 ) // avoid very complex intra if it is unlikely @@ -1330,7 +1547,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt if( !cs.slice->isIRAP() && m_pcEncCfg->getUsePbIntraFast() ) { CodingUnit* bestCU = cuECtx.bestCU; +#if JVET_M0483_IBC + if (bestCU && !CU::isIntra(*bestCU)) +#else if( bestCU && CU::isInter( *bestCU ) ) +#endif { DistParam distParam; const bool useHad = !bestCU->transQuantBypass; @@ -1361,7 +1582,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt else if (encTestmode.type == ETM_IBC || encTestmode.type == ETM_IBC_MERGE) { // IBC MODES - return sps.getSpsNext().getIBCMode() && width <= IBC_MAX_CAND_SIZE && partitioner.currArea().lumaSize().height <= IBC_MAX_CAND_SIZE; +#if JVET_M0483_IBC + return sps.getIBCFlag() && width <= IBC_MAX_CAND_SIZE && partitioner.currArea().lumaSize().height <= IBC_MAX_CAND_SIZE; +#else + return sps.getIBCMode() && width <= IBC_MAX_CAND_SIZE && partitioner.currArea().lumaSize().height <= IBC_MAX_CAND_SIZE; +#endif } else if( isModeInter( encTestmode ) ) { @@ -1401,6 +1626,9 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt if (imvOpt == 3 && cuECtx.get<double>(BEST_NO_IMV_COST) * 1.06 < cuECtx.get<double>(BEST_IMV_COST)) { +#if JVET_M0246_AFFINE_AMVR + if ( !m_pcEncCfg->getUseAffineAmvr() ) +#endif return false; } } @@ -1411,7 +1639,7 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt return false; } if( encTestmode.type == ETM_MERGE_TRIANGLE && ( partitioner.currArea().lumaSize().area() < TRIANGLE_MIN_SIZE || relatedCU.isIntra ) ) - { + { return false; } return true; @@ -1424,7 +1652,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt ////////////////////////////////////////////////////////////////////////// int skipScore = 0; +#if JVET_M0483_IBC + if ((!slice.isIntra() || slice.getSPS()->getIBCFlag()) && cuECtx.get<bool>(IS_BEST_NOSPLIT_SKIP)) +#else if( !slice.isIntra() && cuECtx.get<bool>( IS_BEST_NOSPLIT_SKIP ) ) +#endif { for( int i = 2; i < m_ComprCUCtxList.size(); i++ ) { @@ -1519,6 +1751,15 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt const CodingUnit *cuBR = bestCS->cus.back(); unsigned height = partitioner.currArea().lumaSize().height; +#if JVET_M0483_IBC + if (bestCU && ((bestCU->btDepth == 0 && maxBTD >= ((slice.isIntra() && !slice.getSPS()->getIBCFlag()) ? 3 : 2)) + || (bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ((slice.isIntra() && !slice.getSPS()->getIBCFlag()) ? 4 : 3))) + && (width <= MAX_TU_SIZE_FOR_PROFILE && height <= MAX_TU_SIZE_FOR_PROFILE) + && cuECtx.get<bool>(DID_HORZ_SPLIT) && cuECtx.get<bool>(DID_VERT_SPLIT)) + { + return false; + } +#else if( bestCU && ( ( bestCU->btDepth == 0 && maxBTD >= ( slice.isIntra() ? 3 : 2 ) ) || ( bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ( slice.isIntra() ? 4 : 3 ) ) ) && ( width <= MAX_TU_SIZE_FOR_PROFILE && height <= MAX_TU_SIZE_FOR_PROFILE ) @@ -1526,6 +1767,7 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt { return false; } +#endif } if( m_pcEncCfg->getUseEarlyCU() && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip ) { @@ -1630,6 +1872,15 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt #endif relatedCU.GBiIdx = bestCU->GBiIdx; } +#if JVET_M0483_IBC + else if (CU::isIBC(*bestCU)) + { + relatedCU.isIBC = true; +#if HM_CODED_CU_INFO + relatedCU.isSkip |= bestCU->skip; +#endif + } +#endif else if( CU::isIntra( *bestCU ) ) { relatedCU.isIntra = true; @@ -1677,6 +1928,12 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt { cuECtx.bestEmtSize2Nx2N1stPass = tempCS->cost; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!cu.ispMode) + { + cuECtx.bestCostEmtFirstPassNoIsp = tempCS->cost; + } +#endif } #endif @@ -1710,31 +1967,28 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt cuECtx.set( MAX_QT_SUB_DEPTH, maxQtD ); } - if( ( tempCS->sps->getSpsNext().getMTTMode() & 1 ) == 1 ) - { - int maxMtD = tempCS->pcv->getMaxBtDepth( *tempCS->slice, partitioner.chType ) + partitioner.currImplicitBtDepth; + int maxMtD = tempCS->pcv->getMaxBtDepth( *tempCS->slice, partitioner.chType ) + partitioner.currImplicitBtDepth; - if( encTestmode.type == ETM_SPLIT_BT_H ) + if( encTestmode.type == ETM_SPLIT_BT_H ) + { + if( tempCS->cus.size() > 2 ) { - if( tempCS->cus.size() > 2 ) - { - int h_2 = tempCS->area.blocks[partitioner.chType].height / 2; - int cu1_h = tempCS->cus.front()->blocks[partitioner.chType].height; - int cu2_h = tempCS->cus.back() ->blocks[partitioner.chType].height; + int h_2 = tempCS->area.blocks[partitioner.chType].height / 2; + int cu1_h = tempCS->cus.front()->blocks[partitioner.chType].height; + int cu2_h = tempCS->cus.back() ->blocks[partitioner.chType].height; - cuECtx.set( DO_TRIH_SPLIT, cu1_h < h_2 || cu2_h < h_2 || partitioner.currMtDepth + 1 == maxMtD ); - } + cuECtx.set( DO_TRIH_SPLIT, cu1_h < h_2 || cu2_h < h_2 || partitioner.currMtDepth + 1 == maxMtD ); } - else if( encTestmode.type == ETM_SPLIT_BT_V ) + } + else if( encTestmode.type == ETM_SPLIT_BT_V ) + { + if( tempCS->cus.size() > 2 ) { - if( tempCS->cus.size() > 2 ) - { - int w_2 = tempCS->area.blocks[partitioner.chType].width / 2; - int cu1_w = tempCS->cus.front()->blocks[partitioner.chType].width; - int cu2_w = tempCS->cus.back() ->blocks[partitioner.chType].width; + int w_2 = tempCS->area.blocks[partitioner.chType].width / 2; + int cu1_w = tempCS->cus.front()->blocks[partitioner.chType].width; + int cu2_w = tempCS->cus.back() ->blocks[partitioner.chType].width; - cuECtx.set( DO_TRIV_SPLIT, cu1_w < w_2 || cu2_w < w_2 || partitioner.currMtDepth + 1 == maxMtD ); - } + cuECtx.set( DO_TRIV_SPLIT, cu1_w < w_2 || cu2_w < w_2 || partitioner.currMtDepth + 1 == maxMtD ); } } diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index 422e4c80840c1bd6b3960c1b1abe75129e6c0249..bda381a20add28a2700b6d833f3939c0c24fc4df 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -54,6 +54,9 @@ enum EncTestModeType { +#if JVET_M0253_HASH_ME + ETM_HASH_INTER, +#endif ETM_MERGE_SKIP, ETM_INTER_ME, ETM_AFFINE, @@ -137,6 +140,9 @@ inline bool isModeInter( const EncTestMode& encTestmode ) // perhaps remove || encTestmode.type == ETM_MERGE_SKIP || encTestmode.type == ETM_AFFINE || encTestmode.type == ETM_MERGE_TRIANGLE +#if JVET_M0253_HASH_ME + || encTestmode.type == ETM_HASH_INTER +#endif ); } @@ -178,6 +184,10 @@ struct ComprCUCtx , testModes ( ) , lastTestMode ( ) , earlySkip ( false ) +#if JVET_M0253_HASH_ME + , isHashPerfectMatch + ( false ) +#endif , bestCS ( nullptr ) , bestCU ( nullptr ) , bestTU ( nullptr ) @@ -194,6 +204,12 @@ struct ComprCUCtx #if ENABLE_SPLIT_PARALLELISM , isLevelSplitParallel ( false ) +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + , bestCostWithoutSplitFlags( MAX_DOUBLE ) +#if !JVET_M0464_UNI_MTS + , bestCostEmtFirstPassNoIsp( MAX_DOUBLE ) +#endif #endif { getAreaIdx( cs.area.Y(), *cs.pcv, cuX, cuY, cuW, cuH ); @@ -212,6 +228,9 @@ struct ComprCUCtx std::vector<EncTestMode> testModes; EncTestMode lastTestMode; bool earlySkip; +#if JVET_M0253_HASH_ME + bool isHashPerfectMatch; +#endif CodingStructure *bestCS; CodingUnit *bestCU; TransformUnit *bestTU; @@ -225,6 +244,12 @@ struct ComprCUCtx Distortion interHad; #if ENABLE_SPLIT_PARALLELISM bool isLevelSplitParallel; +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + double bestCostWithoutSplitFlags; +#if !JVET_M0464_UNI_MTS + double bestCostEmtFirstPassNoIsp; +#endif #endif template<typename T> T get( int ft ) const { return typeid(T) == typeid(double) ? (T&)extraFeaturesd[ft] : T(extraFeatures[ft]); } @@ -257,7 +282,7 @@ protected: public: virtual ~EncModeCtrl () {} - + #if REUSE_CU_RESULTS virtual void create ( const EncCfg& cfg ) = 0; virtual void destroy () = 0; @@ -287,6 +312,10 @@ public: EncTestMode currTestMode () const; EncTestMode lastTestMode () const; void setEarlySkipDetected (); +#if JVET_M0253_HASH_ME + void setIsHashPerfectMatch( bool b ) { m_ComprCUCtxList.back().isHashPerfectMatch = b; } + bool getIsHashPerfectMatch() { return m_ComprCUCtxList.back().isHashPerfectMatch; } +#endif virtual void setBest ( CodingStructure& cs ); bool anyMode () const; @@ -307,6 +336,14 @@ public: bool getSkipSecondEMTPass () const { return m_ComprCUCtxList.back().skipSecondEMTPass; } void setSkipSecondEMTPass ( bool b ) { m_ComprCUCtxList.back().skipSecondEMTPass = b; } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + double getBestCostWithoutSplitFlags () const { return m_ComprCUCtxList.back().bestCostWithoutSplitFlags; } + void setBestCostWithoutSplitFlags ( double cost ) { m_ComprCUCtxList.back().bestCostWithoutSplitFlags = cost; } +#if !JVET_M0464_UNI_MTS + double getEmtFirstPassNoIspCost () const { return m_ComprCUCtxList.back().bestCostEmtFirstPassNoIsp; } + void setEmtFirstPassNoIspCost ( double cost ) { m_ComprCUCtxList.back().bestCostEmtFirstPassNoIsp = cost; } +#endif +#endif protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); @@ -318,6 +355,33 @@ protected: ////////////////////////////////////////////////////////////////////////// // some utility interfaces that expose some functionality that can be used without concerning about which particular controller is used ////////////////////////////////////////////////////////////////////////// +#if JVET_M0140_SBT +struct SaveLoadStructSbt +{ + uint8_t numPuInfoStored; + uint32_t puSse[SBT_NUM_SL]; + uint8_t puSbt[SBT_NUM_SL]; + uint8_t puTrs[SBT_NUM_SL]; +}; + +class SaveLoadEncInfoSbt +{ +protected: + void init( const Slice &slice ); + void create(); + void destroy(); + +private: + SaveLoadStructSbt ****m_saveLoadSbt; + Slice const *m_sliceSbt; + +public: + virtual ~SaveLoadEncInfoSbt() { } + void resetSaveloadSbt( int maxSbtSize ); + uint16_t findBestSbt( const UnitArea& area, const uint32_t curPuSse ); + bool saveBestSbt( const UnitArea& area, const uint32_t curPuSse, const uint8_t curPuSbt, const uint8_t curPuTrs ); +}; +#endif static const int MAX_STORED_CU_INFO_REFS = 4; @@ -327,6 +391,9 @@ struct CodedCUInfo bool isIntra; bool isSkip; bool isMMVDSkip; +#if JVET_M0483_IBC + bool isIBC; +#endif bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; Mv saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; @@ -389,7 +456,12 @@ struct BestEncodingInfo { CodingUnit cu; PredictionUnit pu; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + TransformUnit tus[MAX_NUM_TUS]; + size_t numTus; +#else TransformUnit tu; +#endif EncTestMode testMode; int poc; @@ -436,6 +508,9 @@ class EncModeCtrlMTnoRQT : public EncModeCtrl, public CacheBlkInfoCtrl #if REUSE_CU_RESULTS , public BestEncInfoCache #endif +#if JVET_M0140_SBT + , public SaveLoadEncInfoSbt +#endif { enum ExtraFeatures { diff --git a/source/Lib/EncoderLib/EncReshape.cpp b/source/Lib/EncoderLib/EncReshape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce7d76aa2f826341f21c7b15e6aa425b02a7441a --- /dev/null +++ b/source/Lib/EncoderLib/EncReshape.cpp @@ -0,0 +1,1312 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file EncReshape.cpp +\brief encoder reshaper class +*/ +#include "EncReshape.h" +#include <stdio.h> +#include <string.h> +#include <math.h> +#if JVET_M0427_INLOOP_RESHAPER +//! \ingroup EncLib +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +EncReshape::EncReshape() +{ + m_CTUFlag = false; + m_srcReshaped = false; + m_recReshaped = false; + m_reshape = true; + m_exceedSTD = false; + m_tcase = 0; + m_rateAdpMode = 0; + m_chromaAdj = 0; +} + +EncReshape::~EncReshape() +{ +} + +void EncReshape::createEnc(int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight, int bitDepth) +{ + m_lumaBD = bitDepth; + m_reshapeLUTSize = 1 << m_lumaBD; + m_initCWAnalyze = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS; + m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS; + + if (m_fwdLUT.empty()) + m_fwdLUT.resize(m_reshapeLUTSize, 0); + if (m_invLUT.empty()) + m_invLUT.resize(m_reshapeLUTSize,0); + if (m_binCW.empty()) + m_binCW.resize(PIC_ANALYZE_CW_BINS); + if (m_binImportance.empty()) + m_binImportance.resize(PIC_ANALYZE_CW_BINS); + if (m_reshapePivot.empty()) + m_reshapePivot.resize(PIC_CODE_CW_BINS + 1, 0); + if (m_chromaAdjHelpLUT.empty()) + m_chromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 1<<CSCALE_FP_PREC); + + m_sliceReshapeInfo.setUseSliceReshaper(true); + m_sliceReshapeInfo.setSliceReshapeChromaAdj(true); + m_sliceReshapeInfo.setSliceReshapeModelPresentFlag(true); + m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; + memset(m_sliceReshapeInfo.reshaperModelBinCWDelta, 0, (PIC_CODE_CW_BINS) * sizeof(int)); + + m_picWidth = picWidth; + m_picHeight = picHeight; + m_maxCUWidth = maxCUWidth; + m_maxCUHeight = maxCUHeight; + m_widthInCtus = (m_picWidth + m_maxCUWidth - 1) / m_maxCUWidth; + m_heightInCtus = (m_picHeight + m_maxCUHeight - 1) / m_maxCUHeight; + m_numCtuInFrame = m_widthInCtus * m_heightInCtus; +} + +void EncReshape::destroy() +{ +} + +/** +-Perform HDR set up +\param pcPic describe pointer of current coding picture +\param sliceType describe the slice type +*/ +#if JVET_M0483_IBC +void EncReshape::preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT) +#else +void EncReshape::preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isIBC) +#endif +{ + if (m_lumaBD >= 10) + { + m_sliceReshapeInfo.sliceReshaperEnableFlag = true; + if (reshapeCW.rspIntraPeriod == 1) + { + if (pcPic->getPOC() == 0) { m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; } + else { m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false; } + } + else + { +#if JVET_M0483_IBC + if (sliceType == I_SLICE ) { m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; } +#else + if (sliceType == I_SLICE || (sliceType == P_SLICE && isIBC)) { m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; } +#endif + else { m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false; } + } +#if JVET_M0483_IBC + if (sliceType == I_SLICE && isDualT) { m_sliceReshapeInfo.enableChromaAdj = 0; } +#else + if ((sliceType == I_SLICE || (sliceType == P_SLICE && isIBC)) && isDualT) { m_sliceReshapeInfo.enableChromaAdj = 0; } +#endif + else { m_sliceReshapeInfo.enableChromaAdj = 1; } + } + else + { + m_sliceReshapeInfo.sliceReshaperEnableFlag = false; + m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false; + } +} + +/** +-Perform picture analysis for SDR +\param pcPic describe pointer of current coding picture +\param sliceType describe the slice type +\param reshapeCW describe some input info +*/ +#if JVET_M0483_IBC +void EncReshape::preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT) +#else +void EncReshape::preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isIBC) +#endif +{ + m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; + m_sliceReshapeInfo.sliceReshaperEnableFlag = true; + + int modIP = pcPic->getPOC() - pcPic->getPOC() / reshapeCW.rspFpsToIp * reshapeCW.rspFpsToIp; +#if JVET_M0483_IBC + if (sliceType == I_SLICE || (reshapeCW.rspIntraPeriod == -1 && modIP == 0)) +#else + if (sliceType == I_SLICE || (reshapeCW.rspIntraPeriod == -1 && modIP == 0) || (sliceType == P_SLICE && isIBC)) +#endif + { + if (m_sliceReshapeInfo.sliceReshaperModelPresentFlag == true) + { + int stdMin = 16 <<(m_lumaBD-8); + int stdMax = 235 << (m_lumaBD - 8); + int binLen = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS; + + m_reshapeCW = reshapeCW; + m_initCWAnalyze = binLen; + + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + m_binImportance[b] = 0; + m_binCW[b] = binLen; + } + + int startBinIdx = stdMin / binLen; + int endBinIdx = stdMax / binLen; + m_sliceReshapeInfo.reshaperModelMinBinIdx = startBinIdx; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = endBinIdx; + + PelBuf picY = pcPic->getOrigBuf(COMPONENT_Y); + const int width = picY.width; + const int height = picY.height; + const int stride = picY.stride; + + double blockBinVarSum[PIC_ANALYZE_CW_BINS] = { 0.0 }; + uint32_t bockBinCnt[PIC_ANALYZE_CW_BINS] = { 0 }; + + const int PIC_ANALYZE_WIN_SIZE = 5; + const uint32_t winSize = PIC_ANALYZE_WIN_SIZE; + const uint32_t winLens = (winSize - 1) >> 1; + + int64_t tempSq = 0; + int64_t leftSum = 0, leftSumSq = 0; + int64_t *leftColSum = new int64_t[width]; + int64_t *leftColSumSq = new int64_t[width]; + memset(leftColSum, 0, width * sizeof(int64_t)); + memset(leftColSumSq, 0, width * sizeof(int64_t)); + int64_t topSum = 0, topSumSq = 0; + int64_t *topRowSum = new int64_t[height]; + int64_t *topRowSumSq = new int64_t[height]; + memset(topRowSum, 0, height * sizeof(int64_t)); + memset(topRowSumSq, 0, height * sizeof(int64_t)); + int64_t *topColSum = new int64_t[width]; + int64_t *topColSumSq = new int64_t[width]; + memset(topColSum, 0, width * sizeof(int64_t)); + memset(topColSumSq, 0, width * sizeof(int64_t)); + + for (uint32_t y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + const Pel pxlY = picY.buf[x]; + int64_t sum = 0; + int64_t sumSq = 0; + uint32_t numPixInPart = 0; + + uint32_t y1 = std::max((int)(y - winLens), 0); + uint32_t y2 = std::min((int)(y + winLens), (height - 1)); + uint32_t x1 = std::max((int)(x - winLens), 0); + uint32_t x2 = std::min((int)(x + winLens), (width - 1)); + + + uint32_t bx = 0, by = 0; + const Pel *pWinY = &picY.buf[0]; + numPixInPart = (x2 - x1 + 1) * (y2 - y1 + 1); + + if (x == 0 && y == 0) // for the 1st Pixel, calc all points + { + for (by = y1; by <= y2; by++) + { + for (bx = x1; bx <= x2; bx++) + { + tempSq = pWinY[bx] * pWinY[bx]; + leftSum += pWinY[bx]; + leftSumSq += tempSq; + leftColSum[bx] += pWinY[bx]; + leftColSumSq[bx] += tempSq; + topColSum[bx] += pWinY[bx]; + topColSumSq[bx] += tempSq; + topRowSum[by] += pWinY[bx]; + topRowSumSq[by] += tempSq; + } + pWinY += stride; + } + topSum = leftSum; + topSumSq = leftSumSq; + sum = leftSum; + sumSq = leftSumSq; + } + else if (x == 0 && y > 0) // for the 1st column, calc the bottom stripe + { + if (y < height - winLens) + { + pWinY += winLens*stride; + topRowSum[y + winLens] = 0; + topRowSumSq[y + winLens] = 0; + for (bx = x1; bx <= x2; bx++) + { + topRowSum[y + winLens] += pWinY[bx]; + topRowSumSq[y + winLens] += pWinY[bx] * pWinY[bx]; + } + topSum += topRowSum[y + winLens]; + topSumSq += topRowSumSq[y + winLens]; + } + if (y > winLens) + { + topSum -= topRowSum[y - 1 - winLens]; + topSumSq -= topRowSumSq[y - 1 - winLens]; + } + + memset(leftColSum, 0, width * sizeof(int64_t)); + memset(leftColSumSq, 0, width * sizeof(int64_t)); + pWinY = &picY.buf[0]; + pWinY -= (y <= winLens ? y : winLens)*stride; + for (by = y1; by <= y2; by++) + { + for (bx = x1; bx <= x2; bx++) + { + leftColSum[bx] += pWinY[bx]; + leftColSumSq[bx] += pWinY[bx] * pWinY[bx]; + } + pWinY += stride; + } + + leftSum = topSum; + leftSumSq = topSumSq; + sum = topSum; + sumSq = topSumSq; + } + + else if (x > 0) + { + if (x < width - winLens) + { + pWinY -= (y <= winLens ? y : winLens)*stride; + if (y == 0) // for the 1st row, calc the right stripe + { + leftColSum[x + winLens] = 0; + leftColSumSq[x + winLens] = 0; + for (by = y1; by <= y2; by++) + { + leftColSum[x + winLens] += pWinY[x + winLens]; + leftColSumSq[x + winLens] += pWinY[x + winLens] * pWinY[x + winLens]; + pWinY += stride; + } + } + else // for the main area, calc the B-R point + { + leftColSum[x + winLens] = topColSum[x + winLens]; + leftColSumSq[x + winLens] = topColSumSq[x + winLens]; + if (y < height - winLens) + { + pWinY = &picY.buf[0]; + pWinY += winLens * stride; + leftColSum[x + winLens] += pWinY[x + winLens]; + leftColSumSq[x + winLens] += pWinY[x + winLens] * pWinY[x + winLens]; + } + if (y > winLens) + { + pWinY = &picY.buf[0]; + pWinY -= (winLens + 1) * stride; + leftColSum[x + winLens] -= pWinY[x + winLens]; + leftColSumSq[x + winLens] -= pWinY[x + winLens] * pWinY[x + winLens]; + } + } + topColSum[x + winLens] = leftColSum[x + winLens]; + topColSumSq[x + winLens] = leftColSumSq[x + winLens]; + leftSum += leftColSum[x + winLens]; + leftSumSq += leftColSumSq[x + winLens]; + } + if (x > winLens) + { + leftSum -= leftColSum[x - 1 - winLens]; + leftSumSq -= leftColSumSq[x - 1 - winLens]; + } + sum = leftSum; + sumSq = leftSumSq; + } + + double average = double(sum) / numPixInPart; + double variance = double(sumSq) / numPixInPart - average * average; + uint32_t binNum = (uint32_t)(pxlY/PIC_ANALYZE_CW_BINS); + + if (m_lumaBD > 10) + { + average = average / (double)(1<<(m_lumaBD - 10)); + variance = variance / (double)(1 << (2*m_lumaBD - 20)); + binNum = (uint32_t)((pxlY>>(m_lumaBD - 10)) / PIC_ANALYZE_CW_BINS); + } + else if (m_lumaBD < 10) + { + average = average * (double)(1 << (10 - m_lumaBD)); + variance = variance * (double)(1 << (20-2*m_lumaBD)); + binNum = (uint32_t)((pxlY << (10 - m_lumaBD)) / PIC_ANALYZE_CW_BINS); + } + double varLog10 = log10(variance + 1.0); + blockBinVarSum[binNum] += varLog10; + bockBinCnt[binNum]++; + } + picY.buf += stride; + } + + delete[] topColSum; + delete[] topColSumSq; + delete[] topRowSum; + delete[] topRowSumSq; + delete[] leftColSum; + delete[] leftColSumSq; + + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (bockBinCnt[b] > 0) + blockBinVarSum[b] = blockBinVarSum[b] / bockBinCnt[b]; + } + + m_reshape = true; + m_exceedSTD = false; + m_useAdpCW = false; + m_chromaWeight = 1.0; + m_sliceReshapeInfo.enableChromaAdj = 1; + bool intraAdp = false; + bool interAdp = true; + double reshapeTH1 = 0.0; + double reshapeTH2 = 5.0; + deriveReshapeParametersSDRfromStats(bockBinCnt, blockBinVarSum, &reshapeTH1, &reshapeTH2, &intraAdp, &interAdp); + + if (m_rateAdpMode == 2 && reshapeCW.rspBaseQP <= 22) + { + intraAdp = false; + interAdp = false; + } + + m_sliceReshapeInfo.sliceReshaperEnableFlag = intraAdp; + + if (!intraAdp && !interAdp) + { + m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false; + m_reshape = false; + return; + } + + if (m_exceedSTD) + { + startBinIdx = 2; + endBinIdx = 29; + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (bockBinCnt[b] > 0 && b < startBinIdx) + startBinIdx = b; + if (bockBinCnt[b] > 0 && b > endBinIdx) + endBinIdx = b; + } + m_sliceReshapeInfo.reshaperModelMinBinIdx = startBinIdx; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = endBinIdx; + } + + m_initCWAnalyze = m_lumaBD > 10 ? (m_initCWAnalyze >> (m_lumaBD - 10)) : m_lumaBD < 10 ? (m_initCWAnalyze << (10 - m_lumaBD)) : m_initCWAnalyze; + if (reshapeCW.rspBaseQP <= 22 && m_rateAdpMode == 1) + { + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (i >= startBinIdx && i <= endBinIdx) + m_binCW[i] = m_initCWAnalyze + 1; + else + m_binCW[i] = 0; + } + } + else if (m_useAdpCW) + { + double Alpha = 1.0, Beta = 0.0; + deriveReshapeParameters(blockBinVarSum, startBinIdx, endBinIdx, m_reshapeCW, Alpha, Beta); + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (i >= startBinIdx && i <= endBinIdx) + m_binCW[i] = (uint32_t)round(Alpha*blockBinVarSum[i] + Beta); + else + m_binCW[i] = 0; + } + } + else + { + for (int b = startBinIdx; b <= endBinIdx; b++) + { + if (blockBinVarSum[b] < reshapeTH1) + m_binImportance[b] = 2; + else if (blockBinVarSum[b] > reshapeTH2) + m_binImportance[b] = 3; + else + m_binImportance[b] = 1; + } + + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (m_binImportance[i] == 0) + m_binCW[i] = 0; + else if (m_binImportance[i] == 1) + m_binCW[i] = m_initCWAnalyze + 1; + else if (m_binImportance[i] == 2) + m_binCW[i] = m_reshapeCW.binCW[0]; + else if (m_binImportance[i] == 3) + m_binCW[i] = m_reshapeCW.binCW[1]; + else + THROW("SDR Reshape Bin Importance not supported"); + } + } + if (m_reshapeCW.rspPicSize <= 1497600 && reshapeCW.rspIntraPeriod == -1 && modIP == 0 && sliceType != I_SLICE) + { + m_sliceReshapeInfo.sliceReshaperEnableFlag = false; + } + + } + m_chromaAdj = m_sliceReshapeInfo.enableChromaAdj; +#if JVET_M0483_IBC + if (sliceType == I_SLICE && isDualT) +#else + if ((sliceType == I_SLICE || (sliceType == P_SLICE && isIBC)) && isDualT) +#endif + { + m_sliceReshapeInfo.enableChromaAdj = 0; + } + } + else // Inter slices + { + m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false; + m_sliceReshapeInfo.enableChromaAdj = m_chromaAdj; + + if (!m_reshape) + { + m_sliceReshapeInfo.sliceReshaperEnableFlag = false; + } + else + { + const int cTid = m_reshapeCW.rspTid; + bool enableRsp = m_tcase == 5 ? false : (m_tcase < 5 ? (cTid < m_tcase + 1 ? false : true) : (cTid <= 10 - m_tcase ? true : false)); + m_sliceReshapeInfo.sliceReshaperEnableFlag = enableRsp; + } + } +} + +// Bubble Sort to descending order with index +void EncReshape::bubbleSortDsd(double* array, int * idx, int n) +{ + int i, j; + bool swapped; + for (i = 0; i < n - 1; i++) + { + swapped = false; + for (j = 0; j < n - i - 1; j++) + { + if (array[j] < array[j + 1]) + { + swap(&array[j], &array[j + 1]); + swap(&idx[j], &idx[j + 1]); + swapped = true; + } + } + if (swapped == false) + break; + } +} + +void EncReshape::deriveReshapeParametersSDRfromStats(uint32_t * blockBinCnt, double *blockBinVarSum, double* reshapeTH1, double* reshapeTH2, bool *intraAdp, bool *interAdp) +{ + int binIdxSortDsd[PIC_ANALYZE_CW_BINS] = { 0 }; + double binVarSortDsd[PIC_ANALYZE_CW_BINS] = { 0.0 }; + double binHist[PIC_ANALYZE_CW_BINS] = { 0.0 }; + double binVarSortDsdCDF[PIC_ANALYZE_CW_BINS] = { 0.0 }; + double maxBinVar = 0.0, meanBinVar = 0.0, minBinVar = 5.0; + int nonZeroBinCt = 0; + int firstBinVarLessThanVal1 = 0; + int firstBinVarLessThanVal2 = 0; + int firstBinVarLessThanVal3 = 0; + int firstBinVarLessThanVal4 = 0; + + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + binHist[b] = (double) blockBinCnt[b] / (double)(m_reshapeCW.rspPicSize); + if (binHist[b] > 0.001) + { + nonZeroBinCt++; + meanBinVar += blockBinVarSum[b]; + if (blockBinVarSum[b] > maxBinVar) { maxBinVar = blockBinVarSum[b]; } + if (blockBinVarSum[b] < minBinVar) { minBinVar = blockBinVarSum[b]; } + } + binVarSortDsd[b] = blockBinVarSum[b]; + binIdxSortDsd[b] = b; + } + if ((binHist[0] + binHist[1] + binHist[PIC_ANALYZE_CW_BINS - 2] + binHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { m_exceedSTD = true; } + if ((binHist[PIC_ANALYZE_CW_BINS - 2] + binHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { *interAdp = false; return; } + else { *interAdp = true; } + + meanBinVar = meanBinVar / (double)nonZeroBinCt; + bubbleSortDsd(binVarSortDsd, binIdxSortDsd, PIC_ANALYZE_CW_BINS); + binVarSortDsdCDF[0] = binHist[binIdxSortDsd[0]]; + + for (int b = 1; b < PIC_ANALYZE_CW_BINS; b++) + { + binVarSortDsdCDF[b] = binVarSortDsdCDF[b - 1] + binHist[binIdxSortDsd[b]]; + } + + for (int b = 0; b < PIC_ANALYZE_CW_BINS - 1; b++) + { + if (binVarSortDsd[b] > 3.5) { firstBinVarLessThanVal1 = b + 1; } + if (binVarSortDsd[b] > 3.0) { firstBinVarLessThanVal2 = b + 1; } + if (binVarSortDsd[b] > 2.5) { firstBinVarLessThanVal3 = b + 1; } + if (binVarSortDsd[b] > 2.0) { firstBinVarLessThanVal4 = b + 1; } + } + + m_reshapeCW.binCW[0] = 38; + m_reshapeCW.binCW[1] = 28; + + if (m_reshapeCW.rspIntraPeriod == -1) + { + *intraAdp = true; + if (m_reshapeCW.rspPicSize > 1497600) + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.4; + *reshapeTH2 = 4.5; + m_rateAdpMode = 2; + + if (meanBinVar >= 2.52) + { + if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *reshapeTH1 = 2.5; + *reshapeTH2 = 3.0; + } + else if (binVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && binVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + *reshapeTH1 = 2.2; + } + else if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + m_reshapeCW.binCW[1] = 30; + *reshapeTH1 = 2.0; + m_rateAdpMode = 0; + } + else + { + m_reshapeCW.binCW[1] = 30; + m_rateAdpMode = 1; + } + } + } + else if (m_reshapeCW.rspPicSize > 660480) + { + m_reshapeCW.binCW[0] = 34; + *reshapeTH1 = 3.4; + *reshapeTH2 = 4.0; + m_rateAdpMode = 2; + + if (binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + m_useAdpCW = true; + m_reshapeCW.binCW[0] = 38; + } + else + { + m_reshapeCW.binCW[0] = 40; + *reshapeTH1 = 2.2; + *reshapeTH2 = 4.5; + m_rateAdpMode = 0; + } + } + else + { + if (maxBinVar > 3.3) + { + m_reshapeCW.binCW[1] = 30; + } + else + { + m_reshapeCW.binCW[1] = 28; + } + } + } + else if (m_reshapeCW.rspPicSize > 249600) + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.5; + + if (m_exceedSTD) + { + m_reshapeCW.binCW[0] = 36; + m_reshapeCW.binCW[1] = 30; + } + if (minBinVar > 2.6) + { + *reshapeTH1 = 3.0; + } + else { + double diff1 = binVarSortDsdCDF[firstBinVarLessThanVal4] - binVarSortDsdCDF[firstBinVarLessThanVal3]; + double diff2 = binVarSortDsdCDF[firstBinVarLessThanVal2] - binVarSortDsdCDF[firstBinVarLessThanVal1]; + if (diff1 > 0.4 || binVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) + { + m_useAdpCW = true; + m_rateAdpMode = 1; + } + else if (diff2 <= 0.1 && binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && binVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) + { + m_useAdpCW = true; + m_rateAdpMode = 1; + } + else + { + m_rateAdpMode = 2; + } + } + } + else + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.6; + *reshapeTH2 = 4.5; + + if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) + { + *reshapeTH1 = 3.2; + m_rateAdpMode = 1; + } + } + } + else if (m_reshapeCW.rspIntraPeriod == 1) + { + *intraAdp = true; + if (m_reshapeCW.rspPicSize > 5184000) + { + *reshapeTH1 = 2.0; + *reshapeTH2 = 3.0; + m_rateAdpMode = 2; + + if (maxBinVar > 2.4) + { + if (binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.88) + { + if (maxBinVar < 2.695) + { + *reshapeTH2 = 2.2; + } + else + { + if (binVarSortDsdCDF[firstBinVarLessThanVal3] < 0.45) + { + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.0; + m_reshapeCW.binCW[0] = 36; + m_sliceReshapeInfo.enableChromaAdj = 0; + m_rateAdpMode = 0; + } + else + { + m_useAdpCW = true; + m_reshapeCW.binCW[0] = 36; + m_reshapeCW.binCW[1] = 30; + } + } + } + else + { + if (maxBinVar > 2.8) + { + *reshapeTH1 = 2.2; + *reshapeTH2 = 4.0; + m_reshapeCW.binCW[0] = 36; + m_sliceReshapeInfo.enableChromaAdj = 0; + } + else + { + m_useAdpCW = true; + m_reshapeCW.binCW[0] = 38; + m_reshapeCW.binCW[1] = 28; + } + } + } + else + { + if (maxBinVar > 2.24) + { + m_useAdpCW = true; + m_reshapeCW.binCW[0] = 34; + m_reshapeCW.binCW[1] = 30; + } + } + } + else if (m_reshapeCW.rspPicSize > 1497600) + { + *reshapeTH1 = 2.0; + *reshapeTH2 = 4.5; + m_rateAdpMode = 2; + + if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + int firstVarCDFLargerThanVal = 1; + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (binVarSortDsdCDF[b] > 0.7) + { + firstVarCDFLargerThanVal = b; + break; + } + } + if (meanBinVar < 2.52 || binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *reshapeTH1 = 2.2; + *reshapeTH2 = (binVarSortDsd[firstVarCDFLargerThanVal] + binVarSortDsd[firstVarCDFLargerThanVal - 1]) / 2.0; + } + else + { + m_reshapeCW.binCW[1] = 30; + *reshapeTH2 = 2.8; + } + } + else if (binVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && binVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 3.5; + m_rateAdpMode = 1; + } + } + else if (m_reshapeCW.rspPicSize > 660480) + { + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.5; + m_rateAdpMode = 1; + + if (binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + *reshapeTH1 = 2.0; + } + } + else + { + if (maxBinVar > 3.3) + { + m_reshapeCW.binCW[0] = 35; + } + else + { + *reshapeTH1 = 2.8; + m_reshapeCW.binCW[0] = 35; + } + } + } + else if (m_reshapeCW.rspPicSize > 249600) + { + m_rateAdpMode = 1; + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.5; + } + else + { + if (binVarSortDsdCDF[firstBinVarLessThanVal2] < 0.33 && m_reshapeCW.rspFps>40) + { + *intraAdp = false; + *interAdp = false; + } + else + { + m_rateAdpMode = 1; + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 3.0; + *reshapeTH2 = 4.0; + } + } + } + else + { + if (m_reshapeCW.rspPicSize > 5184000) + { + m_reshapeCW.binCW[0] = 40; + *reshapeTH2 = 4.0; + m_rateAdpMode = 2; + + if (maxBinVar < 2.4) + { + *reshapeTH1 = 3.0; + if (m_reshapeCW.rspBaseQP <= 22) + m_tcase = 3; + } + else if (maxBinVar > 3.0) + { + if (minBinVar > 1) + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.8; + *reshapeTH2 = 3.5; + m_sliceReshapeInfo.enableChromaAdj = 0; + m_chromaWeight = 1.05; + m_rateAdpMode = 0; + } + else + { + m_reshapeCW.binCW[0] = 36; + *reshapeTH1 = 2.2; + *reshapeTH2 = 3.5; + m_sliceReshapeInfo.enableChromaAdj = 0; + m_chromaWeight = 0.95; + } + } + else + { + *reshapeTH1 = 1.5; + } + } + else if (m_reshapeCW.rspPicSize > 1497600) + { + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.5; + m_rateAdpMode = 1; + + if (meanBinVar < 2.52) + { + *intraAdp = true; + m_rateAdpMode = 0; + m_tcase = 9; + } + else + { + if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *reshapeTH2 = 3.0; + *intraAdp = true; + } + else if (binVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && binVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + *reshapeTH1 = 3.0; + *intraAdp = true; + m_rateAdpMode = 0; + m_tcase = 9; + } + else if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + *reshapeTH1 = 2.4; + m_reshapeCW.binCW[0] = 36; + } + else + { + *reshapeTH1 = 2.4; + m_reshapeCW.binCW[0] = 36; + } + } + } + else if (m_reshapeCW.rspPicSize > 660480) + { + *intraAdp = true; + m_rateAdpMode = 1; + + if (binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + *reshapeTH1 = 2.1; + *reshapeTH2 = 3.5; + } + else + { + *reshapeTH1 = 2.4; + *reshapeTH2 = 4.5; + m_reshapeCW.binCW[0] = 40; + m_rateAdpMode = 0; + } + } + else + { + if (maxBinVar > 3.3) + { + *reshapeTH1 = 3.5; + *reshapeTH2 = 3.8; + } + else + { + *reshapeTH1 = 3.0; + *reshapeTH2 = 4.0; + m_reshapeCW.binCW[1] = 30; + } + } + } + else if (m_reshapeCW.rspPicSize > 249600) + { + m_reshapeCW.binCW[1] = 30; + *reshapeTH1 = 2.5; + *reshapeTH2 = 4.5; + *intraAdp = true; + m_rateAdpMode = 1; + + if (minBinVar > 2.6) + { + *reshapeTH1 = 3.2; + m_rateAdpMode = 0; + m_tcase = 9; + } + else { + double diff1 = binVarSortDsdCDF[firstBinVarLessThanVal4] - binVarSortDsdCDF[firstBinVarLessThanVal3]; + double diff2 = binVarSortDsdCDF[firstBinVarLessThanVal2] - binVarSortDsdCDF[firstBinVarLessThanVal1]; + if (diff1 > 0.4 || binVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) + { + *reshapeTH1 = 2.9; + *intraAdp = false; + } + else + { + if (diff2 > 0.1) + { + *reshapeTH1 = 2.5; + } + else + { + *reshapeTH1 = 2.9; + if (binVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && binVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) + { + m_rateAdpMode = 0; + m_tcase = 9; + } + } + } + } + } + else + { + m_reshapeCW.binCW[0] = 36; + m_reshapeCW.binCW[1] = 30; + *reshapeTH1 = 2.6; + *reshapeTH2 = 4.5; + *intraAdp = true; + m_rateAdpMode = 1; + if (binVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) + { + *reshapeTH1 = 3.4; + } + } + } +} + +void EncReshape::deriveReshapeParameters(double *array, int start, int end, ReshapeCW respCW, double &alpha, double &beta) +{ + double minVar = 10.0, maxVar = 0.0; + for (int b = start; b <= end; b++) + { + if (array[b] < minVar) minVar = array[b]; + if (array[b] > maxVar) maxVar = array[b]; + } + double maxCW = (double)respCW.binCW[0]; + double minCW = (double)respCW.binCW[1]; + alpha = (minCW - maxCW) / (maxVar - minVar); + beta = (maxCW*maxVar - minCW*minVar) / (maxVar - minVar); +} + +/** +-Init reshaping LUT from dQP model +*/ +void EncReshape::initLUTfromdQPModel() +{ + initModelParam(); + int pwlFwdLUTsize = PIC_CODE_CW_BINS; + int pwlFwdBinLen = m_reshapeLUTSize / PIC_CODE_CW_BINS; + int p1 = m_dQPModel.scaleFracPrec; + int p2 = m_dQPModel.offsetFracPrec; + int totalShift = p1 + p2; + int scaleFP = (1 - 2 * m_dQPModel.scaleSign) * m_dQPModel.scaleAbs; + int offsetFP = (1 - 2 * m_dQPModel.offsetSign) * m_dQPModel.offsetAbs; + int maxQP = (1 - 2 * m_dQPModel.maxQPSign) * m_dQPModel.maxQPAbs; + int minQP = (1 - 2 * m_dQPModel.minQPSign) * m_dQPModel.minQPAbs; + int maxFP = maxQP * (1 << totalShift); + int minFP = minQP * (1 << totalShift); + int temp, signval, absval; + int dQPDiv6FP; + int32_t * slopeLUT = new int32_t[m_reshapeLUTSize](); + int32_t * fwdLUTHighPrec = new int32_t[m_reshapeLUTSize](); + + for (int i = 0; i < m_reshapeLUTSize; i++) + { + int inputY = m_lumaBD < 10 ? i << (10 - m_lumaBD) : m_lumaBD > 10 ? i >> (m_lumaBD - 10) : i; + temp = int64_t((scaleFP*inputY) * (1 << p2)) + int64_t(offsetFP * (1 << p1)); + temp = temp > maxFP ? maxFP : temp < minFP ? minFP : temp; + signval = temp >= 0 ? 1 : -1; + absval = signval * temp; + dQPDiv6FP = signval * (((absval + 3) / 6 + (1 << (totalShift - 17))) >> (totalShift - 16)); + slopeLUT[i] = calcEXP2(dQPDiv6FP); + } + + if (m_dQPModel.fullRangeInputFlag == 0) + { + for (int i = 0; i < (16 << (m_lumaBD - 8)); i++) { slopeLUT[i] = 0; } + for (int i = (235 << (m_lumaBD - 8)); i < m_reshapeLUTSize; i++) { slopeLUT[i] = 0; } + } + + for (int i = 0; i < m_reshapeLUTSize - 1; i++) + fwdLUTHighPrec[i + 1] = fwdLUTHighPrec[i] + slopeLUT[i]; + if (slopeLUT != nullptr) { delete[] slopeLUT; slopeLUT = nullptr; } + + int max_Y = (fwdLUTHighPrec[m_reshapeLUTSize - 1] + (1 << 7)) >> 8; + int Roffset = max_Y >> 1; + for (int i = 0; i < m_reshapeLUTSize; i++) + { + m_fwdLUT[i] = (short)(((fwdLUTHighPrec[i] >> 8) * (m_reshapeLUTSize - 1) + Roffset) / max_Y); + } + + if (fwdLUTHighPrec != nullptr) { delete[] fwdLUTHighPrec; fwdLUTHighPrec = nullptr; } + m_sliceReshapeInfo.reshaperModelMinBinIdx = 1; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = 14; + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + int16_t X1 = i * pwlFwdBinLen; + m_reshapePivot[i] = m_fwdLUT[X1]; + } + m_reshapePivot[pwlFwdLUTsize] = ((1 << m_lumaBD) - 1); + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + m_binCW[i] = m_reshapePivot[i + 1] - m_reshapePivot[i]; + } + + int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0; + for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) + { + deltaCW = (int)m_binCW[i] - (int)m_initCW; + m_sliceReshapeInfo.reshaperModelBinCWDelta[i] = deltaCW; + absDeltaCW = (deltaCW < 0) ? (-deltaCW) : deltaCW; + if (absDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = absDeltaCW; } + } + m_sliceReshapeInfo.maxNbitsNeededDeltaCW = g_aucLog2[maxAbsDeltaCW << 1]; + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + int16_t Y1 = m_reshapePivot[i]; + int16_t Y2 = m_reshapePivot[i + 1]; + m_fwdLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y1); + int log2PwlFwdBinLen = g_aucLog2[pwlFwdBinLen]; + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2PwlFwdBinLen - 1))) >> (log2PwlFwdBinLen); + for (int j = 1; j < pwlFwdBinLen; j++) + { + int tempVal = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + m_fwdLUT[i*pwlFwdBinLen + j] = Clip3((Pel)0, (Pel)((1<<m_lumaBD) -1), (Pel)tempVal); + } + } + reverseLUT(m_fwdLUT, m_invLUT, m_reshapeLUTSize); + updateChromaScaleLUT(); +} + + +/** +-Perform fixe point exp2 calculation +\param val input value +\retval output value = exp2(val) +*/ +int EncReshape::calcEXP2(int val) +{ + int32_t i, f, r, s; + r = 0x00000e20; + + i = ((int32_t)(val)+0x8000) & ~0xffff; + f = (int32_t)(val)-i; + s = ((15 << 16) - i) >> 16; + + r = (r * f + 0x3e1cc333) >> 17; + r = (r * f + 0x58bd46a6) >> 16; + r = r * f + 0x7ffde4a3; + return (uint32_t)r >> s; +} + +void EncReshape::constructReshaperSDR() +{ + int bdShift = m_lumaBD - 10; + int usedCW = 0; + int totCW = bdShift != 0 ? (bdShift > 0 ? m_reshapeLUTSize / (1<<bdShift) : m_reshapeLUTSize * (1 << (-bdShift))) : m_reshapeLUTSize; + int histBins = PIC_ANALYZE_CW_BINS; + int histLenth = totCW/histBins; + int log2HistLenth = g_aucLog2[histLenth]; + int16_t *tempFwdLUT = new int16_t[m_reshapeLUTSize + 1](); + int i, j; + int cwScaleBins1, cwScaleBins2; + int maxAllowedCW = totCW-1; + + cwScaleBins1 = m_reshapeCW.binCW[0]; + cwScaleBins2 = m_reshapeCW.binCW[1]; + + for (i = 0; i < histBins; i++) + usedCW += m_binCW[i]; + + if (usedCW > maxAllowedCW) + { + int cnt0 = 0, cnt1 = 0, cnt2 = 0; + for (i = 0; i < histBins; i++) + { + if (m_binCW[i] == histLenth + 1) cnt0++; + else if (m_binCW[i] == cwScaleBins1) cnt1++; + else if (m_binCW[i] == cwScaleBins2) cnt2++; + } + + int resCW = usedCW - maxAllowedCW; + int cwReduce1 = (cwScaleBins1 - histLenth - 1) * cnt1; + int cwReduce2 = (histLenth + 1 - cwScaleBins2) * cnt0; + + if (resCW <= cwReduce1) + { + int idx = 0; + while (resCW > 0) + { + if (m_binCW[idx] > (histLenth + 1)) + { + m_binCW[idx]--; + resCW--; + } + idx++; + if (idx == histBins) + idx = 0; + } + } + else if (resCW > cwReduce1 && resCW <= (cwReduce1 + cwReduce2)) + { + resCW -= cwReduce1; + int idx = 0; + while (resCW > 0) + { + if (m_binCW[idx] > cwScaleBins2 && m_binCW[idx] < cwScaleBins1) + { + m_binCW[idx]--; + resCW--; + } + idx++; + if (idx == histBins) + idx = 0; + } + for (i = 0; i < histBins; i++) + { + if (m_binCW[i] == cwScaleBins1) + m_binCW[i] = histLenth + 1; + } + } + else if (resCW > (cwReduce1 + cwReduce2)) + { + resCW -= (cwReduce1 + cwReduce2); + int idx = 0; + while (resCW > 0) + { + if (m_binCW[idx] > 0 && m_binCW[idx] < (histLenth + 1)) + { + m_binCW[idx]--; + resCW--; + } + idx++; + if (idx == histBins) + idx = 0; + } + for (i = 0; i < histBins; i++) + { + if (m_binCW[i] == histLenth + 1) + m_binCW[i] = cwScaleBins2; + if (m_binCW[i] == cwScaleBins1) + m_binCW[i] = histLenth + 1; + } + } + } + + if (bdShift != 0) + { + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + m_binCW[i] = bdShift > 0 ? m_binCW[i] * (1 << bdShift) : m_binCW[i] / (1 << (-bdShift)); + } + } + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + m_binCW[i] = m_binCW[2 * i] + m_binCW[2 * i + 1]; + } + m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; + m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + if (m_binCW[i] > 0) + { + m_sliceReshapeInfo.reshaperModelMinBinIdx = i; + break; + } + } + for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--) + { + if (m_binCW[i] > 0) + { + m_sliceReshapeInfo.reshaperModelMaxBinIdx = i; + break; + } + } + + int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0; + for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) + { + deltaCW = (int)m_binCW[i] - (int)m_initCW; + m_sliceReshapeInfo.reshaperModelBinCWDelta[i] = deltaCW; + absDeltaCW = (deltaCW < 0) ? (-deltaCW) : deltaCW; + if (absDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = absDeltaCW; } + } + m_sliceReshapeInfo.maxNbitsNeededDeltaCW = std::max(1, (int)g_aucLog2[maxAbsDeltaCW << 1]); + + histLenth = m_initCW; + log2HistLenth = g_aucLog2[histLenth]; + + int sumBins = 0; + for (i = 0; i < PIC_CODE_CW_BINS; i++) { sumBins += m_binCW[i]; } + CHECK(sumBins >= m_reshapeLUTSize, "SDR CW assignment is wrong!!"); + memset(tempFwdLUT, 0, (m_reshapeLUTSize + 1) * sizeof(int16_t)); + tempFwdLUT[0] = 0; + + for (i = 0; i < PIC_CODE_CW_BINS; i++) + { + tempFwdLUT[(i + 1)*histLenth] = tempFwdLUT[i*histLenth] + m_binCW[i]; + int16_t Y1 = tempFwdLUT[i*histLenth]; + int16_t Y2 = tempFwdLUT[(i + 1)*histLenth]; + m_reshapePivot[i + 1] = Y2; + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2HistLenth - 1))) >> (log2HistLenth); + m_fwdLUT[i*histLenth] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)Y1); + for (j = 1; j < histLenth; j++) + { + tempFwdLUT[i*histLenth + j] = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + m_fwdLUT[i*histLenth + j] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)tempFwdLUT[i*histLenth + j]); + } + } + + for (i = 0; i < PIC_CODE_CW_BINS; i++) + { + int start = i*histLenth; + int end = (i + 1)*histLenth - 1; + m_cwLumaWeight[i] = m_fwdLUT[end] - m_fwdLUT[start]; + } + + if (tempFwdLUT != nullptr) { delete[] tempFwdLUT; tempFwdLUT = nullptr; } + + reverseLUT(m_fwdLUT, m_invLUT, m_reshapeLUTSize); + updateChromaScaleLUT(); +} + +#endif +// +//! \} diff --git a/source/Lib/EncoderLib/EncReshape.h b/source/Lib/EncoderLib/EncReshape.h new file mode 100644 index 0000000000000000000000000000000000000000..81fc6a0b912f85858bfa820b503694e9f85f0b81 --- /dev/null +++ b/source/Lib/EncoderLib/EncReshape.h @@ -0,0 +1,153 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2019, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file EncReshape.h + \brief encoder reshaping header and class (header) + */ + +#ifndef __ENCRESHAPE__ +#define __ENCRESHAPE__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include "CommonLib/Reshape.h" +#if JVET_M0427_INLOOP_RESHAPER + +//! \ingroup EncoderLib +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +struct ModelInfo +{ + unsigned fullRangeInputFlag; + unsigned scaleIntPrec; + unsigned scaleInt; + unsigned scaleFracPrec; + unsigned scaleFrac; + unsigned scaleSign; + unsigned offsetIntPrec; + unsigned offsetInt; + unsigned offsetFracPrec; + unsigned offsetFrac; + unsigned offsetSign; + unsigned minMaxQPAbsPrec; + unsigned maxQPAbs; + unsigned maxQPSign; + unsigned minQPAbs; + unsigned minQPSign; + unsigned scaleAbs; + unsigned offsetAbs; +}; + +class EncReshape : public Reshape +{ +private: + bool m_srcReshaped; + int m_picWidth; + int m_picHeight; + uint32_t m_maxCUWidth; + uint32_t m_maxCUHeight; + uint32_t m_widthInCtus; + uint32_t m_heightInCtus; + uint32_t m_numCtuInFrame; + bool m_exceedSTD; + std::vector<uint32_t> m_binImportance; + int m_tcase; + int m_rateAdpMode; + bool m_useAdpCW; + uint16_t m_initCWAnalyze; + ModelInfo m_dQPModel; + ReshapeCW m_reshapeCW; + Pel m_cwLumaWeight[PIC_CODE_CW_BINS]; + double m_chromaWeight; + int m_chromaAdj; +public: + + EncReshape(); + ~EncReshape(); + + void createEnc( int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight, int bitDepth); + void destroy(); + + bool getSrcReshaped() { return m_srcReshaped; } + void setSrcReshaped(bool b) { m_srcReshaped = b; } +#if JVET_M0483_IBC + void preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT); + void preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT); +#else + void preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isIBC); + void preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isIBC); +#endif + void bubbleSortDsd(double *array, int * idx, int n); + void swap(int *xp, int *yp) { int temp = *xp; *xp = *yp; *yp = temp; } + void swap(double *xp, double *yp) { double temp = *xp; *xp = *yp; *yp = temp; } + void deriveReshapeParametersSDRfromStats(uint32_t *, double*, double* reshapeTH1, double* reshapeTH2, bool *intraAdp, bool *interAdp); + void deriveReshapeParameters(double *array, int start, int end, ReshapeCW respCW, double &alpha, double &beta); + void initLUTfromdQPModel(); + int calcEXP2(int val); + void constructReshaperSDR(); + ReshapeCW * getReshapeCW() { return &m_reshapeCW; } + Pel * getWeightTable() { return m_cwLumaWeight; } + double getCWeight() { return m_chromaWeight; } + + void initModelParam(double scale = 0.015, double offset = -7.5, int QPMax = 6, int QPMin = -3) + { + /// dQP model: dQP = clip3(QPMin, QPMax, dScale*Y+dOffset); + m_dQPModel.fullRangeInputFlag = 0; + m_dQPModel.scaleIntPrec = 0; + m_dQPModel.scaleFracPrec = 16; + m_dQPModel.offsetIntPrec = 3; + m_dQPModel.offsetFracPrec = 1; + m_dQPModel.minMaxQPAbsPrec = 3; + m_dQPModel.scaleSign = scale < 0 ? 1 : 0; + m_dQPModel.scaleAbs = unsigned((scale < 0 ? -scale : scale) * (1 << m_dQPModel.scaleFracPrec)); + m_dQPModel.scaleInt = m_dQPModel.scaleAbs >> m_dQPModel.scaleFracPrec; + m_dQPModel.scaleFrac = m_dQPModel.scaleAbs - (m_dQPModel.scaleInt << m_dQPModel.scaleFracPrec); + m_dQPModel.offsetSign = offset < 0 ? 1 : 0; + m_dQPModel.offsetAbs = unsigned((offset < 0 ? -offset : offset) * (1 << m_dQPModel.offsetFracPrec)); + m_dQPModel.offsetInt = m_dQPModel.offsetAbs >> m_dQPModel.offsetFracPrec; + m_dQPModel.offsetFrac = m_dQPModel.offsetAbs - (m_dQPModel.offsetInt << m_dQPModel.offsetFracPrec); + m_dQPModel.maxQPSign = QPMax < 0 ? 1 : 0; + m_dQPModel.maxQPAbs = m_dQPModel.maxQPSign ? -QPMax : QPMax; + m_dQPModel.minQPSign = QPMin < 0 ? 1 : 0; + m_dQPModel.minQPAbs = m_dQPModel.minQPSign ? -QPMin : QPMin; + } +};// END CLASS DEFINITION EncReshape + +//! \} +#endif +#endif diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp index a3bfa14a62b059b379adf1a8bd09d1ebf5334428..8e467b2eec9fe3c335f9602e6efbe696cce1ab3a 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp @@ -799,7 +799,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn SAOBlkParam modeParam; double minCost, modeCost; -#if K0238_SAO_GREEDY_MERGE_ENCODING +#if K0238_SAO_GREEDY_MERGE_ENCODING double minCost2 = 0; std::vector<SAOStatData**> groupBlkStat; if (isGreedymergeEncoding) @@ -919,7 +919,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn reconParams[ctuRsAddr] = codedParams[ctuRsAddr]; reconstructBlkSAOParam(reconParams[ctuRsAddr], mergeList); -#if K0238_SAO_GREEDY_MERGE_ENCODING +#if K0238_SAO_GREEDY_MERGE_ENCODING if (isGreedymergeEncoding) { if (ctuRsAddr == (mergeCtuAddr - 1)) @@ -1037,7 +1037,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn { #endif offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); -#if K0238_SAO_GREEDY_MERGE_ENCODING +#if K0238_SAO_GREEDY_MERGE_ENCODING } #endif diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 2843c2696bea129ad063b6216fcce17a90eed295..cf4585baee89c463ab3ff11b450158d6c80cf742 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -208,7 +208,7 @@ static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, con const uint32_t chrHeight = pcv.maxCUHeight >> getChannelTypeScaleY (CH_C, chrFmt); const int midLevel = 1 << (bitDepth - 1); int chrValue = MAX_INT; - avgLumaValue = (startAddr < boundingAddr) ? 0 : (uint32_t)pcPic->getOrigBuf().Y().mean(); + avgLumaValue = (startAddr < boundingAddr) ? 0 : (uint32_t)pcPic->getOrigBuf().Y().computeAvg(); if (ctuAddr >= 0) // luma { @@ -238,9 +238,9 @@ static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, con { const CompArea chrArea = clipArea (CompArea (compID, chrFmt, Area ((ctuAddr % pcv.widthInCtus) * chrWidth, (ctuAddr / pcv.widthInCtus) * chrHeight, chrWidth, chrHeight)), pcPic->block (compID)); - avgCompValue = pcPic->getOrigBuf (chrArea).mean(); + avgCompValue = pcPic->getOrigBuf (chrArea).computeAvg(); } - else avgCompValue = pcPic->getOrigBuf (pcPic->block (compID)).mean(); + else avgCompValue = pcPic->getOrigBuf (pcPic->block (compID)).computeAvg(); if (chrValue > avgCompValue) chrValue = avgCompValue; // minimum of the DC offsets } @@ -292,7 +292,7 @@ static int applyQPAdaptationChroma (Picture* const pcPic, Slice* const pcSlice, // change mean picture QP index based on picture's average luma value (Sharp) if (pcEncCfg->getLumaLevelToDeltaQPMapping().mode == LUMALVL_TO_DQP_NUM_MODES) { - if (meanLuma == MAX_UINT) meanLuma = pcPic->getOrigBuf().Y().mean(); + if (meanLuma == MAX_UINT) meanLuma = pcPic->getOrigBuf().Y().computeAvg(); averageAdaptedLumaQP = Clip3 (0, MAX_QP, averageAdaptedLumaQP + lumaDQPOffset (meanLuma, iBitDepth)); } @@ -339,8 +339,8 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr rpcSlice->setSliceBits(0); rpcSlice->setPic( pcPic ); rpcSlice->initSlice(); - int multipleFactor = pcPic->cs->sps->getSpsNext().getUseCompositeRef() ? 2 : 1; - if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && isEncodeLtRef) + int multipleFactor = pcPic->cs->sps->getUseCompositeRef() ? 2 : 1; + if (pcPic->cs->sps->getUseCompositeRef() && isEncodeLtRef) { rpcSlice->setPicOutputFlag(false); } @@ -600,7 +600,11 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr #endif if(rpcSlice->getPPS()->getSliceChromaQpFlag()) { +#if JVET_M0483_IBC + const bool bUseIntraOrPeriodicOffset = (rpcSlice->isIntra() && !rpcSlice->getSPS()->getIBCFlag()) || (m_pcCfg->getSliceChromaOffsetQpPeriodicity() > 0 && (rpcSlice->getPOC() % m_pcCfg->getSliceChromaOffsetQpPeriodicity()) == 0); +#else const bool bUseIntraOrPeriodicOffset = rpcSlice->isIntra() || (m_pcCfg->getSliceChromaOffsetQpPeriodicity() > 0 && (rpcSlice->getPOC() % m_pcCfg->getSliceChromaOffsetQpPeriodicity()) == 0); +#endif int cbQP = bUseIntraOrPeriodicOffset ? m_pcCfg->getSliceChromaOffsetQpIntraOrPeriodic(false) : m_pcCfg->getGOPEntry(iGOPid).m_CbQPoffset; int crQP = bUseIntraOrPeriodicOffset ? m_pcCfg->getSliceChromaOffsetQpIntraOrPeriodic(true) : m_pcCfg->getGOPEntry(iGOPid).m_CrQPoffset; @@ -883,7 +887,7 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, picOrig.height, picOrig.width, iBitDepth); hpEnerAvg += hpEner; pcPic->m_uEnerHpCtu[ctuRsAddr] = hpEner; - pcPic->m_iOffsetCtu[ctuRsAddr] = pcPic->getOrigBuf (ctuArea).mean(); + pcPic->m_iOffsetCtu[ctuRsAddr] = pcPic->getOrigBuf (ctuArea).computeAvg(); } hpEnerAvg /= double (boundingAddr - startAddr); @@ -1131,7 +1135,7 @@ static int applyQPAdaptationSubCtu (CodingStructure &cs, const UnitArea ctuArea, { const CompArea subArea = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (x, y, mts, mts)), pcPic->Y()); - subMLV[addr] = pcPic->getOrigBuf (subArea).mean(); + subMLV[addr] = pcPic->getOrigBuf (subArea).computeAvg(); } #endif } @@ -1337,9 +1341,6 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c // effectively disabling the slice-segment-mode. Slice* const pcSlice = pcPic->slices[getSliceSegmentIdx()]; -#if HEVC_TILES_WPP - const TileMap& tileMap = *pcPic->tileMap; -#endif uint32_t startCtuTsAddr; uint32_t boundingCtuTsAddr; @@ -1411,6 +1412,7 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c #if HEVC_TILES_WPP // Adjust initial state if this is the start of a dependent slice. { + const TileMap& tileMap = *pcPic->tileMap; const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( startCtuTsAddr); const uint32_t currentTileIdx = tileMap.getTileIdxMap(ctuRsAddr); const Tile& currentTile = tileMap.tiles[currentTileIdx]; @@ -1453,7 +1455,11 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c cs.pcv = pcSlice->getPPS()->pcv; cs.fracBits = 0; - if (startCtuTsAddr == 0) +#if JVET_M0055_DEBUG_CTU + if( startCtuTsAddr == 0 && ( pcSlice->getPOC() != m_pcCfg->getSwitchPOC() || -1 == m_pcCfg->getDebugCTU() ) ) +#else + if( startCtuTsAddr == 0 ) +#endif { cs.initStructData (pcSlice->getSliceQp(), pcSlice->getPPS()->getTransquantBypassEnabledFlag()); } @@ -1530,8 +1536,54 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c } +#if JVET_M0255_FRACMMVD_SWITCH +void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr ) +{ + CodingStructure& cs = *pcPic->cs; + Slice* pcSlice = cs.slice; + const PreCalcValues& pcv = *cs.pcv; + const uint32_t widthInCtus = pcv.widthInCtus; +#if HEVC_TILES_WPP + const TileMap& tileMap = *pcPic->tileMap; +#endif + const uint32_t hashThreshold = 20; + uint32_t totalCtu = 0; + uint32_t hashRatio = 0; + + if ( !pcSlice->getSPS()->getDisFracMmvdEnabledFlag() ) + { + return; + } + + for ( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) + { +#if HEVC_TILES_WPP + const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr ); +#else + const uint32_t ctuRsAddr = ctuTsAddr; +#endif + const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; + const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; + const Position pos ( ctuXPosInCtus * pcv.maxCUWidth, ctuYPosInCtus * pcv.maxCUHeight ); + const UnitArea ctuArea( cs.area.chromaFormat, Area( pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight ) ); + + hashRatio += m_pcCuEncoder->getIbcHashMap().getHashHitRatio( ctuArea.Y() ); + totalCtu++; + } + if ( hashRatio > totalCtu * hashThreshold ) + { + pcSlice->setDisFracMMVD( true ); + } +#if JVET_M0854_FRACMMVD_SWITCH_FOR_UHD + if (!pcSlice->getDisFracMMVD()) { + bool useIntegerMVD = (pcPic->lwidth()*pcPic->lheight() > 1920 * 1080); + pcSlice->setDisFracMMVD( useIntegerMVD ); + } +#endif +} +#endif void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr, EncLib* pEncLib ) { @@ -1582,15 +1634,50 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons #if HEVC_DEPENDENT_SLICES } #endif - +#if JVET_M0255_FRACMMVD_SWITCH + if ( pcSlice->getSPS()->getDisFracMmvdEnabledFlag() || +#if JVET_M0483_IBC + (pcSlice->getSPS()->getIBCFlag() && m_pcCuEncoder->getEncCfg()->getIBCHashSearch())) +#else + ( pcSlice->getSPS()->getIBCMode() && m_pcCuEncoder->getEncCfg()->getIBCHashSearch() ) ) +#endif + { +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (pcSlice->getSPS()->getUseReshaper() && m_pcLib->getReshaper()->getCTUFlag() && pcSlice->getSPS()->getIBCFlag()) +#else + if (pcSlice->getSPS()->getUseReshaper() && m_pcLib->getReshaper()->getCTUFlag() && pcSlice->getSPS()->getIBCMode()) +#endif + cs.picture->getOrigBuf(COMPONENT_Y).rspSignal(m_pcLib->getReshaper()->getFwdLUT()); +#endif + m_pcCuEncoder->getIbcHashMap().rebuildPicHashMap( cs.picture->getOrigBuf() ); +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (pcSlice->getSPS()->getUseReshaper() && m_pcLib->getReshaper()->getCTUFlag() && pcSlice->getSPS()->getIBCFlag()) +#else + if (pcSlice->getSPS()->getUseReshaper() && m_pcLib->getReshaper()->getCTUFlag() && pcSlice->getSPS()->getIBCMode()) +#endif + cs.picture->getOrigBuf().copyFrom(cs.picture->getTrueOrigBuf()); +#endif + } + checkDisFracMmvd( pcPic, startCtuTsAddr, boundingCtuTsAddr ); +#endif // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment) for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) { +#if JVET_M0055_DEBUG_CTU +#if HEVC_TILES_WPP + const int32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr ); +#else + const int32_t ctuRsAddr = ctuTsAddr; +#endif +#else #if HEVC_TILES_WPP const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap(ctuTsAddr); #else const uint32_t ctuRsAddr = ctuTsAddr; #endif +#endif #if HEVC_TILES_WPP // update CABAC state @@ -1604,6 +1691,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons const UnitArea ctuArea( cs.area.chromaFormat, Area( pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight ) ); DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) ); +#if JVET_M0055_DEBUG_CTU + if( pCfg->getSwitchPOC() != pcPic->poc || -1 == pCfg->getDebugCTU() ) +#endif if ( pcSlice->getSliceType() != I_SLICE && ctuXPosInCtus == 0) { pcSlice->resetMotionLUTs(); @@ -1714,7 +1804,16 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons resetGbiCodingOrder(false, cs); m_pcInterSearch->initWeightIdxBits(); } +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + if (pcSlice->getSPS()->getUseReshaper()) + { + m_pcCuEncoder->setDecCuReshaperInEncCU(m_pcLib->getReshaper(), pcSlice->getSPS()->getChromaFormatIdc()); + } +#endif +#if JVET_M0055_DEBUG_CTU + if (pCfg->getSwitchPOC() != pcPic->poc || ctuRsAddr >= pCfg->getDebugCTU()) +#endif #if ENABLE_WPP_PARALLELISM pEncLib->getCuEncoder( dataId )->compressCtu( cs, ctuArea, ctuRsAddr, prevQP, currQP ); #else diff --git a/source/Lib/EncoderLib/EncSlice.h b/source/Lib/EncoderLib/EncSlice.h index 39dca4341792cc7f13838691c458417380d64734..7314ca287c92b95f69de9f5cba362641ea72994b 100644 --- a/source/Lib/EncoderLib/EncSlice.h +++ b/source/Lib/EncoderLib/EncSlice.h @@ -146,7 +146,9 @@ public: static #endif void encodeCtus ( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr, EncLib* pcEncLib ); - +#if JVET_M0255_FRACMMVD_SWITCH + void checkDisFracMmvd ( Picture* pcPic, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr ); +#endif // misc. functions void setSearchRange ( Slice* pcSlice ); ///< set ME range adaptively diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index cad55ecf97b431ed446a4f85cea1a22aa389b9a3..1bcf318383da0753ecf6d41a841649cc469c069f 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -89,6 +89,9 @@ InterSearch::InterSearch() , m_pFullCS (nullptr) , m_pcEncCfg (nullptr) , m_pcTrQuant (nullptr) +#if JVET_M0427_INLOOP_RESHAPER + , m_pcReshape (nullptr) +#endif , m_iSearchRange (0) , m_bipredSearchRange (0) , m_motionEstimationSearchMethod(MESEARCH_FULL) @@ -110,6 +113,10 @@ InterSearch::InterSearch() m_affMVList = nullptr; m_affMVListSize = 0; m_affMVListIdx = 0; +#if JVET_M0140_SBT + m_histBestSbt = MAX_UCHAR; + m_histBestMtsIdx = MAX_UCHAR; +#endif } @@ -193,6 +200,9 @@ void InterSearch::init( EncCfg* pcEncCfg, RdCost* pcRdCost, CABACWriter* CABACEstimator, CtxCache* ctxCache +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* pcReshape +#endif ) { CHECK(m_isInitialized, "Already initialized"); @@ -205,6 +215,9 @@ void InterSearch::init( EncCfg* pcEncCfg, m_motionEstimationSearchMethod = motionEstimationSearchMethod; m_CABACEstimator = CABACEstimator; m_CtxCache = ctxCache; +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshape = pcReshape; +#endif for( uint32_t iDir = 0; iDir < MAX_NUM_REF_LIST_ADAPT_SR; iDir++ ) { @@ -251,6 +264,58 @@ void InterSearch::init( EncCfg* pcEncCfg, m_isInitialized = true; } +#if JVET_M0246_AFFINE_AMVR +void InterSearch::resetSavedAffineMotion() +{ + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 2; j++ ) + { + m_affineMotion.acMvAffine4Para[i][j] = Mv( 0, 0 ); + m_affineMotion.acMvAffine6Para[i][j] = Mv( 0, 0 ); + } + m_affineMotion.acMvAffine6Para[i][2] = Mv( 0, 0 ); + + m_affineMotion.affine4ParaRefIdx[i] = -1; + m_affineMotion.affine6ParaRefIdx[i] = -1; + } + for ( int i = 0; i < 3; i++ ) + { + m_affineMotion.hevcCost[i] = std::numeric_limits<Distortion>::max(); + } + m_affineMotion.affine4ParaAvail = false; + m_affineMotion.affine6ParaAvail = false; +} + +void InterSearch::storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int gbiIdx ) +{ + if ( ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine6ParaAvail ) && affineType == AFFINEMODEL_6PARAM ) + { + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 3; j++ ) + { + m_affineMotion.acMvAffine6Para[i][j] = acAffineMv[i][j]; + } + m_affineMotion.affine6ParaRefIdx[i] = affineRefIdx[i]; + } + m_affineMotion.affine6ParaAvail = true; + } + + if ( ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine4ParaAvail ) && affineType == AFFINEMODEL_4PARAM ) + { + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 2; j++ ) + { + m_affineMotion.acMvAffine4Para[i][j] = acAffineMv[i][j]; + } + m_affineMotion.affine4ParaRefIdx[i] = affineRefIdx[i]; + } + m_affineMotion.affine4ParaAvail = true; + } +} +#endif inline void InterSearch::xTZSearchHelp( IntTZSearchStruct& rcStruct, const int iSearchX, const int iSearchY, const uint8_t ucPointNr, const uint32_t uiDistance ) { @@ -645,6 +710,12 @@ Distortion InterSearch::xPatternRefinement( const CPelBuf* pcPatternKey, const Mv* pcMvRefine = (iFrac == 2 ? s_acMvRefineH : s_acMvRefineQ); for (uint32_t i = 0; i < 9; i++) { +#if JVET_M0253_HASH_ME + if (m_skipFracME && i > 0) + { + break; + } +#endif Mv cMvTest = pcMvRefine[i]; cMvTest += baseRefMv; @@ -762,7 +833,11 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu, pu.mv[0] = cMVCand[cand]; pu.mv[0].changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL); pu.interDir = 1; +#if JVET_M0483_IBC + pu.refIdx[0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0); // last idx in the list +#else pu.refIdx[0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list +#endif PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_0].getBuf(UnitAreaRelative(*pu.cu, pu)); motionCompensation(pu, predBufTmp, REF_PIC_LIST_0); @@ -913,7 +988,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS if (validCand) { - sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * yPred + xPred; sad += m_cDistParam.distFunc(m_cDistParam); @@ -935,7 +1010,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } - sad = m_pcRdCost->getBvCostMultiplePreds(0, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(0, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y; sad += m_cDistParam.distFunc(m_cDistParam); @@ -960,7 +1035,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } - sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -981,7 +1056,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS bestX = cMVCand[0].getHor(); bestY = cMVCand[0].getVer(); sadBest = sadBestCand[0]; - if ((!bestX && !bestY) || (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL) <= 32)) + if ((!bestX && !bestY) || (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag()) <= 32)) { //chroma refine bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand); @@ -1011,7 +1086,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } - sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -1022,7 +1097,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS bestX = cMVCand[0].getHor(); bestY = cMVCand[0].getVer(); sadBest = sadBestCand[0]; - if (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL) <= 16) + if (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag()) <= 16) { //chroma refine bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand); @@ -1051,7 +1126,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } - sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -1075,7 +1150,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS bestY = cMVCand[0].getVer(); sadBest = sadBestCand[0]; - if ((sadBest >= tempSadBest) || ((sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL)) <= 32)) + if ((sadBest >= tempSadBest) || ((sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag())) <= 32)) { //chroma refine bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand); @@ -1108,7 +1183,7 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } - sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL); + sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -1216,6 +1291,18 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, CPelBuf tmpPattern = pBuf->Y(); CPelBuf* pcPatternKey = &tmpPattern; +#if JVET_M0427_INLOOP_RESHAPER + if ((pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())) + { + const CompArea &area = pu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpOrgLuma = m_tmpStorageLCU.getBuf(tmpArea); + tmpOrgLuma.copyFrom(tmpPattern); + tmpOrgLuma.rspSignal(m_pcReshape->getFwdLUT()); + pcPatternKey = (CPelBuf*)&tmpOrgLuma; + } +#endif + m_lumaClpRng = pu.cs->slice->clpRng(COMPONENT_Y); Picture* refPic = pu.cu->slice->getPic(); @@ -1270,10 +1357,10 @@ void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iR rcMvSrchRngLT <<= 2; rcMvSrchRngRB <<= 2; - clipMv(rcMvSrchRngLT, pu.cu->lumaPos(), + xClipMv(rcMvSrchRngLT, pu.cu->lumaPos(), pu.cu->lumaSize(), sps); - clipMv(rcMvSrchRngRB, pu.cu->lumaPos(), + xClipMv(rcMvSrchRngRB, pu.cu->lumaPos(), pu.cu->lumaSize(), sps); rcMvSrchRngLT >>= 2; @@ -1282,9 +1369,11 @@ void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iR bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap) { +#if JVET_M0483_IBC==0 // check only no greater than IBC_MAX_CAND_SIZE if (cu.Y().width > IBC_MAX_CAND_SIZE || cu.Y().height > IBC_MAX_CAND_SIZE) return false; +#endif Mv cMvSrchRngLT; Mv cMvSrchRngRB; @@ -1300,13 +1389,20 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const /// ibc search pu.cu->imv = 2; AMVPInfo amvpInfo4Pel; +#if JVET_M0483_IBC + PU::fillIBCMvpCand(pu, amvpInfo4Pel); +#else PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo4Pel); +#endif - - pu.cu->imv = 0;// (Int)cu.cs->sps->getSpsNext().getUseIMV(); // set as IMV=0 initially + pu.cu->imv = 0;// (Int)cu.cs->sps->getUseIMV(); // set as IMV=0 initially Mv cMv, cMvPred[2]; AMVPInfo amvpInfo; +#if JVET_M0483_IBC + PU::fillIBCMvpCand(pu, amvpInfo); +#else PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo); +#endif cMvPred[0].set(amvpInfo.mvCand[0].getHor() >> (2), amvpInfo.mvCand[0].getVer() >> (2)); // store in full pel accuracy, shift before use in search cMvPred[1].set(amvpInfo.mvCand[1].getHor() >> (2), amvpInfo.mvCand[1].getVer() >> (2)); @@ -1348,7 +1444,7 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const bitsBVPBest = bitsBVPTemp; bvpIdxBest = bvpIdxTemp; - if (cu.cs->sps->getSpsNext().getImvMode() && cMv != cMvPred[bvpIdxTemp]) + if (cu.cs->sps->getAMVREnabledFlag() && cMv != cMvPred[bvpIdxTemp]) pu.cu->imv = 1; // set as full-pel else pu.cu->imv = 0; // set as fractional-pel @@ -1359,7 +1455,7 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const Mv mvPredQuadPel; - if ((cMv.getHor() % 4 == 0) && (cMv.getVer() % 4 == 0) && (pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL)) + if ((cMv.getHor() % 4 == 0) && (cMv.getVer() % 4 == 0) && (pu.cs->sps->getAMVREnabledFlag())) { mvPredQuadPel = amvpInfo4Pel.mvCand[bvpIdxTemp];// cMvPred[bvpIdxTemp]; @@ -1376,7 +1472,7 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const bitsBVPBest = bitsBVPQP; bvpIdxBest = bvpIdxTemp; - if (cu.cs->sps->getSpsNext().getImvMode()) + if (cu.cs->sps->getAMVREnabledFlag()) pu.cu->imv = 2; // set as quad-pel } @@ -1397,13 +1493,17 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const pu.cu->imv = 0; if (pu.cu->imv == 2) assert((cMv.getHor() % 16 == 0) && (cMv.getVer() % 16 == 0)); - if (cu.cs->sps->getSpsNext().getUseIMV()) + if (cu.cs->sps->getAMVREnabledFlag()) assert(pu.cu->imv>0 || pu.mvd[REF_PIC_LIST_0] == Mv()); - if (!cu.cs->sps->getSpsNext().getUseIMV()) + if (!cu.cs->sps->getAMVREnabledFlag()) pu.mvd[REF_PIC_LIST_0] >>= (2); +#if JVET_M0483_IBC + pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; +#else pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; +#endif pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); m_ctuRecord[cu.lumaPos()][cu.lumaSize()].bvRecord[pu.bv] = cost; @@ -1458,7 +1558,7 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, } int costQuadPel = MAX_UINT; - if ((candMv.getHor() % 4 == 0) && (candMv.getVer() % 4 == 0) && (pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL)) + if ((candMv.getHor() % 4 == 0) && (candMv.getVer() % 4 == 0) && (pu.cs->sps->getAMVREnabledFlag())) { Mv mvPredQuadPel; int imvShift = 2; @@ -1486,6 +1586,316 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, } +#if JVET_M0253_HASH_ME +void InterSearch::addToSortList(std::list<BlockHash>& listBlockHash, std::list<int>& listCost, int cost, const BlockHash& blockHash) +{ + std::list<BlockHash>::iterator itBlockHash = listBlockHash.begin(); + std::list<int>::iterator itCost = listCost.begin(); + + while (itCost != listCost.end()) + { + if (cost < (*itCost)) + { + listCost.insert(itCost, cost); + listBlockHash.insert(itBlockHash, blockHash); + return; + } + + ++itCost; + ++itBlockHash; + } + + listCost.push_back(cost); + listBlockHash.push_back(blockHash); +} + +void InterSearch::selectMatchesInter(const MapIterator& itBegin, int count, std::list<BlockHash>& listBlockHash, const BlockHash& currBlockHash) +{ + const int maxReturnNumber = 5; + + listBlockHash.clear(); + std::list<int> listCost; + listCost.clear(); + + MapIterator it = itBegin; + for (int i = 0; i < count; i++, it++) + { + if ((*it).hashValue2 != currBlockHash.hashValue2) + { + continue; + } + + int currCost = RdCost::xGetExpGolombNumberOfBits((*it).x - currBlockHash.x) + + RdCost::xGetExpGolombNumberOfBits((*it).y - currBlockHash.y); + + if (listBlockHash.size() < maxReturnNumber) + { + addToSortList(listBlockHash, listCost, currCost, (*it)); + } + else if (!listCost.empty() && currCost < listCost.back()) + { + listCost.pop_back(); + listBlockHash.pop_back(); + addToSortList(listBlockHash, listCost, currCost, (*it)); + } + } +} + +int InterSearch::xHashInterPredME(const PredictionUnit& pu, RefPicList currRefPicList, int currRefPicIndex, Mv bestMv[5]) +{ + int width = pu.cu->lumaSize().width; + int height = pu.cu->lumaSize().height; + int xPos = pu.cu->lumaPos().x; + int yPos = pu.cu->lumaPos().y; + + uint32_t hashValue1; + uint32_t hashValue2; + + if (!TComHash::getBlockHashValue((pu.cs->picture->getOrigBuf()), width, height, xPos, yPos, pu.cu->slice->getSPS()->getBitDepths(), hashValue1, hashValue2)) + { + return 0; + } + BlockHash currBlockHash; + currBlockHash.x = xPos; + currBlockHash.y = yPos; + currBlockHash.hashValue2 = hashValue2; + + int count = static_cast<int>(pu.cu->slice->getRefPic(currRefPicList, currRefPicIndex)->getHashMap()->count(hashValue1)); + if (count == 0) + { + return 0; + } + + list<BlockHash> listBlockHash; + selectMatchesInter(pu.cu->slice->getRefPic(currRefPicList, currRefPicIndex)->getHashMap()->getFirstIterator(hashValue1), count, listBlockHash, currBlockHash); + + if (listBlockHash.empty()) + { + return 0; + } + + int totalSize = 0; + list<BlockHash>::iterator it = listBlockHash.begin(); + for (int i = 0; i < 5 && i < listBlockHash.size(); i++, it++) + { + bestMv[i].set((*it).x - currBlockHash.x, (*it).y - currBlockHash.y); + totalSize++; + } + + return totalSize; +} + +bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch) +{ + int width = pu.cu->lumaSize().width; + int height = pu.cu->lumaSize().height; + int xPos = pu.cu->lumaPos().x; + int yPos = pu.cu->lumaPos().y; + + uint32_t hashValue1; + uint32_t hashValue2; + Distortion bestCost = UINT64_MAX; + + if (!TComHash::getBlockHashValue((pu.cs->picture->getOrigBuf()), width, height, xPos, yPos, pu.cu->slice->getSPS()->getBitDepths(), hashValue1, hashValue2)) + { + return false; + } + + BlockHash currBlockHash; + currBlockHash.x = xPos; + currBlockHash.y = yPos; + currBlockHash.hashValue2 = hashValue2; + + m_pcRdCost->setDistParam(m_cDistParam, pu.cs->getOrgBuf(pu).Y(), 0, 0, m_lumaClpRng.bd, COMPONENT_Y, 0, 1, false); + + int imvBest = 0; + + int numPredDir = pu.cu->slice->isInterP() ? 1 : 2; + for (int refList = 0; refList < numPredDir; refList++) + { + RefPicList eRefPicList = (refList == 0) ? REF_PIC_LIST_0 : REF_PIC_LIST_1; + int refPicNumber = pu.cu->slice->getNumRefIdx(eRefPicList); + +#if JVET_M0483_IBC + if (pu.cs->slice->getSPS()->getIBCFlag() && eRefPicList == REF_PIC_LIST_0) +#else + if (pu.cs->slice->getSPS()->getIBCMode() && eRefPicList == REF_PIC_LIST_0) +#endif + { + refPicNumber--; + } + + for (int refIdx = 0; refIdx < refPicNumber; refIdx++) + { + int bitsOnRefIdx = refIdx + 1; + if (refIdx + 1 == refPicNumber) + { + bitsOnRefIdx--; + } + + if (refList == 0 || pu.cu->slice->getList1IdxToList0Idx(refIdx) < 0) + { + int count = static_cast<int>(pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->count(hashValue1)); + if (count == 0) + { + continue; + } + + list<BlockHash> listBlockHash; + selectMatchesInter(pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->getFirstIterator(hashValue1), count, listBlockHash, currBlockHash); + + if (listBlockHash.empty()) + { + continue; + } + AMVPInfo currAMVPInfoPel; + AMVPInfo currAMVPInfo4Pel; + pu.cu->imv = 2; + PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfo4Pel); + pu.cu->imv = 1; + PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfoPel); + CHECK(currAMVPInfoPel.numCand <= 1, "Wrong") + + const Pel* refBufStart = pu.cu->slice->getRefPic(eRefPicList, refIdx)->getRecoBuf().get(COMPONENT_Y).buf; + const int refStride = pu.cu->slice->getRefPic(eRefPicList, refIdx)->getRecoBuf().get(COMPONENT_Y).stride; + + m_cDistParam.cur.stride = refStride; + + m_pcRdCost->selectMotionLambda(pu.cu->transQuantBypass); + m_pcRdCost->setCostScale(0); + + list<BlockHash>::iterator it; + for (it = listBlockHash.begin(); it != listBlockHash.end(); ++it) + { + int curMVPIdx = 0; + unsigned int curMVPbits = MAX_UINT; + Mv cMv((*it).x - currBlockHash.x, (*it).y - currBlockHash.y); + + for (int mvpIdxTemp = 0; mvpIdxTemp < 2; mvpIdxTemp++) + { + Mv cMvPredPel = currAMVPInfoPel.mvCand[mvpIdxTemp]; + cMvPredPel >>= 2; + m_pcRdCost->setPredictor(cMvPredPel); + + unsigned int tempMVPbits = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0); + + if (tempMVPbits < curMVPbits) + { + curMVPbits = tempMVPbits; + curMVPIdx = mvpIdxTemp; + pu.cu->imv = 1; + } + + if ((cMv.getHor() % 4 == 0) && (cMv.getVer() % 4 == 0)) + { + unsigned int bitsMVP4Pel = MAX_UINT; + Mv mvPredQuadPel = currAMVPInfo4Pel.mvCand[mvpIdxTemp]; + mvPredQuadPel >>= 4; + m_pcRdCost->setPredictor(mvPredQuadPel); + bitsMVP4Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor() >> 2, cMv.getVer() >> 2, 0); + + if (bitsMVP4Pel < curMVPbits) + { + curMVPbits = bitsMVP4Pel; + curMVPIdx = mvpIdxTemp; + pu.cu->imv = 2; + } + } + } + + curMVPbits += bitsOnRefIdx; + + m_cDistParam.cur.buf = refBufStart + (*it).y*refStride + (*it).x; + Distortion currSad = m_cDistParam.distFunc(m_cDistParam); + Distortion currCost = currSad + m_pcRdCost->getCost(curMVPbits); + + if (!isPerfectMatch) + { + if (pu.cu->slice->getRefPic(eRefPicList, refIdx)->slices[0]->getSliceQp() <= pu.cu->slice->getSliceQp()) + { + isPerfectMatch = true; + } + } + + if (currCost < bestCost) + { + cMv <<= 2; + bestCost = currCost; + bestRefPicList = eRefPicList; + bestRefIndex = refIdx; + bestMv = cMv; + bestMVPIndex = curMVPIdx; + imvBest = pu.cu->imv; + if (pu.cu->imv == 2) + { + bestMvd = cMv - currAMVPInfo4Pel.mvCand[curMVPIdx]; + } + else if (pu.cu->imv == 1) + { + bestMvd = cMv - currAMVPInfoPel.mvCand[curMVPIdx]; + } + } + } + } + } + } + pu.cu->imv = imvBest; + if (bestMvd == Mv(0, 0)) + { + pu.cu->imv = 0; + return false; + } + return (bestCost < MAX_INT); +} + +bool InterSearch::predInterHashSearch(CodingUnit& cu, Partitioner& partitioner, bool& isPerfectMatch) +{ + Mv bestMv, bestMvd; + RefPicList bestRefPicList; + int bestRefIndex; + int bestMVPIndex; + + auto &pu = *cu.firstPU; + + Mv cMvZero; + pu.mv[REF_PIC_LIST_0] = Mv(); + pu.mv[REF_PIC_LIST_1] = Mv(); + pu.mvd[REF_PIC_LIST_0] = cMvZero; + pu.mvd[REF_PIC_LIST_1] = cMvZero; + pu.refIdx[REF_PIC_LIST_0] = NOT_VALID; + pu.refIdx[REF_PIC_LIST_1] = NOT_VALID; + pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID; + pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID; + pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID; + pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID; + + if (xHashInterEstimation(pu, bestRefPicList, bestRefIndex, bestMv, bestMvd, bestMVPIndex, isPerfectMatch)) + { + pu.interDir = static_cast<int>(bestRefPicList) + 1; + pu.mv[bestRefPicList] = bestMv; + pu.mv[bestRefPicList].hor <<= MV_FRACTIONAL_BITS_DIFF; + pu.mv[bestRefPicList].ver <<= MV_FRACTIONAL_BITS_DIFF; + + pu.mvd[bestRefPicList] = bestMvd; + pu.refIdx[bestRefPicList] = bestRefIndex; + pu.mvpIdx[bestRefPicList] = bestMVPIndex; + + pu.mvpNum[bestRefPicList] = 2; + + PU::spanMotionInfo(pu); + PelUnitBuf predBuf = pu.cs->getPredBuf(pu); + motionCompensation(pu, predBuf, REF_PIC_LIST_X); + return true; + } + else + { + return false; + } + + return true; +} +#endif + //! search of the best candidate for inter prediction void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) @@ -1540,6 +1950,25 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uint32_t puIdx = 0; auto &pu = *cu.firstPU; +#if JVET_M0246_AFFINE_AMVR + bool checkAffine = pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag(); + bool checkNonAffine = pu.cu->imv == 0 || ( pu.cu->slice->getSPS()->getAMVREnabledFlag() && + pu.cu->imv <= (pu.cu->slice->getSPS()->getAMVREnabledFlag() ? IMV_4PEL : 0)); + CodingUnit *bestCU = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr; +#if JVET_M0444_SMVD + bool trySmvd = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true; +#endif + if ( pu.cu->imv && bestCU != nullptr && checkAffine ) + { + checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine ); + } + + if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() ) + { + checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f; + } +#endif + { // motion estimation only evaluates luma component m_maxCompIDToPred = MAX_NUM_COMPONENT; @@ -1583,16 +2012,24 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) m_pcRdCost->selectMotionLambda( cu.transQuantBypass ); unsigned imvShift = pu.cu->imv << 1; +#if JVET_M0246_AFFINE_AMVR + if ( checkNonAffine ) + { +#endif // Uni-directional prediction for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) { RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); - int refPicNumber = cs.slice->getNumRefIdx(eRefPicList); - if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0) +#if JVET_M0483_IBC==0 + int refPicNumber = cs.sl#ice->getNumRefIdx(eRefPicList); + if (cs.slice->getSPS()->getIBCMode() && eRefPicList == REF_PIC_LIST_0) { refPicNumber--; } for (int iRefIdxTemp = 0; iRefIdxTemp < refPicNumber; iRefIdxTemp++) +#else + for (int iRefIdxTemp = 0; iRefIdxTemp < cs.slice->getNumRefIdx(eRefPicList); iRefIdxTemp++) +#endif { uiBitsTemp = uiMbBits[iRefList]; if ( cs.slice->getNumRefIdx(eRefPicList) > 1 ) @@ -1640,7 +2077,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] ); } - if( cu.cs->sps->getSpsNext().getUseGBi() && cu.GBiIdx == GBI_DEFAULT && cu.cs->slice->isInterB() ) + if( cu.cs->sps->getUseGBi() && cu.GBiIdx == GBI_DEFAULT && cu.cs->slice->isInterB() ) { const bool checkIdentical = true; m_uniMotions.setReadMode(checkIdentical, (uint32_t)iRefList, (uint32_t)iRefIdxTemp); @@ -1676,15 +2113,19 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } } - if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() + if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine() +#if JVET_M0246_AFFINE_AMVR + && checkAffine +#else && cu.imv == 0 +#endif && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast()) ) { ::memcpy( cMvHevcTemp, cMvTemp, sizeof( cMvTemp ) ); } // Bi-predictive Motion estimation - if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false ) + if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false ) && (cu.slice->getCheckLDC() || gbiIdx == GBI_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseGBiFast()) ) { @@ -1794,10 +2235,12 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) iRefStart = 0; iRefEnd = cs.slice->getNumRefIdx(eRefPicList)-1; - if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0) +#if JVET_M0483_IBC==0 + if (cs.slice->getSPS()->getIBCMode() && eRefPicList == REF_PIC_LIST_0) { iRefEnd--; } +#endif for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++) { if( m_pcEncCfg->getUseGBiFast() && (gbiIdx != GBI_DEFAULT) @@ -1807,7 +2250,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) continue; } uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList]; - uiBitsTemp += ((cs.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); + uiBitsTemp += ((cs.slice->getSPS()->getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); if ( cs.slice->getNumRefIdx(eRefPicList) > 1 ) { uiBitsTemp += iRefIdxTemp+1; @@ -1836,7 +2279,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiCostBi = uiCostTemp; uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList]; - uiMotBits[iRefList] -= ((cs.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); + uiMotBits[iRefList] -= ((cs.slice->getSPS()->getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); uiBits[2] = uiBitsTemp; if(iNumIter!=1) @@ -1871,7 +2314,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cu.refIdxBi[1] = iRefIdxBi[1]; #if JVET_M0444_SMVD +#if JVET_M0246_AFFINE_AMVR + if ( cs.slice->getBiDirPred() && trySmvd ) +#else if ( cs.slice->getBiDirPred() ) +#endif { Distortion symCost; Mv cMvPredSym[2]; @@ -1941,7 +2388,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) Distortion mvpCost = m_pcRdCost->getCost(m_auiMVPIdxCost[mvpIdxSym[curRefList]][AMVP_MAX_NUM_CANDS] + m_auiMVPIdxCost[mvpIdxSym[tarRefList]][AMVP_MAX_NUM_CANDS]); symCost = costStart - mvpCost; - + // ME xSymmetricMotionEstimation( pu, origBuf, cMvPredSym[curRefList], cMvPredSym[tarRefList], eCurRefList, cCurMvField, cTarMvField, symCost, gbiIdx ); @@ -1953,8 +2400,8 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } bits = uiMbBits[2]; - bits += 1; // add one bit for symmetrical MVD mode - bits += ((cs.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); + bits += 1; // add one bit for #symmetrical MVD mode + bits += ((cs.slice->getSPS()->getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0); symCost += m_pcRdCost->getCost(bits); cTarMvField.setMvField(cCurMvField.mv.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar); @@ -2011,8 +2458,8 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiLastMode = 2; pu.mv [REF_PIC_LIST_0] = cMvBi[0]; pu.mv [REF_PIC_LIST_1] = cMvBi[1]; - pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - pu.mv[REF_PIC_LIST_1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + pu.mv[REF_PIC_LIST_1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); pu.mvd [REF_PIC_LIST_0] = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]]; pu.mvd [REF_PIC_LIST_1] = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]]; pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0]; @@ -2031,7 +2478,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { uiLastMode = 0; pu.mv [REF_PIC_LIST_0] = cMv[0]; - pu.mv [REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + pu.mv [REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); pu.mvd [REF_PIC_LIST_0] = cMv[0] - cMvPred[0][iRefIdx[0]]; pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0]; pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]]; @@ -2042,7 +2489,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { uiLastMode = 1; pu.mv [REF_PIC_LIST_1] = cMv[1]; - pu.mv [REF_PIC_LIST_1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + pu.mv [REF_PIC_LIST_1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); pu.mvd [REF_PIC_LIST_1] = cMv[1] - cMvPred[1][iRefIdx[1]]; pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1]; pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]]; @@ -2056,7 +2503,15 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } uiHevcCost = ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) ? uiCostBi : ( ( uiCost[0] <= uiCost[1] ) ? uiCost[0] : uiCost[1] ); - if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() && cu.imv == 0 +#if JVET_M0246_AFFINE_AMVR + } +#endif + if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine() +#if JVET_M0246_AFFINE_AMVR + && checkAffine +#else + && cu.imv == 0 +#endif && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast()) ) { @@ -2088,8 +2543,16 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) int refIdx4Para[2] = { -1, -1 }; xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, gbiIdx, enforceGBiPred, - ((cu.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); - if ( cu.slice->getSPS()->getSpsNext().getUseAffineType() ) + ((cu.slice->getSPS()->getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); + +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { + storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, gbiIdx ); + } +#endif + + if ( cu.slice->getSPS()->getUseAffineType() ) { if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME { @@ -2122,7 +2585,14 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) Distortion uiAffine6Cost = std::numeric_limits<Distortion>::max(); cu.affineType = AFFINEMODEL_6PARAM; xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, gbiIdx, enforceGBiPred, - ((cu.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); + ((cu.slice->getSPS()->getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); + +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { + storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_6PARAM, gbiIdx ); + } +#endif // reset to 4 parameter affine inter mode if ( uiAffineCost <= uiAffine6Cost ) @@ -2142,10 +2612,10 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.mvdAffi[REF_PIC_LIST_1][verIdx] = bestMvd[1][verIdx]; } - PU::setAllAffineMv( pu, bestMv[0][0], bestMv[0][1], bestMv[0][2], REF_PIC_LIST_0 + PU::setAllAffineMv( pu, bestMv[0][0], bestMv[0][1], bestMv[0][2], REF_PIC_LIST_0 , false ); - PU::setAllAffineMv( pu, bestMv[1][0], bestMv[1][1], bestMv[1][2], REF_PIC_LIST_1 + PU::setAllAffineMv( pu, bestMv[1][0], bestMv[1][1], bestMv[1][2], REF_PIC_LIST_1 , false ); } @@ -2204,6 +2674,12 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) // MC PelUnitBuf predBuf = pu.cs->getPredBuf(pu); +#if JVET_M0246_AFFINE_AMVR + if ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine4ParaAvail || !m_affineMotion.affine6ParaAvail ) + { + m_affineMotion.hevcCost[pu.cu->imv] = uiHevcCost; + } +#endif motionCompensation( pu, predBuf, REF_PIC_LIST_X ); puIdx++; } @@ -2213,8 +2689,39 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) return; } +#if JVET_M0246_AFFINE_AMVR +uint32_t InterSearch::xCalcAffineMVBits( PredictionUnit& pu, Mv acMvTemp[3], Mv acMvPred[3], bool mvHighPrec ) +{ + int mvNum = pu.cu->affineType ? 3 : 2; + Mv tempMv0 = acMvTemp[0]; + const int shift = mvHighPrec ? MV_FRACTIONAL_BITS_DIFF : 0; + const unsigned int mvdShift = pu.cu->imv == 2 ? MV_FRACTIONAL_BITS_DIFF : 0; + Mv secondPred; + + if ( mvHighPrec ) + { + tempMv0.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } + + m_pcRdCost->setCostScale( 0 ); + uint32_t bitsTemp = 0; + + for ( int verIdx = 0; verIdx < mvNum; verIdx++ ) + { + m_pcRdCost->setPredictor( acMvPred[verIdx] ); + + if ( verIdx != 0 ) + { + secondPred = acMvPred[verIdx] + ( tempMv0 - acMvPred[0] ); + m_pcRdCost->setPredictor( secondPred ); + } + bitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[verIdx].getHor() >> shift, acMvTemp[verIdx].getVer() >> shift, mvdShift ); + } + return bitsTemp; +} +#endif // AMVP void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, int iRefIdx, Mv& rcMvPred, AMVPInfo& rAMVPInfo, bool bFilled, Distortion* puiDistBiP ) @@ -2372,7 +2879,7 @@ Distortion InterSearch::xGetTemplateCost( const PredictionUnit& pu, Distortion uiCost = std::numeric_limits<Distortion>::max(); const Picture* picRef = pu.cu->slice->getRefPic( eRefPicList, iRefIdx ); - cMvCand.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + cMvCand.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); clipMv( cMvCand, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); @@ -2410,9 +2917,16 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& const bool bi = pu.cu->slice->testWeightPred() && pu.cu->slice->getSliceType()==P_SLICE; Mv mv[3]; memcpy(mv, acMvCand, sizeof(mv)); - mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mv[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mv[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif xPredAffineBlk(COMPONENT_Y, pu, picRef, mv, predBuf, bi, pu.cu->slice->clpRng(COMPONENT_Y)); if( bi ) { @@ -2422,7 +2936,7 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& // calc distortion uiCost = m_pcRdCost->getDistPart( origBuf.Y(), predBuf.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y - , DF_HAD + , DF_HAD ); uiCost += m_pcRdCost->getCost( m_auiMVPIdxCost[iMVPIdx][iMVPNum] ); DTRACE( g_trace_ctx, D_COMMON, " (%d) affineTemplateCost=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiCost ); @@ -2431,7 +2945,7 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, Mv& rcMvPred, int iRefIdxPred, Mv& rcMv, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, bool bBi) { - if( pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedUniMv(pu, eRefPicList, iRefIdxPred, rcMvPred, rcMv, ruiBits, ruiCost) ) + if( pu.cu->cs->sps->getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedUniMv(pu, eRefPicList, iRefIdxPred, rcMvPred, rcMv, ruiBits, ruiCost) ) { return; } @@ -2477,7 +2991,7 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref cStruct.inCtuSearch = false; cStruct.zeroMV = false; { - if (pu.cs->sps->getSpsNext().getUseCompositeRef() && pu.cs->slice->getRefPic(eRefPicList, iRefIdxPred)->longTerm) + if (pu.cs->sps->getUseCompositeRef() && pu.cs->slice->getRefPic(eRefPicList, iRefIdxPred)->longTerm) { cStruct.inCtuSearch = true; } @@ -2506,7 +3020,11 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref { setWpScalingDistParam(iRefIdxPred, eRefPicList, pu.cu->slice); } - +#if JVET_M0253_HASH_ME + m_currRefPicList = eRefPicList; + m_currRefPicIndex = iRefIdxPred; + m_skipFracME = false; +#endif // Do integer search if( ( m_motionEstimationSearchMethod == MESEARCH_FULL ) || bBi || bQTBTMV ) { @@ -2575,7 +3093,7 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu, { const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; Mv cFPMvPred = cMvPred; - cFPMvPred.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + cFPMvPred.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); clipMv( cFPMvPred, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); @@ -2583,10 +3101,10 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu, Mv mvTL(cFPMvPred.getHor() - (iSrchRng << iMvShift), cFPMvPred.getVer() - (iSrchRng << iMvShift)); Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift)); - clipMv( mvTL, pu.cu->lumaPos(), + xClipMv( mvTL, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); - clipMv( mvBR, pu.cu->lumaPos(), + xClipMv( mvBR, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); @@ -2598,7 +3116,7 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu, sr.right = mvBR.hor; sr.bottom = mvBR.ver; - if (pu.cs->sps->getSpsNext().getUseCompositeRef() && cStruct.inCtuSearch) + if (pu.cs->sps->getUseCompositeRef() && cStruct.inCtuSearch) { Position posRB = pu.Y().bottomRight(); Position posTL = pu.Y().topLeft(); @@ -2731,11 +3249,11 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, const bool bNewZeroNeighbourhoodTest = bExtendedSettings; int iSearchRange = m_iSearchRange; - rcMv.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + rcMv.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); clipMv( rcMv, pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); - rcMv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + rcMv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); rcMv.divideByPowerOf2(2); // init TZSearchStruct @@ -2789,9 +3307,34 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, , cStruct ); } - - // start search - int iDist = 0; +#if JVET_M0253_HASH_ME + if (m_pcEncCfg->getUseHashME()) + { + int width = pu.cu->lumaSize().width; + int height = pu.cu->lumaSize().height; + if ((width == height && width <= 64 && width >= 4) || (width == 8 && height == 4) || (width == 4 && height == 8)) + { + Mv otherMvps[5]; + int numberOfOtherMvps; + numberOfOtherMvps = xHashInterPredME(pu, m_currRefPicList, m_currRefPicIndex, otherMvps); + for (int i = 0; i < numberOfOtherMvps; i++) + { + xTZSearchHelp(cStruct, otherMvps[i].getHor(), otherMvps[i].getVer(), 0, 0); + } + if (numberOfOtherMvps > 0) + { + // write out best match + rcMv.set(cStruct.iBestX, cStruct.iBestY); + ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCostOfVectorWithPredictor(cStruct.iBestX, cStruct.iBestY, cStruct.imvShift); + m_skipFracME = true; + return; + } + } + } +#endif + + // start search + int iDist = 0; int iStartX = cStruct.iBestX; int iStartY = cStruct.iBestY; @@ -3046,6 +3589,33 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu, ); } +#if JVET_M0253_HASH_ME + if (m_pcEncCfg->getUseHashME()) + { + int width = pu.cu->lumaSize().width; + int height = pu.cu->lumaSize().height; + if ((width == height && width <= 64 && width >= 4) || (width == 8 && height == 4) || (width == 4 && height == 8)) + { + Mv otherMvps[5]; + int numberOfOtherMvps; + numberOfOtherMvps = xHashInterPredME(pu, m_currRefPicList, m_currRefPicIndex, otherMvps); + for (int i = 0; i < numberOfOtherMvps; i++) + { + xTZSearchHelp(cStruct, otherMvps[i].getHor(), otherMvps[i].getVer(), 0, 0); + } + + if (numberOfOtherMvps > 0) + { + // write out best match + rcMv.set(cStruct.iBestX, cStruct.iBestY); + ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCostOfVectorWithPredictor(cStruct.iBestX, cStruct.iBestY, cStruct.imvShift); + m_skipFracME = true; + return; + } + } + } +#endif + // Initial search int iBestX = cStruct.iBestX; int iBestY = cStruct.iBestY; @@ -3233,9 +3803,21 @@ void InterSearch::xPatternSearchFracDIF( // Reference pattern initialization (integer scale) int iOffset = rcMvInt.getHor() + rcMvInt.getVer() * cStruct.iRefStride; CPelBuf cPatternRoi(cStruct.piRefY + iOffset, cStruct.iRefStride, *cStruct.pcPatternKey); +#if JVET_M0253_HASH_ME + if (m_skipFracME) + { + Mv baseRefMv(0, 0); + rcMvHalf.setZero(); + m_pcRdCost->setCostScale(0); + xExtDIFUpSamplingH(&cPatternRoi); + rcMvQter = rcMvInt; rcMvQter <<= 2; // for mv-cost + ruiCost = xPatternRefinement(cStruct.pcPatternKey, baseRefMv, 1, rcMvQter, !bIsLosslessCoded); + return; + } +#endif - if (cStruct.imvShift || (pu.cs->sps->getSpsNext().getUseCompositeRef() && cStruct.zeroMV)) + if (cStruct.imvShift || (pu.cs->sps->getUseCompositeRef() && cStruct.zeroMV)) { m_pcRdCost->setDistParam( m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY + iOffset, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, 0, 1, m_pcEncCfg->getUseHADME() && !bIsLosslessCoded ); ruiCost = m_cDistParam.distFunc( m_cDistParam ); @@ -3478,6 +4060,10 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uint32_t bitsValidList1 = MAX_UINT; Distortion costValidList1 = std::numeric_limits<Distortion>::max(); Mv mvHevc[3]; +#if JVET_M0246_AFFINE_AMVR + const bool changeToHighPrec = pu.cu->imv != 1; + const bool affineAmvrEnabled = pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag(); +#endif xGetBlkBits( slice.isInterP(), puIdx, lastMode, uiMbBits); @@ -3493,12 +4079,16 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) { RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); - int refPicNumber = slice.getNumRefIdx(eRefPicList); - if (slice.getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0) +#if JVET_M0483_IBC==0 + int refPicNumber = s#lice.getNumRefIdx(eRefPicList); + if (slice.getSPS()->getIBCMode() && eRefPicList == REF_PIC_LIST_0) { refPicNumber--; } for (int iRefIdxTemp = 0; iRefIdxTemp < refPicNumber; iRefIdxTemp++) +#else + for (int iRefIdxTemp = 0; iRefIdxTemp < slice.getNumRefIdx(eRefPicList); iRefIdxTemp++) +#endif { // Get RefIdx bits uiBitsTemp = uiMbBits[iRefList]; @@ -3513,6 +4103,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, // Do Affine AMVP xEstimateAffineAMVP( pu, affiAMVPInfoTemp[eRefPicList], origBuf, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], &biPDistTemp ); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + biPDistTemp += m_pcRdCost->getCost( xCalcAffineMVBits( pu, cMvPred[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList];; if ( pu.cu->affineType == AFFINEMODEL_6PARAM && refIdx4Para[iRefList] != iRefIdxTemp ) @@ -3525,13 +4121,59 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, for ( int i=0; i<3; i++ ) { mvHevc[i] = hevcMv[iRefList][iRefIdxTemp]; +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 1 ) + { + mvHevc[i].changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + else if ( pu.cu->imv == 2 ) + { + mvHevc[i].roundToPrecision( MV_PRECISION_QUARTER, MV_PRECISION_INT ); + } +#endif } PelUnitBuf predBuf = m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) ); Distortion uiCandCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvHevc, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); + +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + uiCandCost += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvHevc, cMvPred[iRefList][iRefIdxTemp] ) ); + } + + //check stored affine motion + bool affine4Para = pu.cu->affineType == AFFINEMODEL_4PARAM; + bool savedParaAvail = pu.cu->imv && ( ( m_affineMotion.affine4ParaRefIdx[iRefList] == iRefIdxTemp && affine4Para && m_affineMotion.affine4ParaAvail ) || + ( m_affineMotion.affine6ParaRefIdx[iRefList] == iRefIdxTemp && !affine4Para && m_affineMotion.affine6ParaAvail ) ); + + if ( savedParaAvail ) + { + Mv mvFour[3]; + for ( int i = 0; i < mvNum; i++ ) + { + mvFour[i] = affine4Para ? m_affineMotion.acMvAffine4Para[iRefList][i] : m_affineMotion.acMvAffine6Para[iRefList][i]; + if ( pu.cu->imv != 1 ) + { + mvFour[i].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[i].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } + } + + Distortion candCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); + candCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); + + if ( candCostInherit < uiCandCost ) + { + uiCandCost = candCostInherit; + memcpy( mvHevc, mvFour, 3 * sizeof( Mv ) ); + } + } +#endif + if (pu.cu->affineType == AFFINEMODEL_4PARAM && m_affMVListSize - && (!pu.cu->cs->sps->getSpsNext().getUseGBi() || gbiIdx == GBI_DEFAULT) + && (!pu.cu->cs->sps->getUseGBi() || gbiIdx == GBI_DEFAULT) ) { int shift = MAX_CU_DEPTH; @@ -3572,21 +4214,49 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, vy = mvScaleVer + dMvHorY * (pu.Y().x - mvInfo->x) + dMvVerY * (pu.Y().y - mvInfo->y); roundAffineMv(vx, vy, shift); mvTmp[0] = Mv(vx, vy); +#if JVET_M0145_AFFINE_MV_CLIP + mvTmp[0].clipToStorageBitDepth(); +#endif clipMv(mvTmp[0], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 2 ) + { + mvTmp[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } + else if ( pu.cu->imv == 0 ) +#endif mvTmp[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); vx = mvScaleHor + dMvHorX * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerX * (pu.Y().y - mvInfo->y); vy = mvScaleVer + dMvHorY * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerY * (pu.Y().y - mvInfo->y); roundAffineMv(vx, vy, shift); mvTmp[1] = Mv(vx, vy); +#if JVET_M0145_AFFINE_MV_CLIP + mvTmp[1].clipToStorageBitDepth(); +#endif clipMv(mvTmp[1], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvTmp[1].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvTmp[0].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + mvTmp[1].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } +#else mvTmp[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); mvTmp[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); mvTmp[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif Distortion tmpCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvTmp, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + tmpCost += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvTmp, cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif if (tmpCost < uiCandCost) { uiCandCost = tmpCost; @@ -3597,13 +4267,26 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { Mv mvFour[3]; - mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif mvFour[0] = mvAffine4Para[iRefList][iRefIdxTemp][0]; mvFour[1] = mvAffine4Para[iRefList][iRefIdxTemp][1]; - mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif int shift = MAX_CU_DEPTH; int vx2 = (mvFour[0].getHor() << shift) - ((mvFour[1].getVer() - mvFour[0].getVer()) << (shift + g_aucLog2[pu.lheight()] - g_aucLog2[pu.lwidth()])); int vy2 = (mvFour[0].getVer() << shift) + ((mvFour[1].getHor() - mvFour[0].getHor()) << (shift + g_aucLog2[pu.lheight()] - g_aucLog2[pu.lwidth()])); @@ -3611,12 +4294,37 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, vy2 >>= shift; mvFour[2].hor = vx2; mvFour[2].ver = vy2; +#if JVET_M0145_AFFINE_MV_CLIP + mvFour[2].clipToStorageBitDepth(); +#endif +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvFour[0].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[1].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[2].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + } +#else mvFour[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif for (int i = 0; i < 3; i++) { +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvFour[i].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } +#else mvFour[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif } Distortion uiCandCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + uiCandCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif if ( uiCandCostInherit < uiCandCost ) { uiCandCost = uiCandCostInherit; @@ -3656,6 +4364,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiCostTemp = uiCostTempL0[iList1ToList0Idx]; uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[iList1ToList0Idx] ); +#if JVET_M0246_AFFINE_AMVR + uiBitsTemp += xCalcAffineMVBits( pu, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp] ); +#else for (int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++) { m_pcRdCost->setPredictor( cMvPred[iRefList][iRefIdxTemp][iVerIdx] ); @@ -3668,26 +4379,42 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( cMvTemp[1][iRefIdxTemp][iVerIdx].getHor()>>shift, cMvTemp[1][iRefIdxTemp][iVerIdx].getVer()>>shift, 0 ); } +#endif /*calculate the correct cost*/ uiCostTemp += m_pcRdCost->getCost( uiBitsTemp ); DTRACE( g_trace_ctx, D_COMMON, " (%d) uiCostTemp=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiCostTemp ); } else { - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] +#endif + ); } } else { - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] +#endif + ); } - if(pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx == GBI_DEFAULT && pu.cu->slice->isInterB()) + if(pu.cu->cs->sps->getUseGBi() && pu.cu->GBiIdx == GBI_DEFAULT && pu.cu->slice->isInterB()) { m_uniMotions.setReadModeAffine(true, (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType); - m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType); + m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp] +#endif + ); } // Set best AMVP Index xCopyAffineAMVPInfo( affiAMVPInfoTemp[eRefPicList], aacAffineAMVPInfo[iRefList][iRefIdxTemp] ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) +#endif xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); if ( iRefList == 0 ) @@ -3721,7 +4448,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( pu.cu->affineType == AFFINEMODEL_4PARAM ) { ::memcpy( mvAffine4Para, cMvTemp, sizeof( cMvTemp ) ); - if (!pu.cu->cs->sps->getSpsNext().getUseGBi() || gbiIdx == GBI_DEFAULT) +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 && ( !pu.cu->cs->sps->getUseGBi() || gbiIdx == GBI_DEFAULT ) ) +#else + if (!pu.cu->cs->sps->getUseGBi() || gbiIdx == GBI_DEFAULT) +#endif { AffineMVInfo *affMVInfo = m_affMVList + m_affMVListIdx; @@ -3781,8 +4512,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, iRefIdxBi[1] = bestBiPRefIdxL1; // Get list1 prediction block - PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 + PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; @@ -3846,8 +4581,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, // First iterate, get prediction block of opposite direction if( iIter == 0 && !slice.getMvdL1ZeroFlag() ) { - PU::setAllAffineMv( pu, aacMv[1-iRefList][0], aacMv[1-iRefList][1], aacMv[1-iRefList][2], RefPicList(1-iRefList) + PU::setAllAffineMv( pu, aacMv[1-iRefList][0], aacMv[1-iRefList][1], aacMv[1-iRefList][2], RefPicList(1-iRefList) +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[1-iRefList] = iRefIdx[1-iRefList]; @@ -3867,10 +4606,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, iRefStart = 0; iRefEnd = slice.getNumRefIdx(eRefPicList) - 1; - if (slice.getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0) +#if JVET_M0483_IBC==0 + if (slice.getSPS()->getIBCMode() && eRefPicList == REF_PIC_LIST_0) { iRefEnd--; } +#endif for ( int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ ) { if ( pu.cu->affineType == AFFINEMODEL_6PARAM && refIdx4Para[iRefList] != iRefIdxTemp ) @@ -3885,7 +4626,7 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } // update bits uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList]; - uiBitsTemp += ((pu.cu->slice->getSPS()->getSpsNext().getUseGBi() == true) ? gbiIdxBits : 0); + uiBitsTemp += ((pu.cu->slice->getSPS()->getUseGBi() == true) ? gbiIdxBits : 0); if( slice.getNumRefIdx(eRefPicList) > 1 ) { uiBitsTemp += iRefIdxTemp+1; @@ -3897,8 +4638,15 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // call Affine ME - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + aaiMvpIdxBi[iRefList][iRefIdxTemp], aacAffineAMVPInfo[iRefList][iRefIdxTemp], +#endif + true ); xCopyAffineAMVPInfo( aacAffineAMVPInfo[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) +#endif xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); if ( uiCostTemp < uiCostBi ) @@ -3909,14 +4657,18 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiCostBi = uiCostTemp; uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList]; - uiMotBits[iRefList] -= ((pu.cu->slice->getSPS()->getSpsNext().getUseGBi() == true) ? gbiIdxBits : 0); + uiMotBits[iRefList] -= ((pu.cu->slice->getSPS()->getUseGBi() == true) ? gbiIdxBits : 0); uiBits[2] = uiBitsTemp; if ( iNumIter != 1 ) // MC for next iter { // Set motion - PU::setAllAffineMv( pu, cMvBi[iRefList][0], cMvBi[iRefList][1], cMvBi[iRefList][2], eRefPicList + PU::setAllAffineMv( pu, cMvBi[iRefList][0], cMvBi[iRefList][1], cMvBi[iRefList][2], eRefPicList +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[eRefPicList] = iRefIdxBi[eRefPicList]; PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(*pu.cu, pu) ); @@ -3977,11 +4729,19 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, lastMode = 2; affineCost = uiCostBi; - PU::setAllAffineMv( pu, cMvBi[0][0], cMvBi[0][1], cMvBi[0][2], REF_PIC_LIST_0 + PU::setAllAffineMv( pu, cMvBi[0][0], cMvBi[0][1], cMvBi[0][2], REF_PIC_LIST_0 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); - PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 + PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0]; pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; @@ -4009,8 +4769,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, lastMode = 0; affineCost = uiCost[0]; - PU::setAllAffineMv( pu, aacMv[0][0], aacMv[0][1], aacMv[0][2], REF_PIC_LIST_0 + PU::setAllAffineMv( pu, aacMv[0][0], aacMv[0][1], aacMv[0][2], REF_PIC_LIST_0 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0]; @@ -4032,8 +4796,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, lastMode = 1; affineCost = uiCost[1]; - PU::setAllAffineMv( pu, aacMv[1][0], aacMv[1][1], aacMv[1][2], REF_PIC_LIST_1 + PU::setAllAffineMv( pu, aacMv[1][0], aacMv[1][1], aacMv[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1]; @@ -4142,6 +4910,10 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin int iBestMVPIdx = riMVPIdx; // Get origin MV bits +#if JVET_M0246_AFFINE_AMVR + Mv tmpPredMv[3]; + int iOrgMvBits = xCalcAffineMVBits( pu, acMv, acMvPred ); +#else int iOrgMvBits = 0; for ( int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++ ) { @@ -4156,6 +4928,7 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin } iOrgMvBits += m_pcRdCost->getBitsOfVectorWithPredictor( acMv[iVerIdx].getHor()>>shift, acMv[iVerIdx].getVer()>>shift, 0 ); } +#endif iOrgMvBits += m_auiMVPIdxCost[riMVPIdx][AMVP_MAX_NUM_CANDS]; int iBestMvBits = iOrgMvBits; @@ -4165,7 +4938,15 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin { continue; } - +#if JVET_M0246_AFFINE_AMVR + tmpPredMv[0] = affineAMVPInfo.mvCandLT[iMVPIdx]; + tmpPredMv[1] = affineAMVPInfo.mvCandRT[iMVPIdx]; + if ( mvNum == 3 ) + { + tmpPredMv[2] = affineAMVPInfo.mvCandLB[iMVPIdx]; + } + int iMvBits = xCalcAffineMVBits( pu, acMv, tmpPredMv ); +#else int iMvBits = 0; for ( int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++ ) { @@ -4181,6 +4962,7 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin } iMvBits += m_pcRdCost->getBitsOfVectorWithPredictor( acMv[iVerIdx].getHor()>>shift, acMv[iVerIdx].getVer()>>shift, 0 ); } +#endif iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS]; if (iMvBits < iBestMvBits) @@ -4210,13 +4992,25 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int& mvpIdx, + const AffineAMVPInfo& aamvpi, +#endif bool bBi) { - if( pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, ruiBits, ruiCost) ) + if( pu.cu->cs->sps->getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, ruiBits, ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , mvpIdx, aamvpi +#endif + ) ) { return; } +#if JVET_M0247_AFFINE_AMVR_ENCOPT + uint32_t dirBits = ruiBits - m_auiMVPIdxCost[mvpIdx][aamvpi.numCand]; + int bestMvpIdx = mvpIdx; +#endif const int width = pu.Y().width; const int height = pu.Y().height; @@ -4248,10 +5042,16 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // Set start Mv position, use input mv as started search mv Mv acMvTemp[3]; ::memcpy( acMvTemp, acMv, sizeof(Mv)*3 ); - acMvTemp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - acMvTemp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - acMvTemp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + acMvTemp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + acMvTemp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + acMvTemp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif // Set delta mv // malloc buffer int iParaNum = pu.cu->affineType ? 7 : 5; @@ -4286,6 +5086,18 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, pu.cu->lumaSize(), *pu.cs->sps ); } +#if JVET_M0246_AFFINE_AMVR + int mvdPrecision = ( pu.cu->imv == 1 ) ? 2 : 0; + if ( pu.cu->imv == 2 ) + { + acMvTemp[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + acMvTemp[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + acMvTemp[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } + } +#endif xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cs->slice->clpRng( COMPONENT_Y ) ); // get error @@ -4294,7 +5106,25 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uiBitsBest = ruiBits; - DTRACE( g_trace_ctx, D_COMMON, " (%d) xx uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv == 2 && m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + uiBitsBest = dirBits + xDetermineBestMvp( pu, acMvTemp, mvpIdx, aamvpi ); + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; + } + else + { +#endif + DTRACE( g_trace_ctx, D_COMMON, " (%d) xx uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); +#if JVET_M0246_AFFINE_AMVR + uiBitsBest += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + } +#endif +#else for ( int i = 0; i < mvNum; i++ ) { DTRACE( g_trace_ctx, D_COMMON, "#mvPredForBits=(%d,%d) \n", acMvPred[i].getHor(), acMvPred[i].getVer() ); @@ -4313,6 +5143,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, uiBitsBest += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[i].getHor()>>shift, acMvTemp[i].getVer()>>shift, 0 ); DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); } +#endif uiCostBest = (Distortion)( floor( fWeight * (double)uiCostBest ) + (double)m_pcRdCost->getCost( uiBitsBest ) ); DTRACE( g_trace_ctx, D_COMMON, " (%d) uiBitsBest=%d, uiCostBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest, uiCostBest ); @@ -4321,7 +5152,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, const int bufStride = pBuf->Y().stride; const int predBufStride = predBuf.Y().stride; - +#if JVET_M0247_AFFINE_AMVR_ENCOPT + Mv prevIterMv[7][3]; +#endif int iIterTime; if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { @@ -4332,12 +5165,15 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, iIterTime = bBi ? 3 : 5; } - if ( !pu.cu->cs->sps->getSpsNext().getUseAffineType() ) + if ( !pu.cu->cs->sps->getUseAffineType() ) { iIterTime = bBi ? 5 : 7; } for ( int iter=0; iter<iIterTime; iter++ ) // iterate loop { +#if JVET_M0247_AFFINE_AMVR_ENCOPT + memcpy( prevIterMv[iter], acMvTemp, sizeof( Mv ) * 3 ); +#endif /********************************************************************************* * use gradient to update mv *********************************************************************************/ @@ -4406,7 +5242,18 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, dDeltaMv[1] = dAffinePara[1] * width + dAffinePara[0]; dDeltaMv[3] = -dAffinePara[3] * width + dAffinePara[2]; } +#if JVET_M0246_AFFINE_AMVR + int mvShift = MV_FRACTIONAL_BITS_DIFF - mvdPrecision; + int multiShift = 1 << ( MV_FRACTIONAL_BITS_DIFF + mvdPrecision ); + acDeltaMv[0] = Mv( ( int ) ( dDeltaMv[0] * multiShift + SIGN( dDeltaMv[0] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[2] * multiShift + SIGN( dDeltaMv[2] ) * 0.5 ) << mvShift ); + acDeltaMv[1] = Mv( ( int ) ( dDeltaMv[1] * multiShift + SIGN( dDeltaMv[1] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[3] * multiShift + SIGN( dDeltaMv[3] ) * 0.5 ) << mvShift ); + + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + acDeltaMv[2] = Mv( ( int ) ( dDeltaMv[4] * multiShift + SIGN( dDeltaMv[4] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[5] * multiShift + SIGN( dDeltaMv[5] ) * 0.5 ) << mvShift ); + } +#else acDeltaMv[0] = Mv( (int)(dDeltaMv[0] * 4 + SIGN( dDeltaMv[0] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[2] * 4 + SIGN( dDeltaMv[2] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF ); acDeltaMv[1] = Mv( (int)(dDeltaMv[1] * 4 + SIGN( dDeltaMv[1] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[3] * 4 + SIGN( dDeltaMv[3] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF @@ -4417,21 +5264,36 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, acDeltaMv[2] = Mv( (int)(dDeltaMv[4] * 4 + SIGN( dDeltaMv[4] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[5] * 4 + SIGN( dDeltaMv[5] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF ); } - - bool bAllZero = false; - for ( int i = 0; i < mvNum; i++ ) +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( !m_pcEncCfg->getUseAffineAmvrEncOpt() ) { - if ( acDeltaMv[i].getHor() != 0 || acDeltaMv[i].getVer() != 0 ) +#endif + bool bAllZero = false; + for ( int i = 0; i < mvNum; i++ ) { - bAllZero = false; - break; +#if JVET_M0246_AFFINE_AMVR + Mv deltaMv = acDeltaMv[i]; + if ( pu.cu->imv == 2 ) + { + deltaMv.roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_HALF ); + } + if ( deltaMv.getHor() != 0 || deltaMv.getVer() != 0 ) +#else + if ( acDeltaMv[i].getHor() != 0 || acDeltaMv[i].getVer() != 0 ) +#endif + { + bAllZero = false; + break; + } + bAllZero = true; } - bAllZero = true; - } - - if ( bAllZero ) - break; + if ( bAllZero ) + break; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + } +#endif // do motion compensation with updated mv for ( int i = 0; i < mvNum; i++ ) { @@ -4443,11 +5305,45 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, acMvTemp[i].hor = Clip3( -32768, 32767, acMvTemp[i].hor ); acMvTemp[i].ver = Clip3( -32768, 32767, acMvTemp[i].ver ); #endif - acMvTemp[i].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + acMvTemp[i].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + acMvTemp[i].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif clipMv(acMvTemp[i], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); } + +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + bool identical = false; + for ( int k = iter; k >= 0; k-- ) + { + if ( acMvTemp[0] == prevIterMv[k][0] && acMvTemp[1] == prevIterMv[k][1] ) + { + identical = pu.cu->affineType ? acMvTemp[2] == prevIterMv[k][2] : true; + if ( identical ) + { + break; + } + } + } + if ( identical ) + { + break; + } + } +#endif + xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) ); // get error @@ -4457,6 +5353,23 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uint32_t uiBitsTemp = ruiBits; +#if JVET_M0246_AFFINE_AMVR +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv == 2 && m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + uiBitsTemp = dirBits + xDetermineBestMvp( pu, acMvTemp, bestMvpIdx, aamvpi ); + acMvPred[0] = aamvpi.mvCandLT[bestMvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[bestMvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[bestMvpIdx]; + } + else + { + uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + } +#else + uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); +#endif +#else for ( int i = 0; i < mvNum; i++ ) { m_pcRdCost->setPredictor( acMvPred[i] ); @@ -4472,7 +5385,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[i].getHor()>>shift, acMvTemp[i].getVer()>>shift, 0 ); } - +#endif uiCostTemp = (Distortion)( floor( fWeight * (double)uiCostTemp ) + (double)m_pcRdCost->getCost( uiBitsTemp ) ); // store best cost and mv @@ -4481,10 +5394,13 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, uiCostBest = uiCostTemp; uiBitsBest = uiBitsTemp; memcpy( acMv, acMvTemp, sizeof(Mv) * 3 ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + mvpIdx = bestMvpIdx; +#endif } } - auto checkCPMVRdCost = [&](Mv ctrlPtMv[3]) + auto checkCPMVRdCost = [&](Mv ctrlPtMv[3]) { xPredAffineBlk(COMPONENT_Y, pu, refPic, ctrlPtMv, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); // get error @@ -4492,6 +5408,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uint32_t bitsTemp = ruiBits; +#if JVET_M0246_AFFINE_AMVR + bitsTemp += xCalcAffineMVBits( pu, ctrlPtMv, acMvPred, pu.cu->imv != 1 ); +#else for (int i = 0; i < mvNum; i++) { m_pcRdCost->setPredictor(acMvPred[i]); @@ -4507,6 +5426,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } bitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor(ctrlPtMv[i].getHor() >> shift, ctrlPtMv[i].getVer() >> shift, 0); } +#endif costTemp = (Distortion)(floor(fWeight * (double)costTemp) + (double)m_pcRdCost->getCost(bitsTemp)); // store best cost and mv if (costTemp < uiCostBest) @@ -4519,10 +5439,67 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, if (uiCostBest <= AFFINE_ME_LIST_MVP_TH*m_hevcCost) { +#if JVET_M0247_AFFINE_AMVR_ENCOPT + //search 8 nearest neighbors; integer distance + int testPos[8][2] = { { -1, 0 },{ 0, -1 },{ 0, 1 },{ 1, 0 },{ -1, -1 },{ -1, 1 },{ 1, 1 },{ 1, -1 } }; + const uint32_t mvShift = pu.cu->imv == 1 ? 0 : ( pu.cu->imv == 2 ? ( MV_FRACTIONAL_BITS_DIFF << 1 ) : MV_FRACTIONAL_BITS_DIFF ); + const int maxSearchRound = 3; + + if ( m_pcEncCfg->getUseAffineAmvrEncOpt() && m_pcEncCfg->getIntraPeriod() != ( uint32_t ) -1 && pu.cu->imv ) + { + for ( int rnd = 0; rnd < ( pu.cu->slice->getTLayer() <= 2 ? maxSearchRound : maxSearchRound - 1 ); rnd++ ) + { + bool modelChange = false; + //search the model parameters with finear granularity; + for ( int j = 0; j < mvNum; j++ ) + { + for ( int iter = 0; iter < 2; iter++ ) + { + Mv centerMv[3]; + memcpy( centerMv, acMv, sizeof( Mv ) * 3 ); + memcpy( acMvTemp, acMv, sizeof( Mv ) * 3 ); + for ( int i = ( iter ? 0: 4 ); i < ( iter ? 4 : 8 ); i++ ) + { + acMvTemp[j].set( centerMv[j].getHor() + ( testPos[i][0] << mvShift ), centerMv[j].getVer() + ( testPos[i][1] << mvShift ) ); + + clipMv( acMvTemp[j], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); + xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) ); + + Distortion costTemp = m_pcRdCost->getDistPart( predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, DF_HAD ); + uint32_t bitsTemp = ruiBits; + bitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + costTemp = ( Distortion ) ( floor( fWeight * ( double ) costTemp ) + ( double ) m_pcRdCost->getCost( bitsTemp ) ); + + if ( costTemp < uiCostBest ) + { + uiCostBest = costTemp; + uiBitsBest = bitsTemp; + ::memcpy( acMv, acMvTemp, sizeof( Mv ) * 3 ); + modelChange = true; + } + } + } + } + + if ( !modelChange ) + { + break; + } + } + } +#endif + Mv mvPredTmp[3] = { acMvPred[0], acMvPred[1], acMvPred[2] }; - mvPredTmp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvPredTmp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvPredTmp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvPredTmp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvPredTmp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvPredTmp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif Mv mvME[3]; ::memcpy(mvME, acMv, sizeof(Mv) * 3); Mv dMv = mvME[0] - mvPredTmp[0]; @@ -4554,7 +5531,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, checkCPMVRdCost(acMvTemp); } - //keep the translation; + //keep the translation; if (pu.cu->affineType == AFFINEMODEL_6PARAM && mvME[1] != (mvPredTmp[1] + dMv) && mvME[2] != (mvPredTmp[2] + dMv)) { ::memcpy(acMvTemp, mvME, sizeof(Mv) * 3); @@ -4571,20 +5548,38 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, { int testPos[4][2] = { { -1, 0 },{ 0, -1 },{ 0, 1 },{ 1, 0 } }; Mv centerMv[3]; +#if JVET_M0246_AFFINE_AMVR + const uint32_t mvShift = pu.cu->imv == 1 ? 0 : ( pu.cu->imv == 2 ? ( MV_FRACTIONAL_BITS_DIFF << 1 ) : MV_FRACTIONAL_BITS_DIFF ); +#endif ::memcpy(centerMv, acMv, sizeof(Mv) * 3); acMvTemp[0] = centerMv[0]; for (int i = 0; i < 4; i++) { +#if JVET_M0246_AFFINE_AMVR + acMvTemp[1].set( centerMv[1].getHor() + ( testPos[i][0] << mvShift ), centerMv[1].getVer() + ( testPos[i][1] << mvShift ) ); +#else acMvTemp[1].set(centerMv[1].getHor() + (testPos[i][0] << MV_FRACTIONAL_BITS_DIFF), centerMv[1].getVer() + (testPos[i][1] << MV_FRACTIONAL_BITS_DIFF)); +#endif checkCPMVRdCost(acMvTemp); } } } } - - acMv[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - acMv[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - acMv[2].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + acMv[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + acMv[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + acMv[2].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; +#endif // free buffer for (int i = 0; i<iParaNum; i++) @@ -4678,11 +5673,24 @@ void InterSearch::xExtDIFUpSamplingH( CPelBuf* pattern ) const ChromaFormat chFmt = m_currChromaFormat; m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[0][0], intStride, width + 1, height + filterSize, 0 << MV_FRACTIONAL_BITS_DIFF, false, chFmt, clpRng); +#if JVET_M0253_HASH_ME + if (!m_skipFracME) + { +#endif m_if.filterHor(COMPONENT_Y, srcPtr, srcStride, m_filteredBlockTmp[2][0], intStride, width + 1, height + filterSize, 2 << MV_FRACTIONAL_BITS_DIFF, false, chFmt, clpRng); +#if JVET_M0253_HASH_ME + } +#endif intPtr = m_filteredBlockTmp[0][0] + halfFilterSize * intStride + 1; dstPtr = m_filteredBlock[0][0][0]; m_if.filterVer(COMPONENT_Y, intPtr, intStride, dstPtr, dstStride, width + 0, height + 0, 0 << MV_FRACTIONAL_BITS_DIFF, false, true, chFmt, clpRng); +#if JVET_M0253_HASH_ME + if (m_skipFracME) + { + return; + } +#endif intPtr = m_filteredBlockTmp[0][0] + (halfFilterSize - 1) * intStride + 1; dstPtr = m_filteredBlock[2][0][0]; @@ -4928,6 +5936,12 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti { CHECK( !bSubdiv, "Not performing the implicit TU split" ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + CHECK( !bSubdiv, "Not performing the implicit TU split - sbt" ); + } +#endif else { CHECK( bSubdiv, "transformsplit not supported" ); @@ -4942,17 +5956,27 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti if( firstCbfOfCU || TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth - 1 ) ) { const bool chroma_cbf = TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && currDepth == 1 ) ) +#endif m_CABACEstimator->cbf_comp( cs, chroma_cbf, currArea.blocks[COMPONENT_Cb], currDepth ); } if( firstCbfOfCU || TU::getCbfAtDepth( currTU, COMPONENT_Cr, currDepth - 1 ) ) { const bool chroma_cbf = TU::getCbfAtDepth( currTU, COMPONENT_Cr, currDepth ); +#if JVET_M0140_SBT + if( !( cu.sbtInfo && currDepth == 1 ) ) +#endif m_CABACEstimator->cbf_comp( cs, chroma_cbf, currArea.blocks[COMPONENT_Cr], currDepth, TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ) ); } } } +#if JVET_M0140_SBT + if( !bSubdiv && !( cu.sbtInfo && currTU.noResidual ) ) +#else if( !bSubdiv ) +#endif { m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currArea.Y(), currDepth ); } @@ -4983,6 +6007,12 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); + } +#endif else THROW( "Implicit TU split not available!" ); @@ -4996,6 +6026,253 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti } } +#if JVET_M0140_SBT +void InterSearch::calcMinDistSbt( CodingStructure &cs, const CodingUnit& cu, const uint8_t sbtAllowed ) +{ + if( !sbtAllowed ) + { + m_estMinDistSbt[NUMBER_SBT_MODE] = 0; + for( int comp = 0; comp < getNumberValidTBlocks( *cs.pcv ); comp++ ) + { + const ComponentID compID = ComponentID( comp ); + CPelBuf pred = cs.getPredBuf( compID ); + CPelBuf org = cs.getOrgBuf( compID ); + m_estMinDistSbt[NUMBER_SBT_MODE] += m_pcRdCost->getDistPart( org, pred, cs.sps->getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); + } + return; + } + + //SBT fast algorithm 2.1 : estimate a minimum RD cost of a SBT mode based on the luma distortion of uncoded part and coded part (assuming distorted can be reduced to 1/16); + // if this cost is larger than the best cost, no need to try a specific SBT mode + int cuWidth = cu.lwidth(); + int cuHeight = cu.lheight(); + int numPartX = cuWidth >= 16 ? 4 : ( cuWidth == 4 ? 1 : 2 ); + int numPartY = cuHeight >= 16 ? 4 : ( cuHeight == 4 ? 1 : 2 ); + Distortion dist[4][4]; + memset( dist, 0, sizeof( Distortion ) * 16 ); + + for( uint32_t c = 0; c < getNumberValidTBlocks( *cs.pcv ); c++ ) + { + const ComponentID compID = ComponentID( c ); + const CompArea& compArea = cu.blocks[compID]; + const CPelBuf orgPel = cs.getOrgBuf( compArea ); + const CPelBuf predPel = cs.getPredBuf( compArea ); + int lengthX = compArea.width / numPartX; + int lengthY = compArea.height / numPartY; + int strideOrg = orgPel.stride; + int stridePred = predPel.stride; + uint32_t uiShift = DISTORTION_PRECISION_ADJUSTMENT( ( *cs.sps.getBitDepth( toChannelType( compID ) ) - 8 ) << 1 ); + Intermediate_Int iTemp; + + //calc distY of 16 sub parts + for( int j = 0; j < numPartY; j++ ) + { + for( int i = 0; i < numPartX; i++ ) + { + int posX = i * lengthX; + int posY = j * lengthY; + const Pel* ptrOrg = orgPel.bufAt( posX, posY ); + const Pel* ptrPred = predPel.bufAt( posX, posY ); + Distortion uiSum = 0; + for( int n = 0; n < lengthY; n++ ) + { + for( int m = 0; m < lengthX; m++ ) + { + iTemp = ptrOrg[m] - ptrPred[m]; + uiSum += Distortion( ( iTemp * iTemp ) >> uiShift ); + } + ptrOrg += strideOrg; + ptrPred += stridePred; + } + if( isChroma( compID ) ) + { + uiSum = (Distortion)( uiSum * m_pcRdCost->getChromaWeight() ); + } + dist[j][i] += uiSum; + } + } + } + + //SSE of a CU + m_estMinDistSbt[NUMBER_SBT_MODE] = 0; + for( int j = 0; j < numPartY; j++ ) + { + for( int i = 0; i < numPartX; i++ ) + { + m_estMinDistSbt[NUMBER_SBT_MODE] += dist[j][i]; + } + } + //init per-mode dist + for( int i = SBT_VER_H0; i < NUMBER_SBT_MODE; i++ ) + { + m_estMinDistSbt[i] = std::numeric_limits<uint64_t>::max(); + } + + //SBT fast algorithm 1: not try SBT if the residual is too small to compensate bits for encoding residual info + uint64_t minNonZeroResiFracBits = 12 << SCALE_BITS; + if( m_pcRdCost->calcRdCost( 0, m_estMinDistSbt[NUMBER_SBT_MODE] ) < m_pcRdCost->calcRdCost( minNonZeroResiFracBits, 0 ) ) + { + m_skipSbtAll = true; + return; + } + + //derive estimated minDist of SBT = zero-residual part distortion + non-zero residual part distortion / 16 + int shift = 5; + Distortion distResiPart = 0, distNoResiPart = 0; + + if( CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed ) ) + { + int offsetResiPart = 0; + int offsetNoResiPart = numPartX / 2; + distResiPart = distNoResiPart = 0; + assert( numPartX >= 2 ); + for( int j = 0; j < numPartY; j++ ) + { + for( int i = 0; i < numPartX / 2; i++ ) + { + distResiPart += dist[j][i + offsetResiPart]; + distNoResiPart += dist[j][i + offsetNoResiPart]; + } + } + m_estMinDistSbt[SBT_VER_H0] = ( distResiPart >> shift ) + distNoResiPart; + m_estMinDistSbt[SBT_VER_H1] = ( distNoResiPart >> shift ) + distResiPart; + } + + if( CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed ) ) + { + int offsetResiPart = 0; + int offsetNoResiPart = numPartY / 2; + assert( numPartY >= 2 ); + distResiPart = distNoResiPart = 0; + for( int j = 0; j < numPartY / 2; j++ ) + { + for( int i = 0; i < numPartX; i++ ) + { + distResiPart += dist[j + offsetResiPart][i]; + distNoResiPart += dist[j + offsetNoResiPart][i]; + } + } + m_estMinDistSbt[SBT_HOR_H0] = ( distResiPart >> shift ) + distNoResiPart; + m_estMinDistSbt[SBT_HOR_H1] = ( distNoResiPart >> shift ) + distResiPart; + } + + if( CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) ) + { + assert( numPartX == 4 ); + m_estMinDistSbt[SBT_VER_Q0] = m_estMinDistSbt[SBT_VER_Q1] = 0; + for( int j = 0; j < numPartY; j++ ) + { + m_estMinDistSbt[SBT_VER_Q0] += dist[j][0] + ( ( dist[j][1] + dist[j][2] + dist[j][3] ) << shift ); + m_estMinDistSbt[SBT_VER_Q1] += dist[j][3] + ( ( dist[j][0] + dist[j][1] + dist[j][2] ) << shift ); + } + m_estMinDistSbt[SBT_VER_Q0] = m_estMinDistSbt[SBT_VER_Q0] >> shift; + m_estMinDistSbt[SBT_VER_Q1] = m_estMinDistSbt[SBT_VER_Q1] >> shift; + } + + if( CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ) ) + { + assert( numPartY == 4 ); + m_estMinDistSbt[SBT_HOR_Q0] = m_estMinDistSbt[SBT_HOR_Q1] = 0; + for( int i = 0; i < numPartX; i++ ) + { + m_estMinDistSbt[SBT_HOR_Q0] += dist[0][i] + ( ( dist[1][i] + dist[2][i] + dist[3][i] ) << shift ); + m_estMinDistSbt[SBT_HOR_Q1] += dist[3][i] + ( ( dist[0][i] + dist[1][i] + dist[2][i] ) << shift ); + } + m_estMinDistSbt[SBT_HOR_Q0] = m_estMinDistSbt[SBT_HOR_Q0] >> shift; + m_estMinDistSbt[SBT_HOR_Q1] = m_estMinDistSbt[SBT_HOR_Q1] >> shift; + } + + //SBT fast algorithm 5: try N SBT modes with the lowest distortion + Distortion temp[NUMBER_SBT_MODE]; + memcpy( temp, m_estMinDistSbt, sizeof( Distortion ) * NUMBER_SBT_MODE ); + memset( m_sbtRdoOrder, 255, NUMBER_SBT_MODE ); + int startIdx = 0, numRDO; + numRDO = CU::targetSbtAllowed( SBT_VER_HALF, sbtAllowed ) + CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed ); + numRDO = std::min( ( numRDO << 1 ), SBT_NUM_RDO ); + for( int i = startIdx; i < startIdx + numRDO; i++ ) + { + Distortion minDist = std::numeric_limits<uint64_t>::max(); + for( int n = SBT_VER_H0; n <= SBT_HOR_H1; n++ ) + { + if( temp[n] < minDist ) + { + minDist = temp[n]; + m_sbtRdoOrder[i] = n; + } + } + temp[m_sbtRdoOrder[i]] = std::numeric_limits<uint64_t>::max(); + } + + startIdx += numRDO; + numRDO = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ); + numRDO = std::min( ( numRDO << 1 ), SBT_NUM_RDO ); + for( int i = startIdx; i < startIdx + numRDO; i++ ) + { + Distortion minDist = std::numeric_limits<uint64_t>::max(); + for( int n = SBT_VER_Q0; n <= SBT_HOR_Q1; n++ ) + { + if( temp[n] < minDist ) + { + minDist = temp[n]; + m_sbtRdoOrder[i] = n; + } + } + temp[m_sbtRdoOrder[i]] = std::numeric_limits<uint64_t>::max(); + } +} + +uint8_t InterSearch::skipSbtByRDCost( int width, int height, int mtDepth, uint8_t sbtIdx, uint8_t sbtPos, double bestCost, Distortion distSbtOff, double costSbtOff, bool rootCbfSbtOff ) +{ + int sbtMode = CU::getSbtMode( sbtIdx, sbtPos ); + + //SBT fast algorithm 2.2 : estimate a minimum RD cost of a SBT mode based on the luma distortion of uncoded part and coded part (assuming distorted can be reduced to 1/16); + // if this cost is larger than the best cost, no need to try a specific SBT mode + if( m_pcRdCost->calcRdCost( 11 << SCALE_BITS, m_estMinDistSbt[sbtMode] ) > bestCost ) + { + return 0; //early skip type 0 + } + + if( costSbtOff != MAX_DOUBLE ) + { + if( !rootCbfSbtOff ) + { + //SBT fast algorithm 3: skip SBT when the residual is too small (estCost is more accurate than fast algorithm 1, counting PU mode bits) + uint64_t minNonZeroResiFracBits = 10 << SCALE_BITS; + Distortion distResiPart; + if( sbtIdx == SBT_VER_HALF || sbtIdx == SBT_HOR_HALF ) + { + distResiPart = (Distortion)( ( ( m_estMinDistSbt[NUMBER_SBT_MODE] - m_estMinDistSbt[sbtMode] ) * 9 ) >> 4 ); + } + else + { + distResiPart = (Distortion)( ( ( m_estMinDistSbt[NUMBER_SBT_MODE] - m_estMinDistSbt[sbtMode] ) * 3 ) >> 3 ); + } + + double estCost = ( costSbtOff - m_pcRdCost->calcRdCost( 0 << SCALE_BITS, distSbtOff ) ) + m_pcRdCost->calcRdCost( minNonZeroResiFracBits, m_estMinDistSbt[sbtMode] + distResiPart ); + if( estCost > costSbtOff ) + { + return 1; + } + if( estCost > bestCost ) + { + return 2; + } + } + else + { + //SBT fast algorithm 4: skip SBT when an estimated RD cost is larger than the bestCost + double weight = sbtMode > SBT_HOR_H1 ? 0.4 : 0.6; + double estCost = ( ( costSbtOff - m_pcRdCost->calcRdCost( 0 << SCALE_BITS, distSbtOff ) ) * weight ) + m_pcRdCost->calcRdCost( 0 << SCALE_BITS, m_estMinDistSbt[sbtMode] ); + if( estCost > bestCost ) + { + return 3; + } + } + } + return MAX_UCHAR; +} +#endif + void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &partitioner, Distortion *puiZeroDist /*= NULL*/ , const bool luma, const bool chroma ) @@ -5011,6 +6288,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par const unsigned currDepth = partitioner.currTrDepth; bool bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_M0140_SBT + if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + bCheckFull = false; + } +#endif bool bCheckSplit = !bCheckFull; // get temporary data @@ -5041,6 +6324,30 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #else tu.emtIdx = 0; #endif +#if JVET_M0140_SBT + tu.checkTuNoResidual( partitioner.currPartIdx() ); +#endif + +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + const CompArea &areaY = tu.blocks[COMPONENT_Y]; + PelBuf piPredY = cs.getPredBuf(areaY); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPredY); +#if JVET_M0483_IBC + if (!cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (!cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + const Pel avgLuma = tmpPred.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif double minCost [MAX_NUM_TBLOCKS]; #if !JVET_M0464_UNI_MTS @@ -5106,15 +6413,41 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests std::vector<TrMode> trModes; trModes.push_back( TrMode( 0, true ) ); //DCT2 +#if JVET_M0140_SBT + nNumTransformCands = 1; + //for a SBT-no-residual TU, the RDO process should be called once, in order to get the RD cost + if( tsAllowed && !tu.noResidual ) +#else if( tsAllowed ) +#endif { trModes.push_back( TrMode( 1, true ) ); +#if JVET_M0140_SBT + nNumTransformCands++; +#endif } + +#if APPLY_SBT_SL_ON_MTS + //skip MTS if DCT2 is the best + if( mtsAllowed && ( !tu.cu->slice->getSPS()->getUseSBT() || CU::getSbtIdx( m_histBestSbt ) != SBT_OFF_DCT ) ) +#else if( mtsAllowed ) +#endif { for( int i = 2; i < 6; i++ ) { +#if APPLY_SBT_SL_ON_MTS + //skip the non-best Mts mode + if( !tu.cu->slice->getSPS()->getUseSBT() || ( m_histBestMtsIdx == MAX_UCHAR || m_histBestMtsIdx == i ) ) + { +#endif trModes.push_back( TrMode( i, true ) ); +#if JVET_M0140_SBT + nNumTransformCands++; +#endif +#if APPLY_SBT_SL_ON_MTS + } +#endif } } #endif @@ -5122,7 +6455,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #if JVET_M0464_UNI_MTS const int numTransformCandidates = nNumTransformCands; #else - const int numEmtTransformCandidates = isLuma(compID) && tu.cu->emtFlag && sps.getSpsNext().getUseInterEMT() ? 4 : 1; + const int numEmtTransformCandidates = isLuma(compID) && tu.cu->emtFlag && sps.getUseInterEMT() ? 4 : 1; const int numTransformCandidates = checkTransformSkip[compID] ? ( numEmtTransformCandidates + 1 ) : numEmtTransformCandidates; int lastTransformModeIndex = numTransformCandidates - 1; //lastTransformModeIndex is the mode for transformSkip (if transformSkip is active) #endif @@ -5167,7 +6500,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #if RDOQ_CHROMA_LAMBDA m_pcTrQuant->selectLambda(compID); #endif - +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + double cRescale = round((double)(1 << CSCALE_FP_PREC) / (double)(tu.getChromaAdj())); + m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cRescale*cRescale)); + } +#endif TCoeff currAbsSum = 0; uint64_t currCompFracBits = 0; Distortion currCompDist = 0; @@ -5181,7 +6520,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par PelBuf resiBuf = csFull->getResiBuf( compArea ); crossComponentPrediction( tu, compID, lumaResi, resiBuf, resiBuf, false ); } - +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && tu.blocks[compID].width*tu.blocks[compID].height > 4 ) + { + PelBuf resiBuf = csFull->getResiBuf(compArea); + resiBuf.scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(compID)); + } +#endif #if JVET_M0464_UNI_MTS if( nNumTransformCands > 1 ) { @@ -5216,6 +6561,10 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par nonCoeffDist = m_pcRdCost->getDistPart( zeroBuf, orgResi, channelBitDepth, compID, DF_SSE ); // initialized with zero residual distortion } +#if JVET_M0140_SBT + if( !tu.noResidual ) + { +#endif const bool prevCbf = ( compID == COMPONENT_Cr ? tu.cbf[COMPONENT_Cb] : false ); m_CABACEstimator->cbf_comp( *csFull, false, compArea, currDepth, prevCbf ); @@ -5223,6 +6572,9 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { m_CABACEstimator->cross_comp_pred( tu, compID ); } +#if JVET_M0140_SBT + } +#endif nonCoeffFracBits = m_CABACEstimator->getEstFracBits(); #if WCG_EXT @@ -5263,6 +6615,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par CPelBuf orgResiBuf = csFull->getOrgResiBuf(compArea); m_pcTrQuant->invTransformNxN(tu, compID, resiBuf, cQP); +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && tu.blocks[compID].width*tu.blocks[compID].height > 4 ) + { + resiBuf.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); + } +#endif if (bUseCrossCPrediction) { @@ -5270,7 +6628,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); - + #if WCG_EXT currCompCost = m_pcRdCost->calcRdCost(currCompFracBits, currCompDist, false); #else @@ -5342,6 +6700,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par isLastBest = isLastMode; } +#if JVET_M0140_SBT + if( tu.noResidual ) + { + CHECK( currCompFracBits > 0 || currAbsSum, "currCompFracBits > 0 when tu noResidual" ); + } +#endif } } @@ -5355,7 +6719,10 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; m_CABACEstimator->resetBits(); - +#if JVET_M0140_SBT + if( !tu.noResidual ) + { +#endif static const ComponentID cbf_getComp[3] = { COMPONENT_Cb, COMPONENT_Cr, COMPONENT_Y }; for( unsigned c = 0; c < numTBlocks; c++) { @@ -5370,6 +6737,9 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->cbf_comp( *csFull, TU::getCbfAtDepth( tu, compID, currDepth ), tu.blocks[compID], currDepth, prevCbf ); } } +#if JVET_M0140_SBT + } +#endif for (uint32_t ch = 0; ch < numValidComp; ch++) { @@ -5391,6 +6761,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uiSingleDist += uiSingleDistComp[compID]; } } +#if JVET_M0140_SBT + if( tu.noResidual ) + { + CHECK( m_CABACEstimator->getEstFracBits() > 0, "no residual TU's bits shall be 0" ); + } +#endif csFull->fracBits += m_CABACEstimator->getEstFracBits(); csFull->dist += uiSingleDist; @@ -5416,6 +6792,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0140_SBT + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + { + partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); + } +#endif else THROW( "Implicit TU split not available!" ); @@ -5535,9 +6917,22 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa { cu.skip = true; cu.rootCbf = false; +#if JVET_M0140_SBT + CHECK( cu.sbtInfo != 0, "sbtInfo shall be 0 if CU has no residual" ); +#endif cs.getResiBuf().fill(0); { cs.getRecoBuf().copyFrom(cs.getPredBuf() ); +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) && !cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) && !cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + { + cs.getRecoBuf().Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif } @@ -5555,9 +6950,26 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa CPelBuf reco = cs.getRecoBuf (compID); CPelBuf org = cs.getOrgBuf (compID); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper()&& m_pcReshape->getCTUFlag()))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + distortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif distortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); } else @@ -5575,6 +6987,14 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa PredictionUnit &pu = *cs.getPU( partitioner.chType ); m_CABACEstimator->cu_skip_flag ( cu ); +#if JVET_M0483_IBC + if (CU::isIBC(cu)) + { + m_CABACEstimator->merge_idx(pu); + } + else + { +#endif m_CABACEstimator->subblock_merge_flag( cu ); m_CABACEstimator->triangle_mode ( cu ); if (cu.mmvdSkip) @@ -5583,7 +7003,9 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa } else m_CABACEstimator->merge_idx ( pu ); - +#if JVET_M0483_IBC + } +#endif cs.dist = distortion; cs.fracBits = m_CABACEstimator->getEstFracBits(); @@ -5596,6 +7018,25 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa if (luma) { cs.getResiBuf().bufs[0].copyFrom(cs.getOrgBuf().bufs[0]); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(COMPONENT_Y)); + +#if JVET_M0483_IBC + if (!cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (!cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + cs.getResiBuf(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + cs.getResiBuf(COMPONENT_Y).subtract(tmpPred); + } + else +#endif cs.getResiBuf().bufs[0].subtract(cs.getPredBuf().bufs[0]); } if (chroma) @@ -5649,6 +7090,9 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa if (zeroCost < cs.cost || !cu.rootCbf) { +#if JVET_M0140_SBT + cu.sbtInfo = 0; +#endif cu.rootCbf = false; cs.clearTUs(); @@ -5684,7 +7128,38 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa if (luma) { - cs.getRecoBuf().bufs[0].reconstruct(cs.getPredBuf().bufs[0], cs.getResiBuf().bufs[0], cs.slice->clpRngs().comp[0]); +#if JVET_M0427_INLOOP_RESHAPER + if (cu.rootCbf && cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(COMPONENT_Y)); + +#if JVET_M0483_IBC + if (!cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (!cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + + cs.getRecoBuf(COMPONENT_Y).reconstruct(tmpPred, cs.getResiBuf(COMPONENT_Y), cs.slice->clpRng(COMPONENT_Y)); + } + else + { +#endif + cs.getRecoBuf().bufs[0].reconstruct(cs.getPredBuf().bufs[0], cs.getResiBuf().bufs[0], cs.slice->clpRngs().comp[0]); +#if JVET_M0427_INLOOP_RESHAPER +#if JVET_M0483_IBC + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !CU::isIBC(cu)) +#else + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !cu.ibc) +#endif + { + cs.getRecoBuf().bufs[0].rspSignal(m_pcReshape->getFwdLUT()); + } + } +#endif } if (chroma) { @@ -5706,10 +7181,27 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa CPelBuf org = cs.getOrgBuf (compID); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() ) ) ) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); - finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()) ) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif + finalDistortion += m_pcRdCost->getDistPart(org, reco, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); } else #endif @@ -5804,12 +7296,25 @@ bool InterSearch::xReadBufferedUniMv(PredictionUnit& pu, RefPicList eRefPicList, return false; } -bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost) +bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx, const AffineAMVPInfo& aamvpi +#endif +) { if (m_uniMotions.isReadModeAffine((uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType)) { - m_uniMotions.copyAffineMvTo(acMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType); + m_uniMotions.copyAffineMvTo(acMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , mvpIdx +#endif + ); m_pcRdCost->setCostScale(0); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; +#endif uint32_t uiMvBits = 0; for (int iVerIdx = 0; iVerIdx<(pu.cu->affineType ? 3 : 2); iVerIdx++) @@ -5838,13 +7343,59 @@ void InterSearch::initWeightIdxBits() } } +void InterSearch::xClipMv( Mv& rcMv, const Position& pos, const struct Size& size, const SPS& sps ) +{ + int mvShift = MV_FRACTIONAL_BITS_INTERNAL; + int offset = 8; + int horMax = ( sps.getPicWidthInLumaSamples() + offset - ( int ) pos.x - 1 ) << mvShift; + int horMin = ( -( int ) sps.getMaxCUWidth() - offset - ( int ) pos.x + 1 ) << mvShift; + + int verMax = ( sps.getPicHeightInLumaSamples() + offset - ( int ) pos.y - 1 ) << mvShift; + int verMin = ( -( int ) sps.getMaxCUHeight() - offset - ( int ) pos.y + 1 ) << mvShift; + + if( sps.getWrapAroundEnabledFlag() ) + { + int horMax = ( sps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() - size.width + offset - ( int ) pos.x - 1 ) << mvShift; + int horMin = ( -( int ) sps.getMaxCUWidth() - offset - ( int ) pos.x + 1 ) << mvShift; + rcMv.setHor( std::min( horMax, std::max( horMin, rcMv.getHor() ) ) ); + rcMv.setVer( std::min( verMax, std::max( verMin, rcMv.getVer() ) ) ); + return; + } + + rcMv.setHor( std::min( horMax, std::max( horMin, rcMv.getHor() ) ) ); + rcMv.setVer( std::min( verMax, std::max( verMin, rcMv.getVer() ) ) ); +} + +#if JVET_M0247_AFFINE_AMVR_ENCOPT +uint32_t InterSearch::xDetermineBestMvp( PredictionUnit& pu, Mv acMvTemp[3], int& mvpIdx, const AffineAMVPInfo& aamvpi ) +{ + bool mvpUpdated = false; + uint32_t minBits = std::numeric_limits<uint32_t>::max(); + for ( int i = 0; i < aamvpi.numCand; i++ ) + { + Mv mvPred[3] = { aamvpi.mvCandLT[i], aamvpi.mvCandRT[i], aamvpi.mvCandLB[i] }; + uint32_t candBits = m_auiMVPIdxCost[i][aamvpi.numCand]; + candBits += xCalcAffineMVBits( pu, acMvTemp, mvPred, pu.cu->imv != 1 ); + + if ( candBits < minBits ) + { + minBits = candBits; + mvpIdx = i; + mvpUpdated = true; + } + } + CHECK( !mvpUpdated, "xDetermineBestMvp() error" ); + return minBits; +} +#endif + #if JVET_M0444_SMVD void InterSearch::symmvdCheckBestMvp( - PredictionUnit& pu, + PredictionUnit& pu, PelUnitBuf& origBuf, Mv curMv, - RefPicList curRefList, - AMVPInfo amvpInfo[2][33], + RefPicList curRefList, + AMVPInfo amvpInfo[2][33], int32_t gbiIdx, Mv cMvPredSym[2], int32_t mvpIdxSym[2], @@ -5855,7 +7406,7 @@ void InterSearch::symmvdCheckBestMvp( RefPicList tarRefList = (RefPicList)(1 - curRefList); int32_t refIdxCur = pu.cu->slice->getSymRefIdx(curRefList); int32_t refIdxTar = pu.cu->slice->getSymRefIdx(tarRefList); - + MvField cCurMvField, cTarMvField; cCurMvField.setMvField(curMv, refIdxCur); AMVPInfo& amvpCur = amvpInfo[curRefList][refIdxCur]; @@ -5917,4 +7468,4 @@ void InterSearch::symmvdCheckBestMvp( } } } -#endif \ No newline at end of file +#endif diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index f9edc9438352622bd17b04cddf91a8c1a235074a..4c5caed57d6d30bb89b7e82e8c2286cdaa1bc187 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -52,8 +52,14 @@ #include "CommonLib/AffineGradientSearch.h" #include "CommonLib/IbcHashMap.h" +#if JVET_M0253_HASH_ME +#include "CommonLib/Hash.h" +#endif #include <unordered_map> #include <vector> +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif //! \ingroup EncoderLib //! \{ @@ -76,6 +82,20 @@ struct AffineMVInfo int x, y, w, h; }; +#if JVET_M0246_AFFINE_AMVR +typedef struct +{ + Mv acMvAffine4Para[2][2]; + Mv acMvAffine6Para[2][3]; + int16_t affine4ParaRefIdx[2]; + int16_t affine6ParaRefIdx[2]; + Distortion hevcCost[3]; + Distortion affineCost[3]; + bool affine4ParaAvail; + bool affine6ParaAvail; +} EncAffineMotion; +#endif + /// encoder search class class InterSearch : public InterPrediction, CrossComponentPrediction, AffineGradientSearch { @@ -103,13 +123,18 @@ private: int m_affMVListSize; int m_affMVListMaxSize; Distortion m_hevcCost; - +#if JVET_M0246_AFFINE_AMVR + EncAffineMotion m_affineMotion; +#endif protected: // interface to option EncCfg* m_pcEncCfg; // interface to classes TrQuant* m_pcTrQuant; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshape; +#endif // ME parameters int m_iSearchRange; @@ -122,6 +147,12 @@ protected: CtxCache* m_CtxCache; DistParam m_cDistParam; +#if JVET_M0253_HASH_ME + RefPicList m_currRefPicList; + int m_currRefPicIndex; + bool m_skipFracME; +#endif + // Misc. Pel *m_pTempPel; @@ -133,6 +164,14 @@ protected: bool m_isInitialized; unsigned int m_numBVs, m_numBV16s; Mv m_acBVs[IBC_NUM_CANDIDATES]; +#if JVET_M0140_SBT + Distortion m_estMinDistSbt[NUMBER_SBT_MODE + 1]; // estimated minimum SSE value of the PU if using a SBT mode + uint8_t m_sbtRdoOrder[NUMBER_SBT_MODE]; // order of SBT mode in RDO + bool m_skipSbtAll; // to skip all SBT modes for the current PU + uint8_t m_histBestSbt; // historical best SBT mode for PU of certain SSE values + uint8_t m_histBestMtsIdx; // historical best MTS idx for PU of certain SSE values +#endif + public: InterSearch(); virtual ~InterSearch(); @@ -148,10 +187,25 @@ public: RdCost* pcRdCost, CABACWriter* CABACEstimator, CtxCache* ctxCache +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* m_pcReshape +#endif ); void destroy (); +#if JVET_M0140_SBT + void calcMinDistSbt ( CodingStructure &cs, const CodingUnit& cu, const uint8_t sbtAllowed ); + uint8_t skipSbtByRDCost ( int width, int height, int mtDepth, uint8_t sbtIdx, uint8_t sbtPos, double bestCost, Distortion distSbtOff, double costSbtOff, bool rootCbfSbtOff ); + bool getSkipSbtAll () { return m_skipSbtAll; } + void setSkipSbtAll ( bool skipAll ) { m_skipSbtAll = skipAll; } + uint8_t getSbtRdoOrder ( uint8_t idx ) { assert( m_sbtRdoOrder[idx] < NUMBER_SBT_MODE ); assert( (uint32_t)( m_estMinDistSbt[m_sbtRdoOrder[idx]] >> 2 ) < ( MAX_UINT >> 1 ) ); return m_sbtRdoOrder[idx]; } + Distortion getEstDistSbt ( uint8_t sbtMode) { return m_estMinDistSbt[sbtMode]; } + void initTuAnalyzer () { m_estMinDistSbt[NUMBER_SBT_MODE] = std::numeric_limits<uint64_t>::max(); m_skipSbtAll = false; } + void setHistBestTrs ( uint8_t sbtInfo, uint8_t mtsIdx ) { m_histBestSbt = sbtInfo; m_histBestMtsIdx = mtsIdx; } + void initSbtRdoOrder ( uint8_t sbtMode ) { m_sbtRdoOrder[0] = sbtMode; m_estMinDistSbt[0] = m_estMinDistSbt[sbtMode]; } +#endif + void setTempBuffers (CodingStructure ****pSlitCS, CodingStructure ****pFullCS, CodingStructure **pSaveCS ); void resetCtuRecord () { m_ctuRecord.clear(); } #if ENABLE_SPLIT_PARALLELISM @@ -190,6 +244,10 @@ public: m_affMVListSize = std::min(m_affMVListSize + 1, m_affMVListMaxSize); } } +#if JVET_M0246_AFFINE_AMVR + void resetSavedAffineMotion(); + void storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int gbiIdx ); +#endif protected: /// sub-function for motion vector refinement used in fractional-pel accuracy @@ -241,9 +299,17 @@ public: bool predIBCSearch ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap); void xIntraPatternSearch ( PredictionUnit& pu, IntTZSearchStruct& cStruct, Mv& rcMv, Distortion& ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred); void xSetIntraSearchRange ( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, const int localSearchRangeX, const int localSearchRangeY, Mv& rcMvSrchRngLT, Mv& rcMvSrchRngRB); + void resetIbcSearch() { m_numBVs = m_numBV16s = 0; } void xIBCEstimation ( PredictionUnit& pu, PelUnitBuf& origBuf, Mv *pcMvPred, Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY); void xIBCSearchMVCandUpdate ( Distortion uiSad, int x, int y, Distortion* uiSadBestCand, Mv* cMVCand); int xIBCSearchMVChromaRefine( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion* uiSadBestCand, Mv* cMVCand); +#if JVET_M0253_HASH_ME + void addToSortList(std::list<BlockHash>& listBlockHash, std::list<int>& listCost, int cost, const BlockHash& blockHash); + bool predInterHashSearch(CodingUnit& cu, Partitioner& partitioner, bool& isPerfectMatch); + bool xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch); + int xHashInterPredME(const PredictionUnit& pu, RefPicList currRefPicList, int currRefPicIndex, Mv bestMv[5]); + void selectMatchesInter(const MapIterator& itBegin, int count, std::list<BlockHash>& vecBlockHash, const BlockHash& currBlockHash); +#endif protected: // ------------------------------------------------------------------------------------------------------------------- @@ -280,7 +346,9 @@ protected: RefPicList eRefPicList, int iRefIdx ); - +#if JVET_M0246_AFFINE_AMVR + uint32_t xCalcAffineMVBits ( PredictionUnit& pu, Mv mvCand[3], Mv mvPred[3], bool mvHighPrec = false ); +#endif void xCopyAMVPInfo ( AMVPInfo* pSrc, AMVPInfo* pDst ); uint32_t xGetMvpIdxBits ( int iIdx, int iNum ); @@ -382,6 +450,10 @@ protected: Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int& mvpIdx, + const AffineAMVPInfo& aamvpi, +#endif bool bBi = false ); @@ -408,9 +480,16 @@ protected: void xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int gbiIdx ); #endif - bool xReadBufferedAffineUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost); + bool xReadBufferedAffineUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx, const AffineAMVPInfo& aamvpi +#endif + ); double xGetMEDistortionWeight ( uint8_t gbiIdx, RefPicList eRefPicList); bool xReadBufferedUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, uint32_t& ruiBits, Distortion& ruiCost); + + void xClipMv ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps ); + public: void resetBufferedUniMotions () { m_uniMotions.reset(); } uint32_t getWeightIdxBits ( uint8_t gbiIdx ) { return m_estWeightIdxBits[gbiIdx]; } @@ -433,7 +512,9 @@ protected: void xExtDIFUpSamplingH ( CPelBuf* pcPattern ); void xExtDIFUpSamplingQ ( CPelBuf* pcPatternKey, Mv halfPelRef ); - +#if JVET_M0247_AFFINE_AMVR_ENCOPT + uint32_t xDetermineBestMvp ( PredictionUnit& pu, Mv acMvTemp[3], int& mvpIdx, const AffineAMVPInfo& aamvpi ); +#endif // ------------------------------------------------------------------------------------------------------------------- // compute symbol bits // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index ac23b0a313c1459a5601ecc27059bbc6c00ab1d0..d4cab58f9f0efe39e92d5b59fcee262e28b6c893 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -60,6 +60,9 @@ IntraSearch::IntraSearch() , m_pcEncCfg (nullptr) , m_pcTrQuant (nullptr) , m_pcRdCost (nullptr) +#if JVET_M0427_INLOOP_RESHAPER + , m_pcReshape (nullptr) +#endif , m_CABACEstimator(nullptr) , m_CtxCache (nullptr) , m_isInitialized (false) @@ -149,6 +152,9 @@ void IntraSearch::destroy() m_pSharedPredTransformSkip[ch] = nullptr; } +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU.destroy(); +#endif m_isInitialized = false; } @@ -168,6 +174,9 @@ void IntraSearch::init( EncCfg* pcEncCfg, const uint32_t maxCUWidth, const uint32_t maxCUHeight, const uint32_t maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* pcReshape +#endif ) { CHECK(m_isInitialized, "Already initialized"); @@ -176,10 +185,16 @@ void IntraSearch::init( EncCfg* pcEncCfg, m_pcRdCost = pcRdCost; m_CABACEstimator = CABACEstimator; m_CtxCache = ctxCache; +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshape = pcReshape; +#endif const ChromaFormat cform = pcEncCfg->getChromaFormatIdc(); IntraPrediction::init( cform, pcEncCfg->getBitDepth( CHANNEL_TYPE_LUMA ) ); +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU.create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); +#endif for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ ) { @@ -261,7 +276,11 @@ void IntraSearch::init( EncCfg* pcEncCfg, // INTRA PREDICTION ////////////////////////////////////////////////////////////////////////// +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar ) +#else void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) +#endif { CodingStructure &cs = *cu.cs; const SPS &sps = *cs.sps; @@ -275,7 +294,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) //===== loop over partitions ===== const TempCtx ctxStart ( m_CtxCache, m_CABACEstimator->getCtx() ); - const TempCtx ctxStartIntraMode ( m_CtxCache, SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], m_CABACEstimator->getCtx() ) ); + const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::IntraLumaMpmFlag, m_CABACEstimator->getCtx())); const TempCtx ctxStartMHIntraMode ( m_CtxCache, SubCtx( Ctx::MHIntraPredMode, m_CABACEstimator->getCtx() ) ); const TempCtx ctxStartMrlIdx ( m_CtxCache, SubCtx( Ctx::MultiRefLineIdx, m_CABACEstimator->getCtx() ) ); @@ -295,7 +314,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // 2: EMT is being checked for current CU. Stored results of DCT2 can be utilized for speedup uint8_t emtUsageFlag = 0; const int maxSizeEMT = EMT_INTRA_MAX_CU_WITH_QTBT; - if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getSpsNext().getUseIntraEMT() ) + if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getUseIntraEMT() ) { emtUsageFlag = cu.emtFlag == 1 ? 2 : 1; } @@ -307,6 +326,63 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) emtUsageFlag = 0; //this forces the recalculation of the candidates list. Why is this necessary? (to be checked) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +#if JVET_M0464_UNI_MTS + const int width = partitioner.currArea().lwidth(); + const int height = partitioner.currArea().lheight(); + int nOptionsForISP = NUM_INTRA_SUBPARTITIONS_MODES; +#else + int nOptionsForISP = cu.emtFlag == 0 ? NUM_INTRA_SUBPARTITIONS_MODES : 1; +#endif + double bestCurrentCost = bestCostSoFar; + + int ispOptions[NUM_INTRA_SUBPARTITIONS_MODES] = { 0 }; + if( nOptionsForISP > 1 ) + { + auto splitsThatCanBeUsedForISP = CU::canUseISPSplit( width, height, cu.cs->sps->getMaxTrSize() ); + if( splitsThatCanBeUsedForISP == CAN_USE_VER_AND_HORL_SPLITS ) + { + const CodingUnit* cuLeft = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), partitioner.chType ) : nullptr; + const CodingUnit* cuAbove = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), partitioner.chType ) : nullptr; + bool ispHorIsFirstTest = CU::firstTestISPHorSplit( width, height, COMPONENT_Y, cuLeft, cuAbove ); + if( ispHorIsFirstTest ) + { + ispOptions[1] = HOR_INTRA_SUBPARTITIONS; + ispOptions[2] = VER_INTRA_SUBPARTITIONS; + } + else + { + ispOptions[1] = VER_INTRA_SUBPARTITIONS; + ispOptions[2] = HOR_INTRA_SUBPARTITIONS; + } + } + else if( splitsThatCanBeUsedForISP == HOR_INTRA_SUBPARTITIONS ) + { + nOptionsForISP = 2; + ispOptions[1] = HOR_INTRA_SUBPARTITIONS; + } + else if( splitsThatCanBeUsedForISP == VER_INTRA_SUBPARTITIONS ) + { + nOptionsForISP = 2; + ispOptions[1] = VER_INTRA_SUBPARTITIONS; + } + else + { + nOptionsForISP = 1; + } + } + if( nOptionsForISP > 1 ) + { + //variables for the full RD list without MRL modes + m_rdModeListWithoutMrl .clear(); + m_rdModeListWithoutMrlHor .clear(); + m_rdModeListWithoutMrlVer .clear(); + //variables with data from regular intra used to skip ISP splits + m_intraModeDiagRatio .clear(); + m_intraModeHorVerRatio .clear(); + m_intraModeTestedNormalIntra.clear(); + } +#endif static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList; @@ -344,8 +420,10 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) { // this should always be true CHECK( !pu.Y().valid(), "PU is not valid" ); +#if ENABLE_JVET_L0283_MRL bool isFirstLineOfCtu = (((pu.block(COMPONENT_Y).y)&((pu.cs->sps)->getMaxCUWidth() - 1)) == 0); int numOfPassesExtendRef = (isFirstLineOfCtu ? 1 : MRL_NUM_REF_LINES); +#endif pu.multiRefIdx = 0; //===== init pattern for luma prediction ===== @@ -363,6 +441,17 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) const bool bUseHadamard = cu.transQuantBypass == 0; +#if JVET_M0427_INLOOP_RESHAPER + if (cu.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpOrg = m_tmpStorageLCU.getBuf(tmpArea); + tmpOrg.copyFrom(piOrg); + tmpOrg.rspSignal(m_pcReshape->getFwdLUT()); + m_pcRdCost->setDistParam(distParam, tmpOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); + } + else +#endif m_pcRdCost->setDistParam(distParam, piOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); distParam.applyWeight = false; @@ -398,7 +487,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiSad += distParam.distFunc(distParam); // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated. - m_CABACEstimator->getCtx() = SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode ); + m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode); m_CABACEstimator->getCtx() = SubCtx( Ctx::MHIntraPredMode, ctxStartMHIntraMode ); m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx ); @@ -452,7 +541,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) Distortion sad = distParam.distFunc(distParam); // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated. - m_CABACEstimator->getCtx() = SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode ); + m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode); m_CABACEstimator->getCtx() = SubCtx( Ctx::MHIntraPredMode, ctxStartMHIntraMode ); m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx ); @@ -472,6 +561,15 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) } } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms) + m_rdModeListWithoutMrl.resize( numModesForFullRD ); + std::copy_n( uiRdModeList.begin(), numModesForFullRD, m_rdModeListWithoutMrl.begin() ); + } +#endif +#if ENABLE_JVET_L0283_MRL pu.multiRefIdx = 1; const int numMPMs = NUM_MOST_PROBABLE_MODES; unsigned multiRefMPM [numMPMs]; @@ -503,7 +601,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) Distortion sad = distParam.distFunc(distParam); // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated. - m_CABACEstimator->getCtx() = SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode ); + m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode); m_CABACEstimator->getCtx() = SubCtx( Ctx::MHIntraPredMode, ctxStartMHIntraMode ); m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx ); @@ -514,6 +612,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) } } } +#endif CandCostList.resize(numModesForFullRD); extendRefList.resize(numModesForFullRD); if( m_pcEncCfg->getFastUDIUseMPMEnabled() ) @@ -542,6 +641,36 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiRdModeList.push_back( mostProbableMode ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + //we add the ISP MPMs to the list without mrl modes + m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl; + m_rdModeListWithoutMrlVer = m_rdModeListWithoutMrl; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM>* listPointer; + for( int k = 1; k < nOptionsForISP; k++ ) + { + cu.ispMode = ispOptions[k]; + listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer ); + const int numCandISP = PU::getIntraMPMs( pu, uiPreds ); + for( int j = 0; j < numCandISP; j++ ) + { + bool mostProbableModeIncluded = false; + int mostProbableMode = uiPreds[j]; + + for( int i = 0; i < listPointer->size(); i++ ) + { + mostProbableModeIncluded |= ( mostProbableMode == listPointer->at( i ) ); + } + if( !mostProbableModeIncluded ) + { + listPointer->push_back( mostProbableMode ); + } + } + } + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + } +#endif } } else @@ -594,6 +723,44 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) // we remove the non-MPMs from the ISP lists + { + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > uiRdModeListCopyHor = m_rdModeListWithoutMrlHor; + m_rdModeListWithoutMrlHor.clear(); + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > uiRdModeListCopyVer = m_rdModeListWithoutMrlVer; + m_rdModeListWithoutMrlVer.clear(); + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > *listPointerCopy, *listPointer; + for( int ispOptionIdx = 1; ispOptionIdx < nOptionsForISP; ispOptionIdx++ ) + { + cu.ispMode = ispOptions[ispOptionIdx]; + //we get the mpm cand list + const int numMPMs = NUM_MOST_PROBABLE_MODES; + unsigned uiPreds[numMPMs]; + + pu.multiRefIdx = 0; + + PU::getIntraMPMs( pu, uiPreds ); + + //we copy only the ISP MPMs + listPointerCopy = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? uiRdModeListCopyHor : uiRdModeListCopyVer ); + listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer ); + for( int k = 0; k < listPointerCopy->size(); k++ ) + { + for( int q = 0; q < numMPMs; q++ ) + { + if( listPointerCopy->at( k ) == uiPreds[q] ) + { + listPointer->push_back( listPointerCopy->at( k ) ); + break; + } + } + } + } + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + } +#endif + CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" ); @@ -609,10 +776,26 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) if( CandHadList.size() < 3 || CandHadList[2] > cs.interHad * PBINTRA_RATIO ) { uiRdModeList.resize( std::min<size_t>( uiRdModeList.size(), 2 ) ); +#if JVET_M0102_INTRA_SUBPARTITIONS + extendRefList.resize( std::min<size_t>( extendRefList.size(), 2 ) ); + if( nOptionsForISP > 1 ) + { + m_rdModeListWithoutMrlHor.resize( std::min<size_t>( m_rdModeListWithoutMrlHor.size(), 2 ) ); + m_rdModeListWithoutMrlVer.resize( std::min<size_t>( m_rdModeListWithoutMrlVer.size(), 2 ) ); + } +#endif } if( CandHadList.size() < 2 || CandHadList[1] > cs.interHad * PBINTRA_RATIO ) { uiRdModeList.resize( std::min<size_t>( uiRdModeList.size(), 1 ) ); +#if JVET_M0102_INTRA_SUBPARTITIONS + extendRefList.resize( std::min<size_t>( extendRefList.size(), 1 ) ); + if( nOptionsForISP > 1 ) + { + m_rdModeListWithoutMrlHor.resize( std::min<size_t>( m_rdModeListWithoutMrlHor.size(), 1 ) ); + m_rdModeListWithoutMrlVer.resize( std::min<size_t>( m_rdModeListWithoutMrlVer.size(), 1 ) ); + } +#endif } if( CandHadList.size() < 1 || CandHadList[0] > cs.interHad * PBINTRA_RATIO ) { @@ -620,7 +803,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) cs.interHad = 0; //===== reset context models ===== - m_CABACEstimator->getCtx() = SubCtx( Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode ); + m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode); m_CABACEstimator->getCtx() = SubCtx( Ctx::MHIntraPredMode, ctxStartMHIntraMode ); m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx ); @@ -642,6 +825,50 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // just to be sure numModesForFullRD = ( int ) uiRdModeList.size(); +#if JVET_M0102_INTRA_SUBPARTITIONS + PartSplit intraSubPartitionsProcOrder = TU_NO_ISP; + int bestNormalIntraModeIndex = -1; + uint8_t bestIspOption = NOT_INTRA_SUBPARTITIONS; + TUIntraSubPartitioner subTuPartitioner( partitioner ); +#if !JVET_M0464_UNI_MTS + if ( !cu.ispMode && !cu.emtFlag ) + { + m_modeCtrl->setEmtFirstPassNoIspCost( MAX_DOUBLE ); + } +#endif + for( uint32_t ispOptionIdx = 0; ispOptionIdx < nOptionsForISP; ispOptionIdx++ ) + { + cu.ispMode = ispOptions[ispOptionIdx]; + int numModesForFullRDispOption = cu.ispMode == NOT_INTRA_SUBPARTITIONS ? numModesForFullRD : cu.ispMode == HOR_INTRA_SUBPARTITIONS ? (int)m_rdModeListWithoutMrlHor.size() : (int)m_rdModeListWithoutMrlVer.size(); + for( uint32_t uiMode = 0; uiMode < numModesForFullRDispOption; uiMode++ ) + { + // set luma prediction mode + uint32_t uiOrgMode = cu.ispMode == NOT_INTRA_SUBPARTITIONS ? uiRdModeList[uiMode] : cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor[uiMode] : m_rdModeListWithoutMrlVer[uiMode]; + + pu.intraDir[0] = uiOrgMode; + + int multiRefIdx = 0; + pu.multiRefIdx = multiRefIdx; + if( cu.ispMode ) + { + intraSubPartitionsProcOrder = CU::getISPType( cu, COMPONENT_Y ); + bool tuIsDividedInRows = CU::divideTuInRows( cu ); + if( m_intraModeDiagRatio.at( bestNormalIntraModeIndex ) > 1.25 ) + { + continue; + } + if( ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) > 1.25 && tuIsDividedInRows ) || ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) < 0.8 && !tuIsDividedInRows ) ) + { + continue; + } + } + else + { + multiRefIdx = extendRefList[uiMode]; + pu.multiRefIdx = multiRefIdx; + CHECK( pu.multiRefIdx && ( pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX ), "ERL" ); + } +#else for (uint32_t uiMode = 0; uiMode < numModesForFullRD; uiMode++) { // set luma prediction mode @@ -651,6 +878,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) int multiRefIdx = extendRefList[uiMode]; pu.multiRefIdx = multiRefIdx; CHECK(pu.multiRefIdx && (pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX), "ERL"); +#endif // set context models @@ -659,10 +887,31 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // determine residual for partition cs.initSubStructure( *csTemp, partitioner.chType, cs.area, true ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + xRecurIntraCodingLumaQT( *csTemp, subTuPartitioner, bestCurrentCost, 0, intraSubPartitionsProcOrder ); + } + else + { + xRecurIntraCodingLumaQT( *csTemp, partitioner, MAX_DOUBLE, -1 ); + } + + if( cu.ispMode && !csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ) + { + csTemp->cost = MAX_DOUBLE; + } +#else xRecurIntraCodingLumaQT( *csTemp, partitioner ); +#endif + #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() && !cu.ispMode) +#else if( emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() ) +#endif { m_modeCostStore[puIndex][uiMode] = csTemp->cost; //cs.cost; } @@ -677,19 +926,49 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiBestPUMode = uiOrgMode; bestExtendRef = multiRefIdx; +#if JVET_M0102_INTRA_SUBPARTITIONS + bestIspOption = cu.ispMode; +#endif #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() && !cu.ispMode) +#else if( ( emtUsageFlag == 1 ) && m_pcEncCfg->getFastIntraEMT() ) +#endif { m_bestModeCostStore[puIndex] = csBest->cost; //cs.cost; } +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( csBest->cost < bestCurrentCost ) + { + bestCurrentCost = csBest->cost; + } + if( !cu.ispMode ) + { + bestNormalIntraModeIndex = uiMode; + } #endif } csTemp->releaseIntermediateData(); } // Mode loop +#if JVET_M0102_INTRA_SUBPARTITIONS +#if !JVET_M0464_UNI_MTS + if (!cu.ispMode && !cu.emtFlag) + { + m_modeCtrl->setEmtFirstPassNoIspCost(csBest->cost); + } +#endif + } + cu.ispMode = bestIspOption; +#endif +#if JVET_M0427_INLOOP_RESHAPER + cs.useSubStructure(*csBest, partitioner.chType, pu.singleChan(CHANNEL_TYPE_LUMA), true, true, keepResi, keepResi); +#else cs.useSubStructure( *csBest, partitioner.chType, pu.singleChan( CHANNEL_TYPE_LUMA ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi ); - +#endif csBest->releaseIntermediateData(); //=== update PU data ==== pu.intraDir[0] = uiBestPUMode; @@ -700,7 +979,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) m_CABACEstimator->getCtx() = ctxStart; } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner, const double maxCostAllowed ) +#else void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) +#endif { const ChromaFormat format = cu.chromaFormat; const uint32_t numberValidComponents = getNumberValidComponents(format); @@ -709,6 +992,13 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) cs.setDecomp( cs.area.Cb(), false ); +#if JVET_M0102_INTRA_SUBPARTITIONS + double bestCostSoFar = maxCostAllowed; + bool lumaUsesISP = !CS::isDualITree( *cu.cs ) && cu.ispMode; + PartSplit ispType = lumaUsesISP ? CU::getISPType( cu, COMPONENT_Y ) : TU_NO_ISP; + CHECK( cu.ispMode && bestCostSoFar < 0, "bestCostSoFar must be positive!" ); +#endif + auto &pu = *cu.firstPU; { @@ -732,6 +1022,14 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) saveCS.area.repositionTo( cs.area ); saveCS.clearTUs(); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !CS::isDualITree( cs ) && cu.ispMode ) + { + saveCS.clearCUs(); + saveCS.clearPUs(); + } +#endif + if( CS::isDualITree( cs ) ) { if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -751,17 +1049,37 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) std::vector<TransformUnit*> orgTUs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP ) + { + CodingUnit& auxCU = saveCS.addCU( cu, partitioner.chType ); + auxCU.ispMode = cu.ispMode; + saveCS.sps = cu.cs->sps; + saveCS.addPU( *cu.firstPU, partitioner.chType ); + } +#endif + // create a store for the TUs for( const auto &ptu : cs.tus ) { // for split TUs in HEVC, add the TUs without Chroma parts for correct setting of Cbfs +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP || pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) ) +#else if( pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) ) +#endif { saveCS.addTU( *ptu, partitioner.chType ); orgTUs.push_back( ptu ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP ) + { + saveCS.clearCUs(); + } +#endif // SATD pre-selecting. int satdModeList[NUM_CHROMA_MODE]; int64_t satdSortedCost[NUM_CHROMA_MODE]; @@ -885,20 +1203,38 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) //----- chroma coding ----- pu.intraDir[1] = chromaIntraMode; +#if JVET_M0102_INTRA_SUBPARTITIONS + xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType ); + if( lumaUsesISP && cs.dist == MAX_UINT ) + { + continue; + } +#else xRecurIntraChromaCodingQT( cs, partitioner ); +#endif if (cs.pps->getUseTransformSkip()) { m_CABACEstimator->getCtx() = ctxStart; } +#if JVET_M0102_INTRA_SUBPARTITIONS + uint64_t fracBits = xGetIntraFracBitsQT( cs, partitioner, false, true, -1, ispType ); +#else uint64_t fracBits = xGetIntraFracBitsQT( cs, partitioner, false, true ); +#endif Distortion uiDist = cs.dist; double dCost = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist ); //----- compare ----- if( dCost < dBestCost ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && dCost < bestCostSoFar ) + { + bestCostSoFar = dCost; + } +#endif for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) { const CompArea &area = pu.blocks[i]; @@ -907,6 +1243,10 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) #if KEEP_PRED_AND_RESI_SIGNALS saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf ( area ) ); saveCS.getResiBuf ( area ).copyFrom( cs.getResiBuf ( area ) ); +#endif +#if JVET_M0427_INLOOP_RESHAPER + saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf (area ) ); + cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf (area ) ); #endif cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) ); @@ -931,6 +1271,11 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) cs.getPredBuf ( area ).copyFrom( saveCS.getPredBuf( area ) ); cs.getResiBuf ( area ).copyFrom( saveCS.getResiBuf( area ) ); #endif +#if JVET_M0427_INLOOP_RESHAPER + cs.getPredBuf ( area ).copyFrom( saveCS.getPredBuf( area ) ); + cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf ( area ) ); +#endif + cs.picture->getRecoBuf( area ).copyFrom( cs. getRecoBuf( area ) ); for( uint32_t j = 0; j < saveCS.tus.size(); j++ ) @@ -946,6 +1291,12 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) //----- restore context models ----- m_CABACEstimator->getCtx() = ctxStart; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && bestCostSoFar >= maxCostAllowed ) + { + cu.ispMode = 0; + } +#endif } void IntraSearch::IPCMSearch(CodingStructure &cs, Partitioner& partitioner) @@ -967,6 +1318,9 @@ void IntraSearch::IPCMSearch(CodingStructure &cs, Partitioner& partitioner) cs.cost = 0; cs.setDecomp(cs.area); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(cs.area).copyFrom(cs.getPredBuf()); +#endif } void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const ComponentID &compID) @@ -1001,18 +1355,30 @@ void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const C // Intra search // ------------------------------------------------------------------------------------------------------------------- +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx ) +#else void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma) +#endif { CodingUnit &cu = *cs.getCU( partitioner.chType ); if (bLuma) { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool isFirst = cu.ispMode ? subTuIdx == 0 : partitioner.currArea().lumaPos() == cs.area.lumaPos(); +#else bool isFirst = partitioner.currArea().lumaPos() == cs.area.lumaPos(); +#endif // CU header if( isFirst ) { - if( !cs.slice->isIntra() +#if JVET_M0483_IBC + if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) +#else + if( !cs.slice->isIntra() +#endif && cu.Y().valid() ) { @@ -1024,6 +1390,9 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, m_CABACEstimator->pred_mode ( cu ); } m_CABACEstimator->extend_ref_line(cu); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->isp_mode ( cu ); +#endif if( CU::isIntra(cu) ) { m_CABACEstimator->pcm_data( cu, partitioner ); @@ -1058,16 +1427,29 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType ) +{ + const UnitArea &currArea = partitioner.currArea(); + int subTuCounter = subTuIdx; + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuCounter ); + CodingUnit &currCU = *currTU.cu; +#else void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma) { const UnitArea &currArea = partitioner.currArea(); TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); #if !JVET_M0464_UNI_MTS CodingUnit &currCU = *currTU.cu; +#endif #endif uint32_t currDepth = partitioner.currTrDepth; const bool subdiv = currTU.depth > currDepth; +#if JVET_M0102_INTRA_SUBPARTITIONS + ComponentID compID = partitioner.chType == CHANNEL_TYPE_LUMA ? COMPONENT_Y : COMPONENT_Cb; + const bool chromaCbfISP = currArea.blocks[COMPONENT_Cb].valid() && currCU.ispMode && !subdiv; +#endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1075,21 +1457,39 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + CHECK( subdiv && !currCU.ispMode && isLuma( compID ), "No TU subdivision is allowed with QTBT" ); + } + + if( bChroma && ( !currCU.ispMode || chromaCbfISP ) ) +#else CHECK( subdiv, "No TU subdivision is allowed with QTBT" ); } if (bChroma) +#endif { const uint32_t numberValidComponents = getNumberValidComponents(currArea.chromaFormat); +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t cbfDepth = ( chromaCbfISP ? currDepth - 1 : currDepth ); +#endif for (uint32_t ch = COMPONENT_Cb; ch < numberValidComponents; ch++) { const ComponentID compID = ComponentID(ch); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) || chromaCbfISP ) +#else if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) ) +#endif { const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ) : false ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], cbfDepth, prevCbf ); +#else m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], currDepth, prevCbf ); +#endif } } @@ -1098,19 +1498,34 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, if (subdiv) { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!currCU.ispMode && isLuma( compID ) && currDepth == 0 && bLuma) m_CABACEstimator->emt_cu_flag( currCU ); +#else if( currDepth == 0 && bLuma ) m_CABACEstimator->emt_cu_flag( currCU ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currCU.ispMode && isLuma( compID ) ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Cannot perform an implicit split!" ); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -1118,20 +1533,65 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, else { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!currCU.ispMode && isLuma( compID ) && currDepth == 0 && bLuma && TU::getCbfAtDepth( currTU, COMPONENT_Y, 0) ) m_CABACEstimator->emt_cu_flag( currCU ); +#else if( currDepth == 0 && bLuma && TU::getCbfAtDepth( currTU, COMPONENT_Y, 0 ) ) m_CABACEstimator->emt_cu_flag( currCU ); +#endif #endif //===== Cbfs ===== if (bLuma) { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool lastCbfIsInferred = false; + if( ispType != TU_NO_ISP ) + { + bool rootCbfSoFar = false; + uint32_t nTus = currCU.ispMode == HOR_INTRA_SUBPARTITIONS ? currCU.lheight() >> g_aucLog2[currTU.lheight()] : currCU.lwidth() >> g_aucLog2[currTU.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = currCU.firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, currDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( currTU, COMPONENT_Y, partitioner.currTrDepth ); + } + } + if( !lastCbfIsInferred ) + { + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currTU.Y(), currTU.depth, previousCbf, currCU.ispMode ); + } +#else m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currTU.Y(), currTU.depth ); +#endif } } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID, const int subTuIdx, const PartSplit ispType ) +#else void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, const ComponentID &compID) +#endif { const UnitArea &currArea = partitioner.currArea(); + +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuIdx ); +#else TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); +#endif uint32_t currDepth = partitioner.currTrDepth; const bool subdiv = currTU.depth > currDepth; @@ -1141,12 +1601,23 @@ void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, con { partitioner.splitCurrArea(TU_MAX_TR_SPLIT, cs); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currTU.cu->ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW("Implicit TU split not available!"); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xEncCoeffQT( cs, partitioner, compID ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -1166,27 +1637,80 @@ void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, con } } +#if JVET_M0102_INTRA_SUBPARTITIONS +uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType ) +#else uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma ) +#endif { m_CABACEstimator->resetBits(); +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncIntraHeader( cs, partitioner, bLuma, bChroma, subTuIdx ); + xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuIdx, ispType ); +#else xEncIntraHeader( cs, partitioner, bLuma, bChroma ); xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma ); +#endif + if( bLuma ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType ); +#else xEncCoeffQT( cs, partitioner, COMPONENT_Y ); +#endif } if( bChroma ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, COMPONENT_Cb, subTuIdx, ispType ); + xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType ); +#else xEncCoeffQT( cs, partitioner, COMPONENT_Cb ); xEncCoeffQT( cs, partitioner, COMPONENT_Cr ); +#endif } uint64_t fracBits = m_CABACEstimator->getEstFracBits(); return fracBits; } +#if JVET_M0102_INTRA_SUBPARTITIONS +uint64_t IntraSearch::xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID ) +{ + m_CABACEstimator->resetBits(); + + if( compID == COMPONENT_Cb ) + { + //intra mode coding + PredictionUnit &pu = *cs.getPU( partitioner.currArea().lumaPos(), partitioner.chType ); + m_CABACEstimator->intra_chroma_pred_mode( pu ); + //xEncIntraHeader(cs, partitioner, false, true); + } + CHECK( partitioner.currTrDepth != 1, "error in the depth!" ); + const UnitArea &currArea = partitioner.currArea(); + + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); + + //cbf coding + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1 ); + //coeffs coding and cross comp coding + if( TU::hasCrossCompPredInfo( currTU, compID ) ) + { + m_CABACEstimator->cross_comp_pred( currTU, compID ); + } + if( TU::getCbf( currTU, compID ) ) + { + m_CABACEstimator->residual_coding( currTU, compID ); + } + + uint64_t fracBits = m_CABACEstimator->getEstFracBits(); + return fracBits; +} +#endif + uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const ComponentID &compID) { m_CABACEstimator->resetBits(); @@ -1235,6 +1759,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const bool bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction; const bool ccUseRecoResi = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool ispSplitIsAllowed = CU::canUseISPSplit( *tu.cu, compID ); +#endif //===== init availability pattern ===== @@ -1274,8 +1801,37 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp DTRACE( g_trace_ctx, D_PRED, "@(%4d,%4d) [%2dx%2d] IMode=%d\n", tu.lx(), tu.ly(), tu.lwidth(), tu.lheight(), uiChFinalMode ); //DTRACE_PEL_BUF( D_PRED, piPred, tu, tu.cu->predMode, COMPONENT_Y ); +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; +#if JVET_M0483_IBC + bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())); +#else + bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()) || (slice.getSliceType() == P_SLICE && slice.getSPS()->getIBCMode())); +#endif + if (flag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && isChroma(compID)) + { + const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size())); + const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area ); + PelBuf piPredY; + piPredY = cs.picture->getPredBuf(areaY); + const Pel avgLuma = piPredY.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif //===== get residual signal ===== piResi.copyFrom( piOrg ); +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID==COMPONENT_Y) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPred); + piResi.rspSignal(m_pcReshape->getFwdLUT()); + piResi.subtract(tmpPred); + } + else +#endif piResi.subtract( piPred ); if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID)) @@ -1303,16 +1859,57 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp m_pcTrQuant->selectLambda(compID); #endif +#if JVET_M0427_INLOOP_RESHAPER + flag =flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); + if (flag && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() ) + { + int cResScaleInv = tu.getChromaAdj(); + double cResScale = round((double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv); + m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale)); + piResi.scaleSignal(cResScaleInv, 1, tu.cu->cs->slice->clpRng(compID)); + } +#endif + +#if JVET_M0102_INTRA_SUBPARTITIONS + double diagRatio = 0, horVerRatio = 0; +#endif + #if JVET_M0464_UNI_MTS if( trModes ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr ); +#else m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() ); +#endif tu.mtsIdx = trModes->at(0).first; } +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN( tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr, &diagRatio, &horVerRatio ); +#else m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr); #else m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx()); #endif +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed && +#if JVET_M0464_UNI_MTS + tu.mtsIdx == 0 +#else + !tu.cu->emtFlag +#endif + ) + { + m_intraModeDiagRatio .push_back(diagRatio); + m_intraModeHorVerRatio .push_back(horVerRatio); + m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode); + } +#endif DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum ); @@ -1329,19 +1926,51 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + if (flag && uiAbsSum > 0 && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() ) + { + piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); + } +#endif if (bUseCrossCPrediction) { CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true); } +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0,0), area.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPred); + piReco.reconstruct(tmpPred, piResi, cs.slice->clpRng(compID)); + } + else +#endif piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID )); //===== update distortion ===== #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getReshaper() + && slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD())))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); - ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())) + { + CompArea tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(piReco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif + ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); } else #endif @@ -1350,11 +1979,20 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType ) +{ + int subTuCounter = subTuIdx; + const UnitArea &currArea = partitioner.currArea(); + const CodingUnit &cu = *cs.getCU( currArea.lumaPos(), partitioner.chType ); + bool earlySkipISP = false; +#else void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner ) { const UnitArea &currArea = partitioner.currArea(); #if !JVET_M0464_UNI_MTS const CodingUnit &cu = *cs.getCU(currArea.lumaPos(), partitioner.chType); +#endif #endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; @@ -1364,6 +2002,13 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); bCheckSplit = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + bCheckSplit = partitioner.canSplit( ispType, cs ); + bCheckFull = !bCheckSplit; + } +#endif uint32_t numSig = 0; #if JVET_M0464_UNI_MTS @@ -1430,6 +2075,9 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par checkTransformSkip &= TU::hasTransformSkipFlag( *tu.cs, tu.Y() ); checkTransformSkip &= !cu.transQuantBypass; checkTransformSkip &= !cu.emtFlag; +#if JVET_M0102_INTRA_SUBPARTITIONS + checkTransformSkip &= !cu.ispMode; +#endif CHECK( !tu.Y().valid(), "Invalid TU" ); @@ -1530,6 +2178,12 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { default0Save1Load2 = 2; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + default0Save1Load2 = 0; + } +#endif #if JVET_M0464_UNI_MTS if( nNumTransformCands > 1 ) { @@ -1579,7 +2233,18 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && m_pcRdCost->calcRdCost( csFull->fracBits, csFull->dist + singleDistTmpLuma ) > bestCostSoFar ) + { + earlySkipISP = true; + } + else + { + singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType ); + } +#else singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false ); +#endif singleCostTmp = m_pcRdCost->calcRdCost( singleTmpFracBits, singleDistTmpLuma ); } @@ -1602,7 +2267,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( bestModeId[COMPONENT_Y] != lastCheckId ) { -#if KEEP_PRED_AND_RESI_SIGNALS +#if KEEP_PRED_AND_RESI_SIGNALS || JVET_M0427_INLOOP_RESHAPER saveCS.getPredBuf( tu.Y() ).copyFrom( csFull->getPredBuf( tu.Y() ) ); #endif saveCS.getRecoBuf( tu.Y() ).copyFrom( csFull->getRecoBuf( tu.Y() ) ); @@ -1622,7 +2287,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( bestModeId[COMPONENT_Y] != lastCheckId ) { -#if KEEP_PRED_AND_RESI_SIGNALS +#if KEEP_PRED_AND_RESI_SIGNALS || JVET_M0427_INLOOP_RESHAPER csFull->getPredBuf( tu.Y() ).copyFrom( saveCS.getPredBuf( tu.Y() ) ); #endif csFull->getRecoBuf( tu.Y() ).copyFrom( saveCS.getRecoBuf( tu.Y() ) ); @@ -1667,13 +2332,62 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, *csSplit ); + } +#endif do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xRecurIntraCodingLumaQT( *csSplit, partitioner, bestCostSoFar, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xRecurIntraCodingLumaQT( *csSplit, partitioner ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !cu.ispMode ) + { + csSplit->setDecomp( partitioner.currArea().Y() ); + } + else if( CU::isISPFirst( cu, partitioner.currArea().Y(), COMPONENT_Y ) ) + { + csSplit->setDecomp( cu.Y() ); + } +#else csSplit->setDecomp( partitioner.currArea().Y() ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + uiSplitCbfLuma |= TU::getCbfAtDepth( *csSplit->getTU( partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1 ), COMPONENT_Y, partitioner.currTrDepth ); + if( cu.ispMode ) + { + //exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance) + if( csSplit->cost > bestCostSoFar ) + { + earlySkipISP = true; + splitIsSelected = false; + break; + } + else + { + //more restrictive exit condition + bool tuIsDividedInRows = CU::divideTuInRows( cu ); + int nSubPartitions = tuIsDividedInRows ? cu.lheight() >> g_aucLog2[cu.firstTU->lheight()] : cu.lwidth() >> g_aucLog2[cu.firstTU->lwidth()]; + double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 1 ? 0.83 : 0.91; + if( subTuCounter < nSubPartitions && csSplit->cost > bestCostSoFar*threshold ) + { + earlySkipISP = true; + splitIsSelected = false; + break; + } + } + } +#else uiSplitCbfLuma |= TU::getCbfAtDepth( *csSplit->getTU( partitioner.currArea().lumaPos(), partitioner.chType ), COMPONENT_Y, partitioner.currTrDepth ); +#endif @@ -1695,7 +2409,11 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; //----- determine rate and r-d cost ----- +#if JVET_M0102_INTRA_SUBPARTITIONS + csSplit->fracBits = xGetIntraFracBitsQT( *csSplit, partitioner, true, false, cu.ispMode ? 0 : -1, ispType ); +#else csSplit->fracBits = xGetIntraFracBitsQT(*csSplit, partitioner, true, false); +#endif //--- update cost --- csSplit->cost = m_pcRdCost->calcRdCost(csSplit->fracBits, csSplit->dist); @@ -1707,25 +2425,50 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { // otherwise this would've happened in useSubStructure cs.picture->getRecoBuf( currArea.Y() ).copyFrom( cs.getRecoBuf( currArea.Y() ) ); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf( currArea.Y() ).copyFrom( cs.getPredBuf( currArea.Y() ) ); +#endif } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && earlySkipISP ) + { + cs.cost = MAX_DOUBLE; + } + else + { + cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); + } +#else cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); +#endif } } +#if JVET_M0102_INTRA_SUBPARTITIONS +ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& partitioner, const double bestCostSoFar, const PartSplit ispType ) +#else ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partitioner& partitioner) +#endif { UnitArea currArea = partitioner.currArea(); - const bool keepResi = cs.sps->getSpsNext().getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS; + const bool keepResi = cs.sps->getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS; if( !currArea.Cb().valid() ) return ChromaCbfs( false ); TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + const TransformUnit &currTULuma = CS::isDualITree( cs ) ? *cs.picture->cs->getTU(currArea.lumaPos(), CHANNEL_TYPE_LUMA, 0 ) : currTU; +#else const TransformUnit &currTULuma = CS::isDualITree( cs ) ? *cs.picture->cs->getTU( currArea.lumaPos(), CHANNEL_TYPE_LUMA ) : currTU; #endif +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + bool lumaUsesISP = !CS::isDualITree( cs ) && currTU.cu->ispMode; +#endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; ChromaCbfs cbfs ( false ); @@ -1767,6 +2510,18 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition saveCS.area.repositionTo( cs.area ); saveCS.initStructData( MAX_INT, false, true ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !CS::isDualITree( cs ) && currTU.cu->ispMode ) + { + saveCS.clearCUs(); + CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType ); + auxCU.ispMode = currTU.cu->ispMode; + saveCS.sps = currTU.cs->sps; + saveCS.clearPUs(); + saveCS.addPU( *currTU.cu->firstPU, partitioner.chType ); + } +#endif + TransformUnit &tmpTU = saveCS.addTU(currArea, partitioner.chType); @@ -1857,6 +2612,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition { singleCostTmp = MAX_DOUBLE; } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb ) + { + uint64_t fracBitsTmp = xGetIntraFracBitsQTSingleChromaComponent( cs, partitioner, ComponentID( c ) ); + singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp ); + if( isOneMode || ( !isOneMode && !isLastMode ) ) + { + m_CABACEstimator->getCtx() = ctxStart; + } + } +#endif else if( !isOneMode ) { uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma( currTU, compID ); @@ -1874,6 +2640,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition #if KEEP_PRED_AND_RESI_SIGNALS saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area)); saveCS.getOrgResiBuf(area).copyFrom(cs.getOrgResiBuf(area)); +#endif +#if JVET_M0427_INLOOP_RESHAPER + saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area)); #endif if( keepResi ) { @@ -1889,11 +2658,25 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && dSingleCost > bestCostSoFar && c == COMPONENT_Cb ) + { + //Luma + Cb cost is already larger than the best cost, so we don't need to test Cr + cs.dist = MAX_UINT; + m_CABACEstimator->getCtx() = ctxStart; + break; + //return cbfs; + } +#endif + if (bestModeId < totalModesToTest) { #if KEEP_PRED_AND_RESI_SIGNALS cs.getPredBuf (area).copyFrom(saveCS.getPredBuf (area)); cs.getOrgResiBuf(area).copyFrom(saveCS.getOrgResiBuf(area)); +#endif +#if JVET_M0427_INLOOP_RESHAPER + cs.getPredBuf (area).copyFrom(saveCS.getPredBuf (area)); #endif if( keepResi ) { @@ -1906,6 +2689,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition m_CABACEstimator->getCtx() = ctxBest; } +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(area).copyFrom(cs.getPredBuf(area)); +#endif cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area)); cbfs.cbf(compID) = TU::getCbf(currTU, compID); @@ -1922,12 +2708,22 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currTU.cu->ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Implicit TU split not available" ); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType ); +#else ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner ); +#endif for( uint32_t ch = COMPONENT_Cb; ch < numValidTBlocks; ch++ ) { @@ -1938,11 +2734,30 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition partitioner.exitCurrSplit(); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && cs.dist == MAX_UINT ) + { + return cbfs; + } +#endif { cbfs.Cb |= SplitCbfs.Cb; cbfs.Cr |= SplitCbfs.Cr; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !lumaUsesISP ) + { + for( auto &ptu : cs.tus ) + { + if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) ) + { + TU::setCbfAtDepth( *ptu, COMPONENT_Cb, currDepth, SplitCbfs.Cb ); + TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr ); + } + } + } +#else for( auto &ptu : cs.tus ) { if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) ) @@ -1951,6 +2766,7 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr ); } } +#endif } } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 3c1ce2b8137592b7a868bf67ed1d2ee70c9b9003..1879d06c794c87a4c8b36d7a9fee1526e61702bb 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -48,6 +48,9 @@ #include "CommonLib/TrQuant.h" #include "CommonLib/Unit.h" #include "CommonLib/RdCost.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif //! \ingroup EncoderLib //! \{ @@ -62,6 +65,9 @@ class EncModeCtrl; class IntraSearch : public IntraPrediction, CrossComponentPrediction { private: +#if JVET_M0102_INTRA_SUBPARTITIONS + EncModeCtrl *m_modeCtrl; +#endif Pel* m_pSharedPredTransformSkip[MAX_NUM_TBLOCKS]; XUCache m_unitCache; @@ -81,7 +87,18 @@ private: uint32_t m_savedRdModeList [4][NUM_LUMA_MODE], m_savedNumRdModes[4]; int m_savedExtendRefList[4][NUM_LUMA_MODE]; #endif - +#if JVET_M0102_INTRA_SUBPARTITIONS + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrl; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlHor; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlVer; + + static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeDiagRatio; + static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeHorVerRatio; + static_vector<int, FAST_UDI_MAX_RDMODE_NUM> m_intraModeTestedNormalIntra; +#endif +#if JVET_M0427_INLOOP_RESHAPER + PelStorage m_tmpStorageLCU; +#endif protected: // interface to option EncCfg* m_pcEncCfg; @@ -89,6 +106,9 @@ protected: // interface to classes TrQuant* m_pcTrQuant; RdCost* m_pcRdCost; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshape; +#endif // RD computation CABACWriter* m_CABACEstimator; @@ -109,6 +129,9 @@ public: const uint32_t maxCUWidth, const uint32_t maxCUHeight, const uint32_t maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* m_pcReshape +#endif ); void destroy (); @@ -117,10 +140,19 @@ public: CodingStructure****getFullCSBuf () { return m_pFullCS; } CodingStructure **getSaveCSBuf () { return m_pSaveCS; } +#if JVET_M0102_INTRA_SUBPARTITIONS + void setModeCtrl ( EncModeCtrl *modeCtrl ) { m_modeCtrl = modeCtrl; } +#endif + public: +#if JVET_M0102_INTRA_SUBPARTITIONS + void estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE ); + void estIntraPredChromaQT ( CodingUnit &cu, Partitioner& pm, const double maxCostAllowed = MAX_DOUBLE ); +#else void estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm ); void estIntraPredChromaQT (CodingUnit &cu, Partitioner& pm); +#endif void IPCMSearch (CodingStructure &cs, Partitioner& partitioner); uint64_t xFracModeBitsIntra (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID); @@ -136,12 +168,23 @@ protected: // Intra search // ------------------------------------------------------------------------------------------------------------------- +#if JVET_M0102_INTRA_SUBPARTITIONS + void xEncIntraHeader ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1 ); + void xEncSubdivCbfQT ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); + uint64_t xGetIntraFracBitsQT ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); + uint64_t xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner& pm, const ComponentID compID ); +#else void xEncIntraHeader (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); void xEncSubdivCbfQT (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); uint64_t xGetIntraFracBitsQT (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); +#endif uint64_t xGetIntraFracBitsQTChroma(TransformUnit& tu, const ComponentID &compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + void xEncCoeffQT ( CodingStructure &cs, Partitioner& pm, const ComponentID compID, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); +#else void xEncCoeffQT (CodingStructure &cs, Partitioner& pm, const ComponentID &compID); +#endif #if JVET_M0464_UNI_MTS @@ -150,9 +193,14 @@ protected: void xIntraCodingTUBlock (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr ); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + ChromaCbfs xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const PartSplit ispType = TU_NO_ISP ); + void xRecurIntraCodingLumaQT ( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); +#else ChromaCbfs xRecurIntraChromaCodingQT (CodingStructure &cs, Partitioner& pm); void xRecurIntraCodingLumaQT ( CodingStructure &cs, Partitioner& pm ); +#endif void encPredIntraDPCM( const ComponentID &compID, PelBuf &pOrg, PelBuf &pDst, const uint32_t &uiDirMode ); diff --git a/source/Lib/EncoderLib/RateCtrl.cpp b/source/Lib/EncoderLib/RateCtrl.cpp index d88faa991ef244fcecad7dc8d5a8a321cfd4dae9..f70203efe2aa2a9d6827c633b7fd2be693003e4c 100644 --- a/source/Lib/EncoderLib/RateCtrl.cpp +++ b/source/Lib/EncoderLib/RateCtrl.cpp @@ -1158,7 +1158,7 @@ double EncRCPic::calAverageLambda() if (m_LCUs[i].m_QP > 0 || m_encRCSeq->getAdaptiveBits() != 1) { m_validPixelsInPic += m_LCUs[i].m_numberOfPixel; - + totalLambdas += log(m_LCUs[i].m_lambda); numTotalLCUs++; } diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 34a8b308db02f6ede5d36002a8614f3214b78a6f..c181e48c19766e116a9aefd18033be5f011183c2 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -524,85 +524,55 @@ void HLSWriter::codeHrdParameters( const HRD *hrd, bool commonInfPresentFlag, ui } } - -void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) +#if JVET_M0427_INLOOP_RESHAPER +void HLSWriter::codeReshaper(const SliceReshapeInfo& pSliceReshaperInfo, const SPS* pcSPS, const bool isIntra) { - // tool enabling flags - WRITE_FLAG( spsNext.getUseLargeCTU() ? 1 : 0, "large_ctu_flag" ); - WRITE_FLAG( spsNext.getUseIMV() ? 1 : 0, "imv_enable_flag" ); - WRITE_FLAG( spsNext.getDisableMotCompress() ? 1 : 0, "disable_motion_compression_flag" ); - WRITE_FLAG( spsNext.getUseLMChroma() ? 1 : 0, "lm_chroma_enabled_flag" ); -#if JVET_M0142_CCLM_COLLOCATED_CHROMA - if ( spsNext.getUseLMChroma() && spsNext.getSPS().getChromaFormatIdc() == CHROMA_420 ) - { - WRITE_FLAG( spsNext.getCclmCollocatedChromaFlag() ? 1 : 0, "sps_cclm_collocated_chroma_flag" ); - } -#endif -#if JVET_M0464_UNI_MTS - WRITE_FLAG( spsNext.getUseIntraMTS() ? 1 : 0, "mts_intra_enabled_flag" ); - WRITE_FLAG( spsNext.getUseInterMTS() ? 1 : 0, "mts_inter_enabled_flag" ); -#else - WRITE_FLAG( spsNext.getUseIntraEMT() ? 1 : 0, "emt_intra_enabled_flag" ); - WRITE_FLAG( spsNext.getUseInterEMT() ? 1 : 0, "emt_inter_enabled_flag" ); -#endif - WRITE_FLAG( spsNext.getUseAffine() ? 1 : 0, "affine_flag" ); - if ( spsNext.getUseAffine() ) + WRITE_FLAG(pSliceReshaperInfo.getSliceReshapeModelPresentFlag() ? 1 : 0, "tile_group_reshaper_model_present_flag"); + if (pSliceReshaperInfo.getSliceReshapeModelPresentFlag()) { - WRITE_FLAG( spsNext.getUseAffineType() ? 1 : 0, "affine_type_flag" ); - } - WRITE_FLAG( spsNext.getUseGBi() ? 1 : 0, "gbi_flag" ); - WRITE_FLAG(spsNext.getIBCMode() ? 1 : 0, "ibc_flag" ); - for( int k = 0; k < SPSNext::NumReservedFlags; k++ ) - { - WRITE_FLAG( 0, "reserved_flag" ); - } - - WRITE_FLAG( spsNext.getMTTEnabled() ? 1 : 0, "mtt_enabled_flag" ); - WRITE_FLAG( spsNext.getUseMHIntra() ? 1 : 0, "mhintra_flag" ); - WRITE_FLAG( spsNext.getUseTriangle() ? 1: 0, "triangle_flag" ); -#if ENABLE_WPP_PARALLELISM - WRITE_FLAG( spsNext.getUseNextDQP(), "next_dqp_enabled_flag" ); -#else - WRITE_FLAG( 0, "reserved_flag" ); -#endif - - // additional parameters + WRITE_UVLC(pSliceReshaperInfo.reshaperModelMinBinIdx, "reshaper_model_min_bin_idx"); + WRITE_UVLC(PIC_CODE_CW_BINS - 1 - pSliceReshaperInfo.reshaperModelMaxBinIdx, "reshaper_model_delta_max_bin_idx"); + assert(pSliceReshaperInfo.maxNbitsNeededDeltaCW > 0); + WRITE_UVLC(pSliceReshaperInfo.maxNbitsNeededDeltaCW - 1, "reshaper_model_bin_delta_abs_cw_prec_minus1"); - if( spsNext.getUseIMV() ) - { - WRITE_UVLC( spsNext.getImvMode()-1, "imv_mode_minus1" ); - } - - if( spsNext.getMTTEnabled() ) - { - WRITE_UVLC( spsNext.getMTTMode() - 1, "mtt_mode_minus1" ); - } -#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET - WRITE_FLAG( spsNext.getLadfEnabled() ? 1 : 0, "sps_ladf_enabled_flag" ); - if ( spsNext.getLadfEnabled() ) - { - WRITE_CODE( spsNext.getLadfNumIntervals() - 2, 2, "sps_num_ladf_intervals_minus2" ); - WRITE_SVLC( spsNext.getLadfQpOffset( 0 ), "sps_ladf_lowest_interval_qp_offset"); - for ( int k = 1; k< spsNext.getLadfNumIntervals(); k++ ) + for (int i = pSliceReshaperInfo.reshaperModelMinBinIdx; i <= pSliceReshaperInfo.reshaperModelMaxBinIdx; i++) { - WRITE_SVLC( spsNext.getLadfQpOffset( k ), "sps_ladf_qp_offset" ); - WRITE_UVLC( spsNext.getLadfIntervalLowerBound( k ) - spsNext.getLadfIntervalLowerBound( k - 1 ) - 1, "sps_ladf_delta_threshold_minus1" ); + int deltaCW = pSliceReshaperInfo.reshaperModelBinCWDelta[i]; + int signCW = (deltaCW < 0) ? 1 : 0; + int absCW = (deltaCW < 0) ? (-deltaCW) : deltaCW; + WRITE_CODE(absCW, pSliceReshaperInfo.maxNbitsNeededDeltaCW, "reshaper_model_bin_delta_abs_CW"); + if (absCW > 0) + { + WRITE_FLAG(signCW, "reshaper_model_bin_delta_sign_CW_flag"); + } } } -#endif - // ADD_NEW_TOOL : (sps extension writer) write tool enabling flags and associated parameters here -} + + WRITE_FLAG(pSliceReshaperInfo.getUseSliceReshaper() ? 1 : 0, "tile_group_reshaper_enable_flag"); + + if (!pSliceReshaperInfo.getUseSliceReshaper()) + return; + + if (!(pcSPS->getUseDualITree() && isIntra)) + WRITE_FLAG(pSliceReshaperInfo.getSliceReshapeChromaAdj(), "tile_group_reshaper_chroma_residual_scale_flag"); +}; +#endif // #if JVET_M0427_INLOOP_RESHAPER void HLSWriter::codeSPS( const SPS* pcSPS ) { +#if ENABLE_TRACING + xTraceSPSHeader (); +#endif +#if HEVC_VPS + WRITE_CODE( pcSPS->getVPSId (), 4, "sps_video_parameter_set_id" ); +#endif + WRITE_UVLC( pcSPS->getSPSId (), "sps_seq_parameter_set_id" ); - const ChromaFormat format = pcSPS->getChromaFormatIdc(); - const bool chromaEnabled = isChromaEnabled(format); WRITE_FLAG(pcSPS->getIntraOnlyConstraintFlag() ? 1 : 0, "intra_only_constraint_flag"); WRITE_CODE(pcSPS->getMaxBitDepthConstraintIdc(), 4, "max_bitdepth_constraint_idc"); WRITE_CODE(pcSPS->getMaxChromaFormatConstraintIdc(), 2, "max_chroma_format_constraint_idc"); - WRITE_FLAG(pcSPS->getFrameConstraintFlag() ? 1 : 0, "frame_constraint_flag"); - WRITE_FLAG(pcSPS->getNoQtbttDualTreeIntraConstraintFlag() ? 1 : 0, "no_qtbtt_dual_tree_intra constraint_flag"); + WRITE_FLAG(pcSPS->getFrameConstraintFlag() ? 1 : 0, "frame_only_constraint_flag"); + WRITE_FLAG(pcSPS->getNoQtbttDualTreeIntraConstraintFlag() ? 1 : 0, "no_qtbtt_dual_tree_intra_constraint_flag"); WRITE_FLAG(pcSPS->getNoCclmConstraintFlag() ? 1 : 0, "no_cclm_constraint_flag"); WRITE_FLAG(pcSPS->getNoSaoConstraintFlag() ? 1 : 0, "no_sao_constraint_flag"); WRITE_FLAG(pcSPS->getNoAlfConstraintFlag() ? 1 : 0, "no_alf_constraint_flag"); @@ -615,17 +585,17 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_FLAG(pcSPS->getNoLadfConstraintFlag() ? 1 : 0, "no_ladf_constraint_flag"); WRITE_FLAG(pcSPS->getNoDepQuantConstraintFlag() ? 1 : 0, "no_dep_quant_constraint_flag"); WRITE_FLAG(pcSPS->getNoSignDataHidingConstraintFlag() ? 1 : 0, "no_sign_data_hiding_constraint_flag"); -#if ENABLE_TRACING - xTraceSPSHeader (); -#endif -#if HEVC_VPS - WRITE_CODE( pcSPS->getVPSId (), 4, "sps_video_parameter_set_id" ); -#endif + + // KJS: Marakech decision: sub-layers added back + CHECK( pcSPS->getMaxTLayers() == 0, "Maximum number of temporal sub-layers is '0'" ); WRITE_CODE( pcSPS->getMaxTLayers() - 1, 3, "sps_max_sub_layers_minus1" ); + WRITE_FLAG( pcSPS->getTemporalIdNestingFlag() ? 1 : 0, "sps_temporal_id_nesting_flag" ); codePTL( pcSPS->getPTL(), true, pcSPS->getMaxTLayers() - 1 ); - WRITE_UVLC( pcSPS->getSPSId (), "sps_seq_parameter_set_id" ); + WRITE_UVLC( int(pcSPS->getChromaFormatIdc ()), "chroma_format_idc" ); + + const ChromaFormat format = pcSPS->getChromaFormatIdc(); if( format == CHROMA_444 ) { WRITE_FLAG( 0, "separate_colour_plane_flag"); @@ -635,6 +605,7 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_UVLC( pcSPS->getPicHeightInLumaSamples(), "pic_height_in_luma_samples" ); Window conf = pcSPS->getConformanceWindow(); + // KJS: not removing yet WRITE_FLAG( conf.getWindowEnabledFlag(), "conformance_window_flag" ); if (conf.getWindowEnabledFlag()) { @@ -645,11 +616,13 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) } WRITE_UVLC( pcSPS->getBitDepth(CHANNEL_TYPE_LUMA) - 8, "bit_depth_luma_minus8" ); - + + const bool chromaEnabled = isChromaEnabled(format); WRITE_UVLC( chromaEnabled ? (pcSPS->getBitDepth(CHANNEL_TYPE_CHROMA) - 8):0, "bit_depth_chroma_minus8" ); WRITE_UVLC( pcSPS->getBitsForPOC()-4, "log2_max_pic_order_cnt_lsb_minus4" ); + // KJS: Marakech decision: sub-layers added back const bool subLayerOrderingInfoPresentFlag = 1; WRITE_FLAG(subLayerOrderingInfoPresentFlag, "sps_sub_layer_ordering_info_present_flag"); for(uint32_t i=0; i <= pcSPS->getMaxTLayers()-1; i++) @@ -663,41 +636,43 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) } } CHECK( pcSPS->getMaxCUWidth() != pcSPS->getMaxCUHeight(), "Rectangular CTUs not supported" ); - WRITE_FLAG(pcSPS->getUseDualITree(), "qtbt_dual_intra_tree"); - WRITE_UVLC(g_aucLog2[pcSPS->getCTUSize()] - MIN_CU_LOG2, "log2_CTU_size_minus2"); + WRITE_FLAG(pcSPS->getUseDualITree(), "qtbtt_dual_tree_intra_flag"); + WRITE_UVLC(g_aucLog2[pcSPS->getCTUSize()] - MIN_CU_LOG2, "log2_ctu_size_minus2"); WRITE_UVLC(pcSPS->getLog2MinCodingBlockSize() - 2, "log2_min_luma_coding_block_size_minus2"); - WRITE_FLAG(pcSPS->getSplitConsOverrideEnabledFlag(), "sps_override_partition_constraints_enable_flag"); - WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(I_SLICE)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_slice"); - WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(B_SLICE)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_slice"); - WRITE_UVLC(pcSPS->getMaxBTDepth(), "sps_max_mtt_hierarchy_depth_inter_slices"); - WRITE_UVLC(pcSPS->getMaxBTDepthI(), "sps_max_mtt_hierarchy_depth_intra_slices"); + WRITE_FLAG(pcSPS->getSplitConsOverrideEnabledFlag(), "partition_constraints_override_enabled_flag"); + WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(I_SLICE)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_tile_group_luma"); + WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(B_SLICE)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_tile_group"); + WRITE_UVLC(pcSPS->getMaxBTDepth(), "sps_max_mtt_hierarchy_depth_inter_tile_group"); + WRITE_UVLC(pcSPS->getMaxBTDepthI(), "sps_max_mtt_hierarchy_depth_intra_tile_group_luma"); if (pcSPS->getMaxBTDepthI() != 0) { - WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSizeI()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE)], "sps_log2_diff_max_bt_min_qt_intra_slice"); - WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSizeI()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE)], "sps_log2_diff_max_tt_min_qt_intra_slice"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSizeI()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE)], "sps_log2_diff_max_bt_min_qt_intra_tile_group_luma"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSizeI()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE)], "sps_log2_diff_max_tt_min_qt_intra_tile_group_luma"); } if (pcSPS->getMaxBTDepth() != 0) { - WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSize()] - g_aucLog2[pcSPS->getMinQTSize(B_SLICE)], "sps_log2_diff_max_bt_min_qt_inter_slice"); - WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSize()] - g_aucLog2[pcSPS->getMinQTSize(B_SLICE)], "sps_log2_diff_max_tt_min_qt_inter_slice"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSize()] - g_aucLog2[pcSPS->getMinQTSize(B_SLICE)], "sps_log2_diff_max_bt_min_qt_inter_tile_group"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSize()] - g_aucLog2[pcSPS->getMinQTSize(B_SLICE)], "sps_log2_diff_max_tt_min_qt_inter_tile_group"); } if (pcSPS->getUseDualITree()) { - WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_slice_chroma"); - WRITE_UVLC(pcSPS->getMaxBTDepthIChroma(), "sps_max_mtt_hierarchy_depth_intra_slices_chroma"); + WRITE_UVLC(g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)] - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_tile_group_chroma"); + WRITE_UVLC(pcSPS->getMaxBTDepthIChroma(), "sps_max_mtt_hierarchy_depth_intra_tile_group_chroma"); if (pcSPS->getMaxBTDepthIChroma() != 0) { - WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSizeIChroma()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)], "sps_log2_diff_max_bt_min_qt_intra_slice_chroma"); - WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSizeIChroma()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)], "sps_log2_diff_max_tt_min_qt_intra_slice_chroma"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxBTSizeIChroma()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)], "sps_log2_diff_max_bt_min_qt_intra_tile_group_chroma"); + WRITE_UVLC(g_aucLog2[pcSPS->getMaxTTSizeIChroma()] - g_aucLog2[pcSPS->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA)], "sps_log2_diff_max_tt_min_qt_intra_tile_group_chroma"); } } + + // KJS: does not exist anymore -> remove? WRITE_UVLC( pcSPS->getQuadtreeTULog2MinSize() - 2, "log2_min_luma_transform_block_size_minus2" ); - WRITE_UVLC( pcSPS->getQuadtreeTULog2MaxSize() - pcSPS->getQuadtreeTULog2MinSize(), "log2_diff_max_min_luma_transform_block_size" ); + WRITE_UVLC( pcSPS->getQuadtreeTULog2MaxSize() - pcSPS->getQuadtreeTULog2MinSize(), "log2_diff_max_min_luma_transform_block_size" ); WRITE_FLAG( pcSPS->getSAOEnabledFlag(), "sps_sao_enabled_flag"); WRITE_FLAG( pcSPS->getALFEnabledFlag(), "sps_alf_enabled_flag" ); - WRITE_FLAG( pcSPS->getPCMEnabledFlag() ? 1 : 0, "pcm_enabled_flag"); + WRITE_FLAG( pcSPS->getPCMEnabledFlag() ? 1 : 0, "sps_pcm_enabled_flag"); if( pcSPS->getPCMEnabledFlag() ) { WRITE_CODE( pcSPS->getPCMBitDepth(CHANNEL_TYPE_LUMA) - 1, 4, "pcm_sample_bit_depth_luma_minus1" ); @@ -720,22 +695,92 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_FLAG( pcSPS->getSBTMVPEnabledFlag() ? 1 : 0, "sps_sbtmvp_enabled_flag"); } + WRITE_FLAG( pcSPS->getAMVREnabledFlag() ? 1 : 0, "sps_amvr_enabled_flag" ); + WRITE_FLAG( pcSPS->getBDOFEnabledFlag() ? 1 : 0, "sps_bdof_enabled_flag" ); -#if HEVC_USE_SCALING_LISTS - WRITE_FLAG( pcSPS->getScalingListFlag() ? 1 : 0, "scaling_list_enabled_flag" ); - if(pcSPS->getScalingListFlag()) +#if JVET_M0246_AFFINE_AMVR + WRITE_FLAG( pcSPS->getAffineAmvrEnabledFlag() ? 1 : 0, "sps_affine_amvr_enabled_flag" ); +#endif + +#if JVET_M0147_DMVR + WRITE_FLAG( pcSPS->getUseDMVR() ? 1 : 0, "sps_dmvr_enable_flag" ); +#endif + + // KJS: sps_cclm_enabled_flag + WRITE_FLAG( pcSPS->getUseLMChroma() ? 1 : 0, "lm_chroma_enabled_flag" ); +#if JVET_M0142_CCLM_COLLOCATED_CHROMA + if ( pcSPS->getUseLMChroma() && pcSPS->getChromaFormatIdc() == CHROMA_420 ) { - WRITE_FLAG( pcSPS->getScalingListPresentFlag() ? 1 : 0, "sps_scaling_list_data_present_flag" ); - if(pcSPS->getScalingListPresentFlag()) + WRITE_FLAG( pcSPS->getCclmCollocatedChromaFlag() ? 1 : 0, "sps_cclm_collocated_chroma_flag" ); + } +#endif + +#if JVET_M0303_IMPLICIT_MTS + WRITE_FLAG( pcSPS->getUseMTS() ? 1 : 0, "mts_enabled_flag" ); + if ( pcSPS->getUseMTS() ) + { +#endif +#if JVET_M0464_UNI_MTS + WRITE_FLAG( pcSPS->getUseIntraMTS() ? 1 : 0, "mts_intra_enabled_flag" ); + WRITE_FLAG( pcSPS->getUseInterMTS() ? 1 : 0, "mts_inter_enabled_flag" ); +#else + WRITE_FLAG( pcSPS->getUseIntraEMT() ? 1 : 0, "emt_intra_enabled_flag" ); + WRITE_FLAG( pcSPS->getUseInterEMT() ? 1 : 0, "emt_inter_enabled_flag" ); +#endif +#if JVET_M0303_IMPLICIT_MTS + } +#endif + // KJS: sps_affine_enabled_flag + WRITE_FLAG( pcSPS->getUseAffine() ? 1 : 0, "affine_flag" ); + if ( pcSPS->getUseAffine() ) + { + WRITE_FLAG( pcSPS->getUseAffineType() ? 1 : 0, "affine_type_flag" ); + } + WRITE_FLAG( pcSPS->getUseGBi() ? 1 : 0, "gbi_flag" ); +#if JVET_M0483_IBC + WRITE_FLAG(pcSPS->getIBCFlag() ? 1 : 0, "ibc_flag"); +#else + WRITE_FLAG(pcSPS->getIBCMode() ? 1 : 0, "ibc_flag" ); +#endif + + // KJS: sps_ciip_enabled_flag + WRITE_FLAG( pcSPS->getUseMHIntra() ? 1 : 0, "mhintra_flag" ); + + WRITE_FLAG( pcSPS->getUseTriangle() ? 1: 0, "triangle_flag" ); + + // KJS: not in draft yet +#if JVET_M0255_FRACMMVD_SWITCH + WRITE_FLAG( pcSPS->getDisFracMmvdEnabledFlag() ? 1 : 0, "sps_fracmmvd_disabled_flag" ); +#endif + // KJS: not in draft yet +#if JVET_M0140_SBT + WRITE_FLAG( pcSPS->getUseSBT() ? 1 : 0, "sbt_enable_flag"); + if( pcSPS->getUseSBT() ) + { + WRITE_FLAG(pcSPS->getMaxSbtSize() == 64 ? 1 : 0, "max_sbt_size_64_flag"); + } +#endif + // KJS: not in draft yet +#if JVET_M0427_INLOOP_RESHAPER + WRITE_FLAG(pcSPS->getUseReshaper() ? 1 : 0, "sps_reshaper_enable_flag"); +#endif + +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + WRITE_FLAG( pcSPS->getLadfEnabled() ? 1 : 0, "sps_ladf_enabled_flag" ); + if ( pcSPS->getLadfEnabled() ) + { + WRITE_CODE( pcSPS->getLadfNumIntervals() - 2, 2, "sps_num_ladf_intervals_minus2" ); + WRITE_SVLC( pcSPS->getLadfQpOffset( 0 ), "sps_ladf_lowest_interval_qp_offset"); + for ( int k = 1; k< pcSPS->getLadfNumIntervals(); k++ ) { - codeScalingList( pcSPS->getScalingList() ); + WRITE_SVLC( pcSPS->getLadfQpOffset( k ), "sps_ladf_qp_offset" ); + WRITE_UVLC( pcSPS->getLadfIntervalLowerBound( k ) - pcSPS->getLadfIntervalLowerBound( k - 1 ) - 1, "sps_ladf_delta_threshold_minus1" ); } } #endif - CHECK( pcSPS->getMaxTLayers() == 0, "Maximum number of T-layers is '0'" ); - + // KJS: reference picture sets to be replaced const RPSList* rpsList = pcSPS->getRPSList(); WRITE_UVLC(rpsList->getNumberOfReferencePictureSets(), "num_short_term_ref_pic_sets" ); @@ -759,19 +804,31 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_FLAG( pcSPS->getUseStrongIntraSmoothing(), "strong_intra_smoothing_enable_flag" ); #endif + + // KJS: remove scaling lists? +#if HEVC_USE_SCALING_LISTS + WRITE_FLAG( pcSPS->getScalingListFlag() ? 1 : 0, "scaling_list_enabled_flag" ); + if(pcSPS->getScalingListFlag()) + { + WRITE_FLAG( pcSPS->getScalingListPresentFlag() ? 1 : 0, "sps_scaling_list_data_present_flag" ); + if(pcSPS->getScalingListPresentFlag()) + { + codeScalingList( pcSPS->getScalingList() ); + } + } +#endif + + // KJS: no VUI defined yet WRITE_FLAG( pcSPS->getVuiParametersPresentFlag(), "vui_parameters_present_flag" ); if (pcSPS->getVuiParametersPresentFlag()) { codeVUI(pcSPS->getVuiParameters(), pcSPS); } - // KTA tools - bool sps_extension_present_flag=false; bool sps_extension_flags[NUM_SPS_EXTENSION_FLAGS]={false}; sps_extension_flags[SPS_EXT__REXT] = pcSPS->getSpsRangeExtension().settingsDifferFromDefaults(); - sps_extension_flags[SPS_EXT__NEXT] = pcSPS->getSpsNext().nextToolsEnabled(); // Other SPS extension flags checked here. @@ -821,11 +878,6 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_FLAG( (spsRangeExtension.getCabacBypassAlignmentEnabledFlag() ? 1 : 0), "cabac_bypass_alignment_enabled_flag" ); break; } - case SPS_EXT__NEXT: - { - codeSPSNext( pcSPS->getSpsNext(), pcSPS->getPCMEnabledFlag() ); - break; - } default: CHECK(sps_extension_flags[i]!=false, "Unknown PPS extension signalled"); // Should never get here with an active SPS extension flag. break; @@ -1265,26 +1317,41 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) } } } +#if JVET_M0483_IBC + if (!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) + { + CHECK(pcSlice->getMaxNumMergeCand() > MRG_MAX_NUM_CANDS, "More merge candidates signalled than supported"); + WRITE_UVLC(MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "six_minus_max_num_merge_cand"); + } +#endif if( !pcSlice->isIntra() ) { +#if JVET_M0483_IBC==0 CHECK( pcSlice->getMaxNumMergeCand() > MRG_MAX_NUM_CANDS, "More merge candidates signalled than supported" ); WRITE_UVLC( MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "six_minus_max_num_merge_cand" ); +#endif - if ( pcSlice->getSPS()->getSBTMVPEnabledFlag() && !pcSlice->getSPS()->getSpsNext().getUseAffine() ) // ATMVP only + if ( pcSlice->getSPS()->getSBTMVPEnabledFlag() && !pcSlice->getSPS()->getUseAffine() ) // ATMVP only { CHECK( pcSlice->getMaxNumAffineMergeCand() != 1, "Sub-block merge can number should be 1" ); } else - if ( !pcSlice->getSPS()->getSBTMVPEnabledFlag() && !pcSlice->getSPS()->getSpsNext().getUseAffine() ) // both off + if ( !pcSlice->getSPS()->getSBTMVPEnabledFlag() && !pcSlice->getSPS()->getUseAffine() ) // both off { CHECK( pcSlice->getMaxNumAffineMergeCand() != 0, "Sub-block merge can number should be 0" ); } else - if ( pcSlice->getSPS()->getSpsNext().getUseAffine() ) + if ( pcSlice->getSPS()->getUseAffine() ) { CHECK( pcSlice->getMaxNumAffineMergeCand() > AFFINE_MRG_MAX_NUM_CANDS, "More affine merge candidates signalled than supported" ); WRITE_UVLC( AFFINE_MRG_MAX_NUM_CANDS - pcSlice->getMaxNumAffineMergeCand(), "five_minus_max_num_affine_merge_cand" ); } +#if JVET_M0255_FRACMMVD_SWITCH + if ( pcSlice->getSPS()->getDisFracMmvdEnabledFlag() ) + { + WRITE_FLAG( pcSlice->getDisFracMMVD(), "tile_group_fracmmvd_disabled_flag" ); + } +#endif } int iCode = pcSlice->getSliceQp() - ( pcSlice->getPPS()->getPicInitQPMinus26() + 26 ); WRITE_SVLC( iCode, "slice_qp_delta" ); @@ -1330,6 +1397,13 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) { WRITE_FLAG(pcSlice->getLFCrossSliceBoundaryFlag()?1:0, "slice_loop_filter_across_slices_enabled_flag"); } + +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + codeReshaper(pcSlice->getReshapeInfo(), pcSlice->getSPS(), pcSlice->isIntra()); + } +#endif #if HEVC_DEPENDENT_SLICES } #endif @@ -1642,7 +1716,7 @@ bool HLSWriter::xFindMatchingLTRP(Slice* pcSlice, uint32_t *ltrpsIndex, int ltrp void HLSWriter::alf( const AlfSliceParam& alfSliceParam ) { - WRITE_FLAG( alfSliceParam.enabledFlag[COMPONENT_Y], "alf_slice_enable_flag" ); + WRITE_FLAG( alfSliceParam.enabledFlag[COMPONENT_Y], "tile_group_alf_enabled_flag" ); if( !alfSliceParam.enabledFlag[COMPONENT_Y] ) { return; @@ -1699,12 +1773,12 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro { if( !isChroma ) { - WRITE_FLAG( alfSliceParam.coeffDeltaFlag, "alf_coefficients_delta_flag" ); - if( !alfSliceParam.coeffDeltaFlag ) + WRITE_FLAG( alfSliceParam.alfLumaCoeffDeltaFlag, "alf_luma_coeff_delta_flag" ); + if( !alfSliceParam.alfLumaCoeffDeltaFlag ) { if( alfSliceParam.numLumaFilters > 1 ) { - WRITE_FLAG( alfSliceParam.coeffDeltaPredModeFlag, "coeff_delta_pred_mode_flag" ); + WRITE_FLAG( alfSliceParam.alfLumaCoeffDeltaPredictionFlag, "alf_luma_coeff_delta_prediction_flag" ); } } } @@ -1719,7 +1793,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro // vlc for all for( int ind = 0; ind < numFilters; ++ind ) { - if( isChroma || !alfSliceParam.coeffDeltaFlag || alfSliceParam.filterCoeffFlag[ind] ) + if( isChroma || !alfSliceParam.alfLumaCoeffDeltaFlag || alfSliceParam.alfLumaCoeffFlag[ind] ) { for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { @@ -1737,23 +1811,23 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro int kMin = EncAdaptiveLoopFilter::getGolombKMin( alfShape, numFilters, kMinTab, bitsCoeffScan ); // Golomb parameters - WRITE_UVLC( kMin - 1, "min_golomb_order" ); + WRITE_UVLC( kMin - 1, isChroma ? "alf_chroma_min_eg_order_minus1" : "alf_luma_min_eg_order_minus1" ); for( int idx = 0; idx < maxGolombIdx; idx++ ) { bool golombOrderIncreaseFlag = ( kMinTab[idx] != kMin ) ? true : false; CHECK( !( kMinTab[idx] <= kMin + 1 ), "ALF Golomb parameter not consistent" ); - WRITE_FLAG( golombOrderIncreaseFlag, "golomb_order_increase_flag" ); + WRITE_FLAG( golombOrderIncreaseFlag, isChroma ? "alf_chroma_eg_order_increase_flag" : "alf_luma_eg_order_increase_flag" ); kMin = kMinTab[idx]; } if( !isChroma ) { - if( alfSliceParam.coeffDeltaFlag ) + if( alfSliceParam.alfLumaCoeffDeltaFlag ) { for( int ind = 0; ind < numFilters; ++ind ) { - WRITE_FLAG( alfSliceParam.filterCoeffFlag[ind], "filter_coefficient_flag[i]" ); + WRITE_FLAG( alfSliceParam.alfLumaCoeffFlag[ind], "alf_luma_coeff_flag[i]" ); } } } @@ -1761,7 +1835,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.filterCoeffFlag[ind] && alfSliceParam.coeffDeltaFlag ) + if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) { continue; } diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h index 2e3dd35f9e845131965bed3f3b9706b7fd350f17..b3866e8ab3a78c22f66574ec4eda016167dc362d 100644 --- a/source/Lib/EncoderLib/VLCWriter.h +++ b/source/Lib/EncoderLib/VLCWriter.h @@ -120,7 +120,6 @@ public: void setBitstream ( OutputBitstream* p ) { m_pcBitIf = p; } uint32_t getNumberOfWrittenBits () { return m_pcBitIf->getNumberOfWrittenBits(); } void codeVUI ( const VUI *pcVUI, const SPS* pcSPS ); - void codeSPSNext ( const SPSNext& spsNext, const bool usePCM ); void codeSPS ( const SPS* pcSPS ); void codePPS ( const PPS* pcPPS ); #if HEVC_VPS @@ -145,6 +144,9 @@ private: void alfGolombEncode( const int coeff, const int k ); void truncatedUnaryEqProb( int symbol, int maxSymbol ); +#if JVET_M0427_INLOOP_RESHAPER + void codeReshaper ( const SliceReshapeInfo& pSliceReshaperInfo, const SPS* pcSPS, const bool isIntra); +#endif }; //! \}