From cb5cfa44c740194006d5c0b4b8ab353efb61e530 Mon Sep 17 00:00:00 2001 From: Brian Heng <brian.heng@broadcom.com> Date: Tue, 10 Dec 2019 15:10:36 +0100 Subject: [PATCH] JVET-P1004: Removal of Bricks - Remove bricks and related syntax. - Add new tile / slice syntax from P1004. - Fix cross tile / slice prediction bugs. - Update config files and documentation with new tile / slice config options. --- cfg/encoder_intra_vtm.cfg | 14 +- cfg/encoder_lowdelay_P_vtm.cfg | 14 +- cfg/encoder_lowdelay_vtm.cfg | 14 +- cfg/encoder_randomaccess_vtm.cfg | 14 +- ...coder_randomaccess_vtm_RasterScanSlice.cfg | 38 +- ...oder_randomaccess_vtm_RectangularSlice.cfg | 39 +- ...omaccess_vtm_RectangularSliceFixedSize.cfg | 163 +++++++ ...er_randomaccess_vtm_SingleTilePerSlice.cfg | 38 +- doc/software-manual.tex | 168 ++----- source/App/EncoderApp/EncApp.cpp | 27 ++ source/App/EncoderApp/EncAppCfg.cpp | 446 ++++++++++++++++++ source/App/EncoderApp/EncAppCfg.h | 22 + source/Lib/CommonLib/AdaptiveLoopFilter.cpp | 64 +++ source/Lib/CommonLib/CommonDef.h | 8 + source/Lib/CommonLib/ContextModelling.cpp | 8 + source/Lib/CommonLib/IntraPrediction.cpp | 33 ++ source/Lib/CommonLib/LoopFilter.cpp | 42 ++ source/Lib/CommonLib/MCTS.cpp | 20 + source/Lib/CommonLib/Picture.cpp | 10 + source/Lib/CommonLib/Picture.h | 4 + source/Lib/CommonLib/Quant.cpp | 4 + source/Lib/CommonLib/SampleAdaptiveOffset.cpp | 4 + source/Lib/CommonLib/Slice.cpp | 354 ++++++++++++++ source/Lib/CommonLib/Slice.h | 201 ++++++++ source/Lib/CommonLib/TypeDef.h | 4 + source/Lib/CommonLib/UnitPartitioner.cpp | 4 + source/Lib/CommonLib/UnitTools.cpp | 14 + source/Lib/CommonLib/UnitTools.h | 2 + source/Lib/DecoderLib/CABACReader.cpp | 140 ++++++ source/Lib/DecoderLib/CABACReader.h | 16 + source/Lib/DecoderLib/DecLib.cpp | 18 + source/Lib/DecoderLib/DecSlice.cpp | 68 +++ source/Lib/DecoderLib/VLCReader.cpp | 197 ++++++++ source/Lib/EncoderLib/CABACWriter.cpp | 12 + .../Lib/EncoderLib/EncAdaptiveLoopFilter.cpp | 4 + source/Lib/EncoderLib/EncCfg.h | 47 ++ source/Lib/EncoderLib/EncCu.cpp | 78 +++ source/Lib/EncoderLib/EncGOP.cpp | 24 + source/Lib/EncoderLib/EncHRD.cpp | 4 + source/Lib/EncoderLib/EncLib.cpp | 57 +++ source/Lib/EncoderLib/EncLib.h | 2 + .../EncoderLib/EncSampleAdaptiveOffset.cpp | 8 + source/Lib/EncoderLib/EncSlice.cpp | 230 +++++++++ source/Lib/EncoderLib/EncSlice.h | 8 + source/Lib/EncoderLib/InterSearch.cpp | 17 + source/Lib/EncoderLib/SEIEncoder.cpp | 4 + source/Lib/EncoderLib/VLCWriter.cpp | 102 ++++ 47 files changed, 2541 insertions(+), 268 deletions(-) create mode 100644 cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSliceFixedSize.cfg diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index c6759769a..f413f709f 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -48,18 +48,8 @@ TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1 TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) -#============ Slices ================ -SliceMode : 0 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 1500 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across +#============ Tiles / Slices ================ +EnablePicPartitioning : 0 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 0b7152799..e3a15ee59 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -65,18 +65,8 @@ TemporalFilter : 0 # Enable/disable GOP Based Temporal TemporalFilterFutureReference : 0 # Enable/disable reading future frames TemporalFilterStrengthFrame4 : 0.4 # Enable filter at every 4th frame with strength -#============ Slices ================ -SliceMode : 0 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 1500 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across +#============ Tiles / Slices ================ +EnablePicPartitioning : 0 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index fe8ca9c99..35fe96c08 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -65,18 +65,8 @@ TemporalFilter : 0 # Enable/disable GOP Based Temporal TemporalFilterFutureReference : 0 # Enable/disable reading future frames TemporalFilterStrengthFrame4 : 0.4 # Enable filter at every 4th frame with strength -#============ Slices ================ -SliceMode : 0 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 1500 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across +#============ Tiles / Slices ================ +EnablePicPartitioning : 0 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 788444ee0..58a684e9e 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -76,18 +76,8 @@ TemporalFilterFutureReference : 1 # Enable/disable reading future fram TemporalFilterStrengthFrame8 : 0.95 # Enable filter at every 8th frame with given strength TemporalFilterStrengthFrame16 : 1.5 # Enable filter at every 16th frame with given strength, longer intervals has higher priority -#============ Slices ================ -SliceMode : 0 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 1500 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across +#============ Tiles / Slices ================ +EnablePicPartitioning : 0 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RasterScanSlice.cfg b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RasterScanSlice.cfg index 1df2375be..fb5b259b9 100644 --- a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RasterScanSlice.cfg +++ b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RasterScanSlice.cfg @@ -70,34 +70,16 @@ TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1 TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) -#============ Slices ================ -SliceMode : 3 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 2 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across - -#============ Tiles ================ -TileUniformSpacing : 0 # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array - # 1: the column and row boundaries are distributed uniformly -UniformTileColsWidthMinus1 : 0 # Width to use if TileUniformSpacing is equal to 1 -UniformTileRowHeightMinus1 : 0 # Height to use if TileUniformSpacing is equal to 1 - -NumTileColumnsMinus1 : 1 # Number of tile columns in a picture minus 1 -TileColumnWidthArray : 2 # Array containing tile column width values in units of CTU (from left to right in picture) -NumTileRowsMinus1 : 1 # Number of tile rows in a picture minus 1 -TileRowHeightArray : 1 # Array containing tile row height values in units of CTU (from top to bottom in picture) - -LFCrossTileBoundaryFlag : 0 # In-loop filtering is across or not across tile boundary. - # 0:not across, 1: across - -RectSliceFlag : 0 +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + +# Figure 4 - Section 6.3.1 - 12 tiles and 3 raster-scan slices +TileColumnWidthArray : 6 6 6 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 3 3 3 3 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 1 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RasterSliceSizes : 2 5 5 # Raster-scan slice sizes in units of tiles. Last slice size will be repeated uniformly to cover any remaining tiles in the picture +DisableLoopFilterAcrossTiles : 0 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 0 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSlice.cfg b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSlice.cfg index a69582afc..952231c63 100644 --- a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSlice.cfg +++ b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSlice.cfg @@ -70,35 +70,16 @@ TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1 TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) -#============ Slices ================ -SliceMode : 3 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 2 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across - -#============ Tiles ================ -TileUniformSpacing : 0 # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array - # 1: the column and row boundaries are distributed uniformly -UniformTileColsWidthMinus1 : 0 # Width to use if TileUniformSpacing is equal to 1 -UniformTileRowHeightMinus1 : 0 # Height to use if TileUniformSpacing is equal to 1 -NumTileColumnsMinus1 : 3 # Number of tile columns in a picture minus 1 -TileColumnWidthArray : 1 1 1 # Array containing tile column width values in units of CTU (from left to right in picture) -NumTileRowsMinus1 : 1 # Number of tile rows in a picture minus 1 -TileRowHeightArray : 1 # Array containing tile row height values in units of CTU (from top to bottom in picture) - -LFCrossTileBoundaryFlag : 0 # In-loop filtering is across or not across tile boundary. - # 0:not across, 1: across - -RectSliceFlag : 1 -NumRectSlicesInPicMinus1 : 3 -RectSlicesBoundaryArray : 0 4 1 5 2 6 3 7 +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + +# Figure 6 - Section 6.3.1 - 4 tiles and 4 rectangular slices +TileColumnWidthArray : 9 9 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 6 6 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 0 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RectSlicePositions : 0 206 9 35 45 107 117 215 # Rectangular slice positions. List containing pairs of top-left CTU RS address followed by bottom-right CTU RS address +DisableLoopFilterAcrossTiles : 0 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 0 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSliceFixedSize.cfg b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSliceFixedSize.cfg new file mode 100644 index 000000000..d939ef937 --- /dev/null +++ b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_RectangularSliceFixedSize.cfg @@ -0,0 +1,163 @@ +#======== File I/O ===================== +BitstreamFile : str.bin +ReconFile : rec.yuv + +#======== Profile ================ +Profile : next + +#======== Unit definition ================ +MaxCUWidth : 64 # Maximum coding unit width in pixel +MaxCUHeight : 64 # Maximum coding unit height in pixel +MaxPartitionDepth : 4 # Maximum coding unit depth + +#======== Coding Structure ============= +IntraPeriod : 32 # Period of I-Frame ( -1 = only first) +DecodingRefreshType : 1 # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI +GOPSize : 16 # GOP Size (number of B slice = GOPSize-1) + +IntraQPOffset : -3 +LambdaFromQpEnable : 1 # see JCTVC-X0038 for suitable parameters for IntraQPOffset, QPoffset, QPOffsetModelOff, QPOffsetModelScale when enabled +# Type POC QPoffset QPOffsetModelOff QPOffsetModelScale CbQPoffset CrQPoffset QPfactor tcOffsetDiv2 betaOffsetDiv2 temporal_id #ref_pics_active_L0 #ref_pics_L0 reference_pictures_L0 #ref_pics_active_L1 #ref_pics_L1 reference_pictures_L1 +Frame1: B 16 1 0.0 0.0 0 0 1.0 0 0 0 2 3 16 32 24 2 2 16 32 +Frame2: B 8 1 -4.8848 0.2061 0 0 1.0 0 0 1 2 2 8 16 2 2 -8 8 +Frame3: B 4 4 -5.7476 0.2286 0 0 1.0 0 0 2 2 2 4 12 2 2 -4 -12 +Frame4: B 2 5 -5.90 0.2333 0 0 1.0 0 0 3 2 2 2 10 2 3 -2 -6 -14 +Frame5: B 1 6 -7.1444 0.3 0 0 1.0 0 0 4 2 2 1 -1 2 4 -1 -3 -7 -15 +Frame6: B 3 6 -7.1444 0.3 0 0 1.0 0 0 4 2 2 1 3 2 3 -1 -5 -13 +Frame7: B 6 5 -5.90 0.2333 0 0 1.0 0 0 3 2 2 2 6 2 2 -2 -10 +Frame8: B 5 6 -7.1444 0.3 0 0 1.0 0 0 4 2 2 1 5 2 3 -1 -3 -11 +Frame9: B 7 6 -7.1444 0.3 0 0 1.0 0 0 4 2 3 1 3 7 2 2 -1 -9 +Frame10: B 12 4 -5.7476 0.2286 0 0 1.0 0 0 2 2 2 4 12 2 2 -4 4 +Frame11: B 10 5 -5.90 0.2333 0 0 1.0 0 0 3 2 2 2 10 2 2 -2 -6 +Frame12: B 9 6 -7.1444 0.3 0 0 1.0 0 0 4 2 2 1 9 2 3 -1 -3 -7 +Frame13: B 11 6 -7.1444 0.3 0 0 1.0 0 0 4 2 3 1 3 11 2 2 -1 -5 +Frame14: B 14 5 -5.90 0.2333 0 0 1.0 0 0 3 2 3 2 6 14 2 2 -2 2 +Frame15: B 13 6 -7.1444 0.3 0 0 1.0 0 0 4 2 3 1 5 13 2 2 -1 -3 +Frame16: B 15 6 -7.1444 0.3 0 0 1.0 0 0 4 2 4 1 3 7 15 2 2 -1 1 + +#=========== Motion Search ============= +FastSearch : 1 # 0:Full search 1:TZ search +SearchRange : 384 # (0: Search range is a Full frame) +ASR : 1 # Adaptive motion search range +MinSearchWindow : 96 # Minimum motion search window size for the adaptive window ME +BipredSearchRange : 4 # Search range for bi-prediction refinement +HadamardME : 1 # Use of hadamard measure for fractional ME +FEN : 1 # Fast encoder decision +FDM : 1 # Fast Decision for Merge RD cost + +#======== Quantization ============= +QP : 32 # Quantization parameter(0-51) +MaxDeltaQP : 0 # CU-based multi-QP optimization +MaxCuDQPSubdiv : 0 # Maximum subdiv for CU luma Qp adjustment +DeltaQpRD : 0 # Slice-based multi-QP optimization +RDOQ : 1 # RDOQ +RDOQTS : 1 # RDOQ for transform skip + +#=========== Deblock Filter ============ +LoopFilterOffsetInPPS : 1 # Dbl params: 0=varying params in SliceHeader, param = base_param + GOP_offset_param; 1 (default) =constant params in PPS, param = base_param) +LoopFilterDisable : 0 # Disable deblocking filter (0=Filter, 1=No Filter) +LoopFilterBetaOffset_div2 : 0 # base_param: -6 ~ 6 +LoopFilterTcOffset_div2 : 0 # base_param: -6 ~ 6 +DeblockingFilterMetric : 0 # blockiness metric (automatically configures deblocking parameters in bitstream). Applies slice-level loop filter offsets (LoopFilterOffsetInPPS and LoopFilterDisable must be 0) + +#=========== Misc. ============ +InternalBitDepth : 10 # codec operating bit-depth + +#=========== Coding Tools ================= +SAO : 1 # Sample adaptive offset (0: OFF, 1: ON) +TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) +TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +TransformSkipLog2MaxSize : 5 +SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) + +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + +# 24 tiles and 6 rectangular slices +TileColumnWidthArray : 3 3 3 3 3 3 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 3 3 3 3 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 0 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RectSliceFixedWidth : 2 # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead) +RectSliceFixedHeight : 2 # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead) +DisableLoopFilterAcrossTiles : 0 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 0 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) + +#============ Lossless ================ +TransquantBypassEnable : 0 # Value of PPS flag. +CUTransquantBypassFlagForce: 0 # Force transquant bypass mode, when transquant_bypass_enable_flag is enabled + +#============ Rate Control ====================== +RateControl : 0 # Rate control: enable rate control +TargetBitrate : 1000000 # Rate control: target bitrate, in bps +KeepHierarchicalBit : 2 # Rate control: 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation +LCULevelRateControl : 1 # Rate control: 1: LCU level RC; 0: picture level RC +RCLCUSeparateModel : 1 # Rate control: use LCU level separate R-lambda model +InitialQP : 0 # Rate control: initial QP +RCForceIntraQP : 0 # Rate control: force intra QP to be equal to initial QP + +#============ VTM settings ====================== +LoopFilterTcOffset_div2 : 0 +SEIDecodedPictureHash : 0 +CbQpOffset : 1 +CrQpOffset : 1 + +ReWriteParamSets : 1 +#============ NEXT ==================== + +# General +CTUSize : 128 +LCTUFast : 1 + +DualITree : 1 # separate partitioning of luma and chroma channels for I-slices +MinQTLumaISlice : 8 +MinQTChromaISlice : 4 +MinQTNonISlice : 8 +MaxMTTHierarchyDepth : 3 +MaxMTTHierarchyDepthISliceL : 3 +MaxMTTHierarchyDepthISliceC : 3 + +MTS : 1 +MTSIntraMaxCand : 3 +MTSInterMaxCand : 4 +SBT : 1 +LFNST : 1 +ISP : 1 +MMVD : 1 +Affine : 1 +SubPuMvp : 1 +MaxNumMergeCand : 6 +LMChroma : 1 # use CCLM only +DepQuant : 1 +IMV : 1 +ALF : 1 +GBi : 1 +GBiFast : 1 +BIO : 1 +MHIntra : 1 +Triangle : 1 +IBC : 0 # turned off in CTC +AllowDisFracMMVD : 1 +AffineAmvr : 1 +LMCSEnable : 1 # LMCS: 0: disable, 1:enable +LMCSSignalType : 0 # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG +LMCSUpdateCtrl : 0 # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP +MIP : 1 +DMVR : 1 +SMVD : 1 + +# Fast tools +PBIntraFast : 1 +ISPFast : 1 +FastMrg : 1 +AMaxBT : 1 +FastMIP : 0 +FastLFNST : 0 + +# Encoder optimization tools +AffineAmvrEncOpt : 1 +MmvdDisNum : 6 +### DO NOT ADD ANYTHING BELOW THIS LINE ### +### DO NOT DELETE THE EMPTY LINE BELOW ### + + + diff --git a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_SingleTilePerSlice.cfg b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_SingleTilePerSlice.cfg index 0aeccf23b..4dabdcdb8 100644 --- a/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_SingleTilePerSlice.cfg +++ b/cfg/nonCTC-SliceConfigExamples/encoder_randomaccess_vtm_SingleTilePerSlice.cfg @@ -70,36 +70,14 @@ TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1 TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) -#============ Slices ================ -SliceMode : 3 # 0: Disable all slice options. - # 1: Enforce maximum number of LCU in an slice, - # 2: Enforce maximum number of bytes in an 'slice' - # 3: Enforce maximum number of tiles in a slice -SliceArgument : 1 # Argument for 'SliceMode'. - # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice. - # If SliceMode==2 it represents max. bytes per slice. - # If SliceMode==3 it represents max. tiles per slice. - -LFCrossSliceBoundaryFlag : 1 # In-loop filtering, including ALF and DB, is across or not across slice boundary. - # 0:not across, 1: across - -#============ Tiles ================ -TileUniformSpacing : 1 # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array - # 1: the column and row boundaries are distributed uniformly -UniformTileColsWidthMinus1 : 1 # Width to use if TileUniformSpacing is equal to 1 -UniformTileRowHeightMinus1 : 0 # Height to use if TileUniformSpacing is equal to 1 - -NumTileColumnsMinus1 : 1 # Number of tile columns in a picture minus 1 -TileColumnWidthArray : 2 # Array containing tile column width values in units of CTU (from left to right in picture) -NumTileRowsMinus1 : 1 # Number of tile rows in a picture minus 1 -TileRowHeightArray : 1 # Array containing tile row height values in units of CTU (from top to bottom in picture) - -LFCrossTileBoundaryFlag : 0 # In-loop filtering is across or not across tile boundary. - # 0:not across, 1: across - -RectSliceFlag : 1 -NumRectSlicesInPicMinus1 : 3 -RectSlicesBoundaryArray : 0 0 1 1 2 2 3 3 +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) +TileColumnWidthArray : 1 2 3 4 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 1 2 3 4 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 1 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RasterSliceSizes : 1 # Raster-scan slice sizes in units of tiles. Last slice size will be repeated uniformly to cover any remaining tiles in the picture +DisableLoopFilterAcrossTiles : 0 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 0 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) #============ Lossless ================ TransquantBypassEnable : 0 # Value of PPS flag. diff --git a/doc/software-manual.tex b/doc/software-manual.tex index d75a76205..3e305d9bc 100755 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1707,167 +1707,82 @@ Specifies the maximum depth for CU chroma QP adjustment; if negative, CU chroma %% -%% Slice/Tile/Brick coding parameters +%% Slice/Tile coding parameters %% -\begin{OptionTableNoShorthand}{Slice, tile and brick coding parameters}{tab:slice-coding} -%\Option{SliceGranularity} & -%\ShortOption{\None} & -%\Default{0} & -%Determines the depth in an LCU at which slices may begin and end. -%\par -%\begin{tabular}{cp{0.45\textwidth}} -% 0 & Slice addresses are LCU aligned \\ -% $1 \leq n \leq 3$ -% & Slice start addresses are aligned to CUs at depth $n$ \\ -%\end{tabular} -% -%Note: The smallest permissible alignment is 16x16 CUs. -%Values of $n$ must satisfy this constraint, for example, with a 64x64 -%LCU, $n$ must be less than or equal to 2. -%\\ +\begin{OptionTableNoShorthand}{Slice and tile coding parameters}{tab:slice-coding} -\Option{SliceMode} & +\Option{EnablePicPartitioning} & %\ShortOption{\None} & \Default{0} & -Controls the slice partitioning method in conjunction with -SliceArgument. -\par -\begin{tabular}{cp{0.45\textwidth}} - 0 & Single slice \\ - 1 & (deprecated) Maximum number of CTUs per slice \\ - 2 & (deprecated) Maximum number of bytes per slice \\ - 3 & Maximum number of tiles per slice \\ - 4 & One slice per brick -\end{tabular} +Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used). \\ -\Option{SliceArgument} & +\Option{TileColumnWidthArray} & %\ShortOption{\None} & \Default{\NotSet} & -(deprecated) -Specifies the maximum number of CTUs, bytes or tiles in a slice depending on the -SliceMode setting. +Tile column widths in units of CTUs. Last column width in list will be repeated uniformly to cover any remaining picture width. \\ -\Option{RectSliceFlag} & +\Option{TileRowHeightArray} & %\ShortOption{\None} & -\Default{1} & -Controls the slice shape method in conjunction with SliceMode, -SliceArgument, and Tile/Brick configurations. -\par -\begin{tabular}{cp{0.45\textwidth}} - 0 & Raster scan slice. Bricks within slice are in raster scan order \\ - 1 & Rectangular slice. Bricks within slice form rectangular shape \\ - NOTE: When SliceMode is equal to 3, RectSliceFlag is equal to 1, - and there is more than one tiles/bricks in the pic, - NumRecSliceInPicMinus1 must be greater than 0 -\end{tabular} +\Default{\NotSet} & +Tile row heights in units of CTUs. Last row height in list will be repeated uniformly to cover any remaining picture height. \\ -\Option{NumRecSlicesInPicMinus1} & +\Option{RasterScanSlices} & %\ShortOption{\None} & \Default{0} & -Specifies the number of rectangular slices in the picture. +Use raster-scan or rectangular slices (0: rectangular, 1: raster-scan). \\ -\Option{RectSlicesBoundaryArray} & +\Option{RectSlicePositions} & %\ShortOption{\None} & \Default{\NotSet} & -Specifies a space or comma separated list of top-left brick index and -bottom-right brick index of rectangular slices. -The top-left brick index and bottom-right brick index corresponds to the top left -rectangular slice in the picture. The rest of indices corresponds to the each rectangular slices -in the picture in the rectangular slice raster scan in the picture, respectively. - -For example, when the picture is partitioned into 16 tiles (4 tile columns and 4 tile rows), -each tile is not further partitioned into bricks, SliceMode is equal to 3, SliceArgument is equal to 4, -and NumRecSlicesInPicMinus1 is equal to 3, the values of RectSlicesBoundaryArray shall be as followss: -0 5 2 7 8 13 10 15. -\par -\begin{tabular}{cp{0.45\textwidth}} - First slice has top-left brick index 0 and bottom-right brick index 5 \\ - Second slice has top-left brick index 2 and bottom-right brick index 7 \\ - Third slice has top-left brick index 8 and bottom-right brick index 13 \\ - Fourth slice has top-left brick index 10 and bottom-right brick index 15 -\end{tabular} +Rectangular slice positions. List containing pairs of top-left CTU RS address followed by bottom-right CTU RS address. \\ -\Option{IDRRefParamList} & +\Option{RectSliceFixedWidth} & %\ShortOption{\None} & -\Default{false} & -Enables the signalling of reference picture list syntax elements in slice headers of IDR pictures +\Default{0} & +Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead). \\ -\Option{WaveFrontSynchro} & +\Option{RectSliceFixedHeight} & %\ShortOption{\None} & -\Default{false} & -Enables the use of specific CABAC probabilities synchronization at the -beginning of each line of CTBs in order to produce a bitstream that can -be encoded or decoded using one or more cores. +\Default{0} & +Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead). \\ -\Option{TileUniformSpacing} & +\Option{RasterSliceSizes} & %\ShortOption{\None} & -\Default{false} & -Controls the mode used to determine per row and column tile sizes. -\par -\begin{tabular}{cp{0.45\textwidth}} - 0 & Each tile column width and tile row height is explicitly set - by TileColumnWidthArray and TileRowHeightArray respectively \\ - 1 & Tile columns and tile rows are uniformly spaced. \\ -\end{tabular} +\Default{\NotSet} & +Raster-scan slice sizes in units of tiles. Last size in list will be repeated uniformly to cover any remaining tiles in the picture. \\ -\Option{UniformTileColsWidthMinus1}% -\Option{UniformTileRowHeightMinus1} & +\Option{DisableLoopFilterAcrossTiles} & %\ShortOption{\None} & -\Default{-1} & -Specifies the tile width and height to use if TileUniformSpacing is set to 1. +\Default{0} & +Loop filtering applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries). \\ -\Option{NumTileColumnsMinus1}% -\Option{NumTileRowsMinus1} & +\Option{DisableLoopFilterAcrossSlices} & %\ShortOption{\None} & \Default{0} & -Specifies the tile based picture partitioning geometry as -$\mathrm{NumTileColumnsMinus1} + 1 \times \mathrm{NumTileRowsMinus1} + 1$ -columns and rows. +Loop filtering applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries). \\ -\Option{TileColumnWidthArray}% -\Option{TileRowHeightArray} & +\Option{IDRRefParamList} & %\ShortOption{\None} & -\Default{\NotSet} & -Specifies a space or comma separated list of widths and heights, -respectively, of each tile column or tile row. The first value in the -list corresponds to the leftmost tile column or topmost tile row. +\Default{false} & +Enables the signalling of reference picture list syntax elements in slice headers of IDR pictures \\ -\Option{BrickSplit1}% -\Option{BrickSplit2} % -\Option{BrickSplitN} & -%\ShortOption{\None} & -\Default{\NotSet} & -Specifies the splitting of tiles into bricks, N can be in the range of 1 to 128 and has no further meaning except to distinguish different splitting parameters. - -The following options are supported: - -BrickSplitN tileIdx uniform (numsplits) heights - -\begin{tabular}{cp{0.45\textwidth}} - tileIdx & the index of the tile to be split in raster scan order starting with zero \\ - uniform & specifies whether uniform splitting shall be used (1 for uniform, 0 non-uniform) \\ - numsplits & specifies the number of splits, if uniform is not used \\ - heights & specifies the height of the uniform splits or a list of heights for non-uniform splits \\ -\end{tabular} - -\\ -\Option{TileRowHeightArray} & +\Option{WaveFrontSynchro} & %\ShortOption{\None} & -\Default{\NotSet} & -Specifies a space or comma separated list of widths and heights, -respectively, of each tile column or tile row. The first value in the -list corresponds to the leftmost tile column or topmost tile row. +\Default{false} & +Enables the use of specific CABAC probabilities synchronization at the +beginning of each line of CTBs in order to produce a bitstream that can +be encoded or decoded using one or more cores. \\ @@ -1885,13 +1800,6 @@ list corresponds to the leftmost tile column or topmost tile row. Enables or disables the in-loop deblocking filter. \\ -\Option{LFCrossSliceBoundaryFlag} & -%\ShortOption{\None} & -\Default{true} & -Enables or disables the use of in-loop filtering across slice -boundaries. -\\ - \Option{LoopFilterOffsetInPPS}& %\ShortOption{\None}& \Default{false}& @@ -1926,12 +1834,6 @@ Specifies the use of a deblocking filter metric to evaluate the suitability of d LoopFilterOffsetInPPS and LoopFilterDisable must be 0. Currently excepted values are 0, 1 and 2. \\ -\Option{LFCrossSliceBoundaryFlag}& -%\ShortOption{\None}& -\Default{true}& -Enables or disables the use of a deblocking across tile boundaries. -\\ - \Option{LoopFilterAcrossVirtualBoundariesDisabledFlag}& %\ShortOption{\None}& \Default{false}& diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 4a61240e4..7f65ed862 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -440,6 +440,30 @@ void EncApp::xInitLibCfg() m_cEncLib.setUseWP ( m_useWeightedPred ); m_cEncLib.setWPBiPred ( m_useWeightedBiPred ); +#if JVET_P1004_REMOVE_BRICKS + //====== Tiles and Slices ======== + m_cEncLib.setNoPicPartitionFlag( !m_picPartitionFlag ); + if( m_picPartitionFlag ) + { + m_cEncLib.setTileColWidths( m_tileColumnWidth ); + m_cEncLib.setTileRowHeights( m_tileRowHeight ); + m_cEncLib.setRectSliceFlag( !m_rasterSliceFlag ); + m_cEncLib.setNumSlicesInPic( m_numSlicesInPic ); + m_cEncLib.setTileIdxDeltaPresentFlag( m_tileIdxDeltaPresentFlag ); + m_cEncLib.setRectSlices( m_rectSlices ); + m_cEncLib.setRasterSliceSizes( m_rasterSliceSize ); + m_cEncLib.setLFCrossTileBoundaryFlag( !m_disableLFCrossTileBoundaryFlag ); + m_cEncLib.setLFCrossSliceBoundaryFlag( !m_disableLFCrossSliceBoundaryFlag ); + } + else + { + m_cEncLib.setRectSliceFlag( true ); + m_cEncLib.setNumSlicesInPic( 1 ); + m_cEncLib.setTileIdxDeltaPresentFlag( 0 ); + m_cEncLib.setLFCrossTileBoundaryFlag( true ); + m_cEncLib.setLFCrossSliceBoundaryFlag( true ); + } +#else //====== Slice ======== m_cEncLib.setSliceMode ( m_sliceMode ); m_cEncLib.setSliceArgument ( m_sliceArgument ); @@ -450,6 +474,7 @@ void EncApp::xInitLibCfg() m_bLFCrossSliceBoundaryFlag = true; } m_cEncLib.setLFCrossSliceBoundaryFlag ( m_bLFCrossSliceBoundaryFlag ); +#endif m_cEncLib.setUseSAO ( m_bUseSAO ); m_cEncLib.setTestSAODisableAtPictureLevel ( m_bTestSAODisableAtPictureLevel ); m_cEncLib.setSaoEncodingRate ( m_saoEncodingRate ); @@ -550,6 +575,7 @@ void EncApp::xInitLibCfg() m_cEncLib.setSEIXSDMetricType ( uint8_t(m_xsdMetricType) ); #endif +#if !JVET_P1004_REMOVE_BRICKS m_cEncLib.setTileUniformSpacingFlag ( m_tileUniformSpacingFlag ); if (m_tileUniformSpacingFlag) { @@ -580,6 +606,7 @@ void EncApp::xInitLibCfg() m_bLFCrossTileBoundaryFlag = true; } m_cEncLib.setLFCrossTileBoundaryFlag ( m_bLFCrossTileBoundaryFlag ); +#endif m_cEncLib.setEntropyCodingSyncEnabledFlag ( m_entropyCodingSyncEnabledFlag ); m_cEncLib.setTMVPModeId ( m_TMVPModeId ); #if JVET_P1006_PICTURE_HEADER diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index c4115fa9e..a3c1abdfc 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -231,6 +231,7 @@ std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry) //in return in; } +#if !JVET_P1004_REMOVE_BRICKS std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry) //input { in>>entry.m_tileIdx; @@ -249,6 +250,7 @@ std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry) // } return in; } +#endif bool confirmPara(bool bflag, const char* message); @@ -715,6 +717,91 @@ automaticallySelectRExtProfile(const bool bUsingGeneralRExtTools, } } } +#if JVET_P1004_REMOVE_BRICKS + +static uint32_t getMaxTileColsByLevel( Level::Name level ) +{ + switch( level ) + { + case Level::LEVEL1: + case Level::LEVEL2: + case Level::LEVEL2_1: + return 1; + case Level::LEVEL3: + return 2; + case Level::LEVEL3_1: + return 3; + case Level::LEVEL4: + case Level::LEVEL4_1: + return 5; + case Level::LEVEL5: + case Level::LEVEL5_1: + case Level::LEVEL5_2: + return 10; + case Level::LEVEL6: + case Level::LEVEL6_1: + case Level::LEVEL6_2: + default: + return 20; + } +} + +static uint32_t getMaxTileRowsByLevel( Level::Name level ) +{ + switch( level ) + { + case Level::LEVEL1: + case Level::LEVEL2: + case Level::LEVEL2_1: + return 1; + case Level::LEVEL3: + return 2; + case Level::LEVEL3_1: + return 3; + case Level::LEVEL4: + case Level::LEVEL4_1: + return 5; + case Level::LEVEL5: + case Level::LEVEL5_1: + case Level::LEVEL5_2: + return 11; + case Level::LEVEL6: + case Level::LEVEL6_1: + case Level::LEVEL6_2: + default: + return 21; + } +} + +static uint32_t getMaxSlicesByLevel( Level::Name level ) +{ + switch( level ) + { + case Level::LEVEL1: + case Level::LEVEL2: + return 16; + case Level::LEVEL2_1: + return 20; + case Level::LEVEL3: + return 30; + case Level::LEVEL3_1: + return 40; + case Level::LEVEL4: + case Level::LEVEL4_1: + return 75; + case Level::LEVEL5: + case Level::LEVEL5_1: + case Level::LEVEL5_2: + return 200; + case Level::LEVEL6: + case Level::LEVEL6_1: + case Level::LEVEL6_2: + default: + return 600; + } +} + +#endif // ==================================================================================================================== // Public member functions // ==================================================================================================================== @@ -733,7 +820,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) int tmpWeightedPredictionMethod; int tmpFastInterSearchMode; int tmpMotionEstimationSearchMethod; +#if !JVET_P1004_REMOVE_BRICKS int tmpSliceMode; +#endif int tmpDecodedPictureHashSEIMappedType; string inputColourSpaceConvert; string inputPathPrefix; @@ -741,14 +830,23 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) int saoOffsetBitShift[MAX_NUM_CHANNEL_TYPE]; // Multi-value input fields: // minval, maxval (incl), min_entries, max_entries (incl) [, default values, number of default values] +#if JVET_P1004_REMOVE_BRICKS + SMultiValueInput<uint32_t> cfgTileColumnWidth (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); + SMultiValueInput<uint32_t> cfgTileRowHeight (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); + SMultiValueInput<uint32_t> cfgRectSlicePos (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); + SMultiValueInput<uint32_t> cfgRasterSliceSize (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); +#else SMultiValueInput<uint32_t> cfg_ColumnWidth (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); SMultiValueInput<uint32_t> cfg_RowHeight (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); +#endif SMultiValueInput<int> cfg_startOfCodedInterval (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16); SMultiValueInput<int> cfg_codedPivotValue (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16); SMultiValueInput<int> cfg_targetPivotValue (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16); +#if !JVET_P1004_REMOVE_BRICKS SMultiValueInput<uint32_t> cfg_SliceIdx (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); SMultiValueInput<uint32_t> cfg_SignalledSliceId (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); +#endif SMultiValueInput<double> cfg_adIntraLambdaModifier (0, std::numeric_limits<double>::max(), 0, MAX_TLAYER); ///< Lambda modifier for Intra pictures, one for each temporal layer. If size>temporalLayer, then use [temporalLayer], else if size>0, use [size()-1], else use m_adLambdaModifier. @@ -1179,6 +1277,18 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("MaxNumOffsetsPerPic", m_maxNumOffsetsPerPic, 2048, "Max number of SAO offset per picture (Default: 2048)") ("SAOLcuBoundary", m_saoCtuBoundary, false, "0: right/bottom CTU boundary areas skipped from SAO parameter estimation, 1: non-deblocked pixels are used for those areas") ("SAOGreedyEnc", m_saoGreedyMergeEnc, false, "SAO greedy merge encoding algorithm") +#if JVET_P1004_REMOVE_BRICKS + ("EnablePicPartitioning", m_picPartitionFlag, false, "Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used)") + ("TileColumnWidthArray", cfgTileColumnWidth, cfgTileColumnWidth, "Tile column widths in units of CTUs. Last column width in list will be repeated uniformly to cover any remaining picture width") + ("TileRowHeightArray", cfgTileRowHeight, cfgTileRowHeight, "Tile row heights in units of CTUs. Last row height in list will be repeated uniformly to cover any remaining picture height") + ("RasterScanSlices", m_rasterSliceFlag, false, "Indicates if using raster-scan or rectangular slices (0: rectangular, 1: raster-scan)") + ("RectSlicePositions", cfgRectSlicePos, cfgRectSlicePos, "Rectangular slice positions. List containing pairs of top-left CTU RS address followed by bottom-right CTU RS address") + ("RectSliceFixedWidth", m_rectSliceFixedWidth, 0, "Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead)") + ("RectSliceFixedHeight", m_rectSliceFixedHeight, 0, "Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead)") + ("RasterSliceSizes", cfgRasterSliceSize, cfgRasterSliceSize, "Raster-scan slice sizes in units of tiles. Last size in list will be repeated uniformly to cover any remaining tiles in the picture") + ("DisableLoopFilterAcrossTiles", m_disableLFCrossTileBoundaryFlag, false, "Loop filtering applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries)") + ("DisableLoopFilterAcrossSlices", m_disableLFCrossSliceBoundaryFlag, false, "Loop filtering applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries)") +#else ("SliceMode", tmpSliceMode, int(NO_SLICES), "0: Disable all Recon slice limits, 1: (deprecated #CTU), 2: (deprecated #bytes), 3:specify tiles per slice, 4: one brick per slice") ("SliceArgument", m_sliceArgument, 0, "Depending on SliceMode being:" "\t1: max number of CTUs per slice" @@ -1186,6 +1296,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) "\t3: max number of tiles per slice") ("LFCrossSliceBoundaryFlag", m_bLFCrossSliceBoundaryFlag, true) +#endif ("FastUDIUseMPMEnabled", m_bFastUDIUseMPMEnabled, true, "If enabled, adapt intra direction search, accounting for MPM") ("FastMEForGenBLowDelayEnabled", m_bFastMEForGenBLowDelayEnabled, true, "If enabled use a fast ME for generalised B Low Delay slices") ("UseBLambdaForNonKeyLowDelayPictures", m_bUseBLambdaForNonKeyLowDelayPictures, true, "Enables use of B-Lambda for non-key low-delay pictures") @@ -1193,6 +1304,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("WeightedPredP,-wpP", m_useWeightedPred, false, "Use weighted prediction in P slices") ("WeightedPredB,-wpB", m_useWeightedBiPred, false, "Use weighted (bidirectional) prediction in B slices") ("WeightedPredMethod,-wpM", tmpWeightedPredictionMethod, int(WP_PER_PICTURE_WITH_SIMPLE_DC_COMBINED_COMPONENT), "Weighted prediction method") +#if !JVET_P1004_REMOVE_BRICKS //deprecated copies of renamed tile parameters ("UniformSpacingIdc", m_tileUniformSpacingFlag, false, "deprecated alias of TileUniformSpacing") ("TileUniformSpacing", m_tileUniformSpacingFlag, false, "Indicates that tile columns and rows are distributed uniformly") @@ -1203,7 +1315,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("TileColumnWidthArray", cfg_ColumnWidth, cfg_ColumnWidth, "Array containing tile column width values in units of CTU") ("TileRowHeightArray", cfg_RowHeight, cfg_RowHeight, "Array containing tile row height values in units of CTU") ("LFCrossTileBoundaryFlag", m_bLFCrossTileBoundaryFlag, true, "1: cross-tile-boundary loop filtering. 0:non-cross-tile-boundary loop filtering") +#endif ("WaveFrontSynchro", m_entropyCodingSyncEnabledFlag, false, "0: entropy coding sync disabled; 1 entropy coding sync enabled") +#if !JVET_P1004_REMOVE_BRICKS ("RectSliceFlag", m_rectSliceFlag, true, "Rectangular slice flag") ("NumRectSlicesInPicMinus1", m_numSlicesInPicMinus1, 0, "Number slices in pic minus 1") @@ -1213,6 +1327,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("RectSlicesBoundaryArray", cfg_SliceIdx, cfg_SliceIdx, "Rectangular slices boundaries in Pic") ("SignalledSliceId", cfg_SignalledSliceId, cfg_SliceIdx, "Signalled rectangular slice ID") +#endif ("ScalingList", m_useScalingListId, SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile") ("ScalingListFile", m_scalingListFileName, string(""), "Scaling list file name. Use an empty string to produce help.") #if JVET_P0365_SCALING_MATRIX_LFNST @@ -1458,6 +1573,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) opts.addOptions()(cOSS.str(), m_GOPList[i-1], GOPEntry()); } +#if !JVET_P1004_REMOVE_BRICKS for(int i=1; i<MAX_TILES+1; i++) { std::ostringstream cOSS; @@ -1465,6 +1581,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) opts.addOptions()(cOSS.str(), m_brickSplits[i-1], BrickSplit()); } +#endif po::setDefaults(opts); po::ErrorReporter err; const list<const char*>& argv_unhandled = po::scanArgv(opts, argc, (const char**) argv, err); @@ -1614,6 +1731,54 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_framesToBeEncoded *= 2; } +#if JVET_P1004_REMOVE_BRICKS + if( m_picPartitionFlag ) + { + // store tile column widths + m_tileColumnWidth.resize(cfgTileColumnWidth.values.size()); + for(uint32_t i=0; i<cfgTileColumnWidth.values.size(); i++) + { + m_tileColumnWidth[i]=cfgTileColumnWidth.values[i]; + } + + // store tile row heights + m_tileRowHeight.resize(cfgTileRowHeight.values.size()); + for(uint32_t i=0; i<cfgTileRowHeight.values.size(); i++) + { + m_tileRowHeight[i]=cfgTileRowHeight.values[i]; + } + + // store rectangular slice positions + if( !m_rasterSliceFlag ) + { + m_rectSlicePos.resize(cfgRectSlicePos.values.size()); + for(uint32_t i=0; i<cfgRectSlicePos.values.size(); i++) + { + m_rectSlicePos[i]=cfgRectSlicePos.values[i]; + } + } + + // store raster-scan slice sizes + else + { + m_rasterSliceSize.resize(cfgRasterSliceSize.values.size()); + for(uint32_t i=0; i<cfgRasterSliceSize.values.size(); i++) + { + m_rasterSliceSize[i]=cfgRasterSliceSize.values[i]; + } + } + } + else + { + m_tileColumnWidth.clear(); + m_tileRowHeight.clear(); + m_rectSlicePos.clear(); + m_rasterSliceSize.clear(); + m_rectSliceFixedWidth = 0; + m_rectSliceFixedHeight = 0; + } + +#else if( !m_tileUniformSpacingFlag && m_numTileColumnsMinus1 > 0 ) { if (cfg_ColumnWidth.values.size() > m_numTileColumnsMinus1) @@ -1661,6 +1826,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) { m_tileRowHeight.clear(); } +#endif m_numSubProfile = (uint8_t) cfg_SubProfile.values.size(); m_subProfile.resize(m_numSubProfile); for (uint8_t i = 0; i < m_numSubProfile; ++i) @@ -1668,6 +1834,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_subProfile[i] = cfg_SubProfile.values[i]; } +#if !JVET_P1004_REMOVE_BRICKS if (m_tileUniformSpacingFlag) { int uniformTileHeight = ((m_uniformTileRowHeightMinus1 + 1) * m_uiCTUSize); @@ -1675,6 +1842,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_numTileRowsMinus1 = ((m_iSourceHeight + uniformTileHeight - 1) / uniformTileHeight) - 1; m_numTileColumnsMinus1 = ((m_iSourceWidth + uniformTileWidth - 1) / uniformTileWidth) - 1; } +#endif /* rules for input, output and internal bitdepths as per help text */ if (m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA ] == 0) { @@ -1876,6 +2044,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if !JVET_P1004_REMOVE_BRICKS if (tmpSliceMode<0 || tmpSliceMode>=int(NUMBER_OF_SLICE_CONSTRAINT_MODES)) { EXIT( "Error: bad slice mode"); @@ -2024,6 +2193,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_sliceId[i] = i; } } +#endif if (tmpDecodedPictureHashSEIMappedType<0 || tmpDecodedPictureHashSEIMappedType>=int(NUMBER_OF_HASHTYPES)) { @@ -2881,17 +3051,21 @@ bool EncAppCfg::xCheckParameter() xConfirmPara(!m_useTransformSkip, "BDPCM cannot be used when transform skip is disabled."); } +#if !JVET_P1004_REMOVE_BRICKS if (m_sliceMode!=NO_SLICES) { xConfirmPara( m_sliceArgument < 1 , "SliceArgument should be larger than or equal to 1" ); } +#endif +#if !JVET_P1004_REMOVE_BRICKS bool tileFlag = (m_numTileColumnsMinus1 > 0 || m_numTileRowsMinus1 > 0 ); if (m_profile!=Profile::HIGHTHROUGHPUTREXT) { xConfirmPara( tileFlag && m_entropyCodingSyncEnabledFlag, "Tiles and entropy-coding-sync (Wavefronts) can not be applied together, except in the High Throughput Intra 4:4:4 16 profile"); } +#endif xConfirmPara( m_iSourceWidth % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling"); xConfirmPara( m_iSourceHeight % SPS::getWinUnitY(m_chromaFormatIDC) != 0, "Picture height must be an integer multiple of the specified chroma subsampling"); @@ -3318,6 +3492,264 @@ bool EncAppCfg::xCheckParameter() m_maxDecPicBuffering[MAX_TLAYER-1] = m_numReorderPics[MAX_TLAYER-1] + 1; } +#if JVET_P1004_REMOVE_BRICKS + if( m_picPartitionFlag ) + { + PPS pps; + uint32_t colIdx, rowIdx; + uint32_t remSize; + + pps.setPicWidthInLumaSamples( m_iSourceWidth ); + pps.setPicHeightInLumaSamples( m_iSourceHeight ); + pps.setLog2CtuSize( floorLog2(m_uiCTUSize) ); + + // set default tile column if not provided + if( m_tileColumnWidth.size() == 0 ) + { + m_tileColumnWidth.push_back( pps.getPicWidthInCtu() ); + } + // set default tile row if not provided + if( m_tileRowHeight.size() == 0 ) + { + m_tileRowHeight.push_back( pps.getPicHeightInCtu() ); + } + + // remove any tile columns that can be specified implicitly + while( m_tileColumnWidth.size() > 1 && m_tileColumnWidth.end()[-1] == m_tileColumnWidth.end()[-2] ) + { + m_tileColumnWidth.pop_back(); + } + + // remove any tile rows that can be specified implicitly + while( m_tileRowHeight.size() > 1 && m_tileRowHeight.end()[-1] == m_tileRowHeight.end()[-2] ) + { + m_tileRowHeight.pop_back(); + } + + // setup tiles in temporary PPS structure + remSize = pps.getPicWidthInCtu(); + for( colIdx=0; remSize > 0 && colIdx<m_tileColumnWidth.size(); colIdx++ ) + { + xConfirmPara(m_tileColumnWidth[ colIdx ] == 0, "Tile column widths cannot be equal to 0"); + m_tileColumnWidth[ colIdx ] = std::min( remSize, m_tileColumnWidth[ colIdx ]); + pps.addTileColumnWidth( m_tileColumnWidth[ colIdx ] ); + remSize -= m_tileColumnWidth[ colIdx ]; + } + m_tileColumnWidth.resize( colIdx ); + pps.setNumExpTileColumns( (uint32_t)m_tileColumnWidth.size() ); + remSize = pps.getPicHeightInCtu(); + for( rowIdx=0; remSize > 0 && rowIdx<m_tileRowHeight.size(); rowIdx++ ) + { + xConfirmPara(m_tileRowHeight[ rowIdx ] == 0, "Tile row heights cannot be equal to 0"); + m_tileRowHeight[ rowIdx ] = std::min( remSize, m_tileRowHeight[ rowIdx ]); + pps.addTileRowHeight( m_tileRowHeight[ rowIdx ] ); + remSize -= m_tileRowHeight[ rowIdx ]; + } + m_tileRowHeight.resize( rowIdx ); + pps.setNumExpTileRows( (uint32_t)m_tileRowHeight.size() ); + pps.initTiles(); + xConfirmPara(pps.getNumTileColumns() > getMaxTileColsByLevel( m_level ), "Number of tile columns exceeds maximum number allowed according to specified level"); + xConfirmPara(pps.getNumTileRows() > getMaxTileRowsByLevel( m_level ), "Number of tile rows exceeds maximum number allowed according to specified level"); + m_numTileCols = pps.getNumTileColumns(); + m_numTileRows = pps.getNumTileRows(); + + // rectangular slices + if( !m_rasterSliceFlag ) + { + uint32_t sliceIdx; + bool needTileIdxDelta = false; + + // generate slice list for the simplified fixed-rectangular-slice-size config option + if( m_rectSliceFixedWidth > 0 && m_rectSliceFixedHeight > 0 ) + { + int tileIdx = 0; + m_rectSlicePos.clear(); + while( tileIdx < pps.getNumTiles() ) + { + uint32_t startTileX = tileIdx % pps.getNumTileColumns(); + uint32_t startTileY = tileIdx / pps.getNumTileColumns(); + uint32_t startCtuX = pps.getTileColumnBd( startTileX ); + uint32_t startCtuY = pps.getTileRowBd( startTileY ); + uint32_t stopCtuX = (startTileX + m_rectSliceFixedWidth) >= pps.getNumTileColumns() ? pps.getPicWidthInCtu() - 1 : pps.getTileColumnBd( startTileX + m_rectSliceFixedWidth ) - 1; + uint32_t stopCtuY = (startTileY + m_rectSliceFixedHeight) >= pps.getNumTileRows() ? pps.getPicHeightInCtu() - 1 : pps.getTileRowBd( startTileY + m_rectSliceFixedHeight ) - 1; + uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); + uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); + + // add rectangular slice to list + m_rectSlicePos.push_back( startCtuY * pps.getPicWidthInCtu() + startCtuX ); + m_rectSlicePos.push_back( stopCtuY * pps.getPicWidthInCtu() + stopCtuX ); + + // get slice size in tiles + uint32_t sliceWidth = stopTileX - startTileX + 1; + uint32_t sliceHeight = stopTileY - startTileY + 1; + + // move to next tile in raster scan order + tileIdx += sliceWidth; + if( tileIdx % pps.getNumTileColumns() == 0 ) + { + tileIdx += (sliceHeight - 1) * pps.getNumTileColumns(); + } + } + } + + xConfirmPara( m_rectSlicePos.size() & 1, "Odd number of rectangular slice positions provided. Rectangular slice positions must be specified in pairs of (top-left / bottom-right) raster-scan CTU addresses."); + + // set default slice size if not provided + if( m_rectSlicePos.size() == 0 ) + { + m_rectSlicePos.push_back( 0 ); + m_rectSlicePos.push_back( pps.getPicWidthInCtu() * pps.getPicHeightInCtu() - 1 ); + } + pps.setNumSlicesInPic( (uint32_t)(m_rectSlicePos.size() >> 1) ); + xConfirmPara(pps.getNumSlicesInPic() > getMaxSlicesByLevel( m_level ), "Number of rectangular slices exceeds maximum number allowed according to specified level"); + pps.initRectSlices(); + + // set slice parameters from CTU addresses + for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) + { + xConfirmPara( m_rectSlicePos[2*sliceIdx] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); + xConfirmPara( m_rectSlicePos[2*sliceIdx + 1] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); + + // map raster scan CTU address to X/Y position + uint32_t startCtuX = m_rectSlicePos[2*sliceIdx] % pps.getPicWidthInCtu(); + uint32_t startCtuY = m_rectSlicePos[2*sliceIdx] / pps.getPicWidthInCtu(); + uint32_t stopCtuX = m_rectSlicePos[2*sliceIdx + 1] % pps.getPicWidthInCtu(); + uint32_t stopCtuY = m_rectSlicePos[2*sliceIdx + 1] / pps.getPicWidthInCtu(); + + // get corresponding tile index + uint32_t startTileX = pps.ctuToTileCol( startCtuX ); + uint32_t startTileY = pps.ctuToTileRow( startCtuY ); + uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); + uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); + uint32_t tileIdx = startTileY * pps.getNumTileColumns() + startTileX; + + // get slice size in tiles + uint32_t sliceWidth = stopTileX - startTileX + 1; + uint32_t sliceHeight = stopTileY - startTileY + 1; + + // check for slice / tile alignment + xConfirmPara( startCtuX != pps.getTileColumnBd( startTileX ), "Rectangular slice position does not align with a left tile edge."); + xConfirmPara( stopCtuX != (pps.getTileColumnBd( stopTileX + 1 ) - 1), "Rectangular slice position does not align with a right tile edge."); + if( sliceWidth > 1 || sliceHeight > 1 ) + { + xConfirmPara( startCtuY != pps.getTileRowBd( startTileY ), "Rectangular slice position does not align with a top tile edge."); + xConfirmPara( stopCtuY != (pps.getTileRowBd( stopTileY + 1 ) - 1), "Rectangular slice position does not align with a bottom tile edge."); + } + + // set slice size and tile index + pps.setSliceWidthInTiles( sliceIdx, sliceWidth ); + pps.setSliceHeightInTiles( sliceIdx, sliceHeight ); + pps.setSliceTileIdx( sliceIdx, tileIdx ); + if( sliceIdx > 0 && !needTileIdxDelta ) + { + uint32_t lastTileIdx = pps.getSliceTileIdx( sliceIdx-1 ); + lastTileIdx += pps.getSliceWidthInTiles( sliceIdx-1 ); + if( lastTileIdx % pps.getNumTileColumns() == 0) + { + lastTileIdx += (pps.getSliceHeightInTiles( sliceIdx-1 ) - 1) * pps.getNumTileColumns(); + } + if( lastTileIdx != tileIdx ) + { + needTileIdxDelta = true; + } + } + + // special case for multiple slices within a single tile + if( sliceWidth == 1 && sliceHeight == 1 ) + { + uint32_t firstSliceIdx = sliceIdx; + uint32_t numSlicesInTile = 1; + pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); + + while( sliceIdx < pps.getNumSlicesInPic()-1 ) + { + uint32_t nextTileIdx; + startCtuX = m_rectSlicePos[2*(sliceIdx+1)] % pps.getPicWidthInCtu(); + startCtuY = m_rectSlicePos[2*(sliceIdx+1)] / pps.getPicWidthInCtu(); + stopCtuX = m_rectSlicePos[2*(sliceIdx+1) + 1] % pps.getPicWidthInCtu(); + stopCtuY = m_rectSlicePos[2*(sliceIdx+1) + 1] / pps.getPicWidthInCtu(); + startTileX = pps.ctuToTileCol( startCtuX ); + startTileY = pps.ctuToTileRow( startCtuY ); + stopTileX = pps.ctuToTileCol( stopCtuX ); + stopTileY = pps.ctuToTileRow( stopCtuY ); + nextTileIdx = startTileY * pps.getNumTileColumns() + startTileX; + sliceWidth = stopTileX - startTileX + 1; + sliceHeight = stopTileY - startTileY + 1; + if(nextTileIdx != tileIdx || sliceWidth != 1 || sliceHeight != 1) + { + break; + } + numSlicesInTile++; + sliceIdx++; + pps.setSliceWidthInTiles( sliceIdx, 1 ); + pps.setSliceHeightInTiles( sliceIdx, 1 ); + pps.setSliceTileIdx( sliceIdx, tileIdx ); + pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); + } + pps.setNumSlicesInTile( firstSliceIdx, numSlicesInTile ); + } + } + pps.setTileIdxDeltaPresentFlag( needTileIdxDelta ); + m_tileIdxDeltaPresentFlag = needTileIdxDelta; + + // check rectangular slice mapping and full picture CTU coverage + pps.initRectSliceMap(); + + // store rectangular slice parameters from temporary PPS structure + m_numSlicesInPic = pps.getNumSlicesInPic(); + m_rectSlices.resize( pps.getNumSlicesInPic() ); + for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) + { + m_rectSlices[sliceIdx].setSliceWidthInTiles( pps.getSliceWidthInTiles(sliceIdx) ); + m_rectSlices[sliceIdx].setSliceHeightInTiles( pps.getSliceHeightInTiles(sliceIdx) ); + m_rectSlices[sliceIdx].setNumSlicesInTile( pps.getNumSlicesInTile(sliceIdx) ); + m_rectSlices[sliceIdx].setSliceHeightInCtu( pps.getSliceHeightInCtu(sliceIdx) ); + m_rectSlices[sliceIdx].setTileIdx( pps.getSliceTileIdx(sliceIdx) ); + } + } + // raster-scan slices + else + { + uint32_t listIdx = 0; + uint32_t remTiles = pps.getNumTiles(); + + // set default slice size if not provided + if( m_rasterSliceSize.size() == 0 ) + { + m_rasterSliceSize.push_back( remTiles ); + } + + // set raster slice sizes + while( remTiles > 0 ) + { + // truncate if size exceeds number of remaining tiles + if( listIdx < m_rasterSliceSize.size() ) + { + m_rasterSliceSize[listIdx] = std::min( remTiles, m_rasterSliceSize[listIdx] ); + remTiles -= m_rasterSliceSize[listIdx]; + } + // replicate last size uniformly as needed to cover the remainder of the picture + else + { + m_rasterSliceSize.push_back( std::min( remTiles, m_rasterSliceSize.back() ) ); + remTiles -= m_rasterSliceSize.back(); + } + listIdx++; + } + // shrink list if too many sizes were provided + m_rasterSliceSize.resize( listIdx ); + + m_numSlicesInPic = (uint32_t)m_rasterSliceSize.size(); + xConfirmPara(m_rasterSliceSize.size() > getMaxSlicesByLevel( m_level ), "Number of raster-scan slices exceeds maximum number allowed according to specified level"); + } + } + else + { + m_numTileCols = 1; + m_numTileRows = 1; + m_numSlicesInPic = 1; + } +#else for (int i=0; i<MAX_TILES; i++) { @@ -3327,11 +3759,20 @@ bool EncAppCfg::xCheckParameter() // ToDo: check that brick dimensions don't exceed tile dimensions } } +#endif +#if JVET_P1004_REMOVE_BRICKS + if ((m_MCTSEncConstraint) && (!m_disableLFCrossTileBoundaryFlag)) +#else if ((m_MCTSEncConstraint) && (m_bLFCrossTileBoundaryFlag)) +#endif { printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling filtering across tile boundaries!\n"); +#if JVET_P1004_REMOVE_BRICKS + m_disableLFCrossTileBoundaryFlag = true; +#else m_bLFCrossTileBoundaryFlag = false; +#endif } if ((m_MCTSEncConstraint) && (m_TMVPModeId)) { @@ -3715,12 +4156,17 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "ChromaTS:%d ", m_useChromaTS); #endif msg( VERBOSE, "BDPCM:%d ", m_useBDPCM ); +#if JVET_P1004_REMOVE_BRICKS + msg( VERBOSE, "Tiles: %dx%d ", m_numTileCols, m_numTileRows ); + msg( VERBOSE, "Slices: %d ", m_numSlicesInPic); +#else msg( VERBOSE, "Slice: M=%d ", int(m_sliceMode)); if (m_sliceMode!=NO_SLICES) { msg( VERBOSE, "A=%d ", m_sliceArgument); } msg( VERBOSE, "Tiles:%dx%d ", m_numTileColumnsMinus1 + 1, m_numTileRowsMinus1 + 1 ); +#endif msg( VERBOSE, "MCTS:%d ", m_MCTSEncConstraint ); msg( VERBOSE, "SAO:%d ", (m_bUseSAO)?(1):(0)); msg( VERBOSE, "ALF:%d ", m_alf ? 1 : 0 ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index c6e9d8e9c..2c79f19fe 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -200,8 +200,10 @@ protected: RPLEntry m_RPLList1[MAX_GOP]; ///< the RPL entries from the config file bool m_idrRefParamList; ///< indicates if reference picture list syntax elements are present in slice headers of IDR pictures GOPEntry m_GOPList[MAX_GOP]; ///< the coding structure entries from the config file +#if !JVET_P1004_REMOVE_BRICKS BrickSplit m_brickSplits[MAX_TILES]; BrickSplitMap m_brickSplitMap; +#endif int m_numReorderPics[MAX_TLAYER]; ///< total number of reorder pictures int m_maxDecPicBuffering[MAX_TLAYER]; ///< total number of pictures in the decoded picture buffer bool m_crossComponentPredictionEnabledFlag; ///< flag enabling the use of cross-component prediction @@ -435,6 +437,23 @@ protected: bool m_useFastDecisionForMerge; ///< flag for using Fast Decision Merge RD-Cost bool m_bUseCbfFastMode; ///< flag for using Cbf Fast PU Mode Decision bool m_useEarlySkipDetection; ///< flag for using Early SKIP Detection +#if JVET_P1004_REMOVE_BRICKS + bool m_picPartitionFlag; ///< enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + std::vector<uint32_t> m_tileColumnWidth; ///< tile column widths in units of CTUs (last column width will be repeated uniformly to cover any remaining picture width) + std::vector<uint32_t> m_tileRowHeight; ///< tile row heights in units of CTUs (last row height will be repeated uniformly to cover any remaining picture height) + bool m_rasterSliceFlag; ///< indicates if using raster-scan or rectangular slices (0: rectangular, 1: raster-scan) + std::vector<uint32_t> m_rectSlicePos; ///< rectangular slice positions (pairs of top-left CTU address followed by bottom-right CTU address) + int m_rectSliceFixedWidth; ///< fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead) + int m_rectSliceFixedHeight; ///< fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead) + std::vector<uint32_t> m_rasterSliceSize; ///< raster-scan slice sizes in units of tiles (last size will be repeated uniformly to cover any remaining tiles in the picture) + bool m_disableLFCrossTileBoundaryFlag; ///< 0: filter across tile boundaries 1: do not filter across tile boundaries + bool m_disableLFCrossSliceBoundaryFlag; ///< 0: filter across slice boundaries 1: do not filter across slice boundaries + uint32_t m_numSlicesInPic; ///< derived number of rectangular slices in the picture (raster-scan slice specified at slice level) + bool m_tileIdxDeltaPresentFlag; ///< derived tile index delta present flag + std::vector<RectSlice> m_rectSlices; ///< derived list of rectangular slice signalling parameters + uint32_t m_numTileCols; ///< derived number of tile columns + uint32_t m_numTileRows; ///< derived number of tile rows +#else SliceConstraint m_sliceMode; int m_sliceArgument; ///< argument according to selected slice mode @@ -448,8 +467,10 @@ protected: int m_uniformTileRowHeightMinus1; std::vector<int> m_tileColumnWidth; std::vector<int> m_tileRowHeight; +#endif bool m_entropyCodingSyncEnabledFlag; +#if !JVET_P1004_REMOVE_BRICKS bool m_rectSliceFlag; int m_numSlicesInPicMinus1; std::vector<int> m_topLeftBrickIdx; @@ -458,6 +479,7 @@ protected: bool m_signalledSliceIdFlag; int m_signalledSliceIdLengthMinus1; std::vector<int> m_sliceId; +#endif bool m_bFastUDIUseMPMEnabled; bool m_bFastMEForGenBLowDelayEnabled; diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index a082870b7..e70d54002 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -103,7 +103,11 @@ void AdaptiveLoopFilter::getAlfBoundary( const CodingStructure& cs, int posX, in topBry = posY; } +#if JVET_P1004_REMOVE_BRICKS + if ( !pps.getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile( *currCtu, *prevCtu ) ) +#else if ( !pps.getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameBrick( *currCtu, *prevCtu ) ) +#endif { topBry = posY; } @@ -124,7 +128,11 @@ void AdaptiveLoopFilter::getAlfBoundary( const CodingStructure& cs, int posX, in botBry = posY + ctuSize; } +#if JVET_P1004_REMOVE_BRICKS + if ( !pps.getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile( *currCtu, *nextCtu ) ) +#else if ( !pps.getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameBrick( *currCtu, *nextCtu ) ) +#endif { botBry = posY + ctuSize; } @@ -145,7 +153,11 @@ void AdaptiveLoopFilter::getAlfBoundary( const CodingStructure& cs, int posX, in leftBry = posX; } +#if JVET_P1004_REMOVE_BRICKS + if ( !pps.getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile( *currCtu, *prevCtu ) ) +#else if ( !pps.getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameBrick( *currCtu, *prevCtu ) ) +#endif { leftBry = posX; } @@ -166,7 +178,11 @@ void AdaptiveLoopFilter::getAlfBoundary( const CodingStructure& cs, int posX, in rightBry = posX + ctuSize; } +#if JVET_P1004_REMOVE_BRICKS + if ( !pps.getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile( *currCtu, *nextCtu ) ) +#else if ( !pps.getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameBrick( *currCtu, *nextCtu ) ) +#endif { rightBry = posX + ctuSize; } @@ -381,7 +397,12 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const int xPos, const int const Position prevCtuPos(xPos, yPos - ctuSize); const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA); #if JVET_P1006_PICTURE_HEADER +#if JVET_P1004_REMOVE_BRICKS + if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu))) +#else if (!pps->getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) +#endif #else if ((!slice.getLFCrossSliceBoundaryFlag() || !pps->getLoopFilterAcrossBricksEnabledFlag()) && !CU::isSameSlice(*currCtu, *prevCtu)) #endif @@ -396,7 +417,12 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const int xPos, const int const Position nextCtuPos(xPos, yPos + ctuSize); const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA); #if JVET_P1006_PICTURE_HEADER +#if JVET_P1004_REMOVE_BRICKS + if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu))) +#else if (!pps->getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) +#endif #else if ((!slice.getLFCrossSliceBoundaryFlag() || !pps->getLoopFilterAcrossBricksEnabledFlag()) && !CU::isSameSlice(*currCtu, *nextCtu)) #endif @@ -411,7 +437,12 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const int xPos, const int const Position prevCtuPos(xPos - ctuSize, yPos); const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA); #if JVET_P1006_PICTURE_HEADER +#if JVET_P1004_REMOVE_BRICKS + if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu))) +#else if (!pps->getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) +#endif #else if ((!slice.getLFCrossSliceBoundaryFlag() || !pps->getLoopFilterAcrossBricksEnabledFlag()) && !CU::isSameSlice(*currCtu, *prevCtu)) #endif @@ -426,7 +457,12 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const int xPos, const int const Position nextCtuPos(xPos + ctuSize, yPos); const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA); #if JVET_P1006_PICTURE_HEADER +#if JVET_P1004_REMOVE_BRICKS + if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu))) +#else if (!pps->getLoopFilterAcrossBricksEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) +#endif #else if ((!slice.getLFCrossSliceBoundaryFlag() || !pps->getLoopFilterAcrossBricksEnabledFlag()) && !CU::isSameSlice(*currCtu, *nextCtu)) #endif @@ -528,11 +564,13 @@ const int AdaptiveLoopFilter::m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { +#if !JVET_P1004_REMOVE_BRICKS if (!cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y) && !cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) && !cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr)) { return; } +#endif // set clipping range m_clpRngs = cs.slice->getClpRngs(); @@ -543,8 +581,13 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) m_ctuEnableFlag[compIdx] = cs.picture->getAlfCtuEnableFlag( compIdx ); m_ctuAlternative[compIdx] = cs.picture->getAlfCtuAlternativeData( compIdx ); } +#if JVET_P1004_REMOVE_BRICKS + short* alfCtuFilterIndex = nullptr; + uint32_t lastSliceIdx = 0xFFFFFFFF; +#else reconstructCoeffAPSs(cs, true, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr), false); short* alfCtuFilterIndex = cs.slice->getPic()->getAlfCtbFilterIndex(); +#endif PelUnitBuf recYuv = cs.getRecoBuf(); m_tempBuf.copyFrom( recYuv ); @@ -568,6 +611,27 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { for( int xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth ) { +#if JVET_P1004_REMOVE_BRICKS + // get first CU in CTU + const CodingUnit *cu = cs.getCU( Position(xPos, yPos), CHANNEL_TYPE_LUMA ); + + // skip this CTU if ALF is disabled + if (!cu->slice->getTileGroupAlfEnabledFlag(COMPONENT_Y) && !cu->slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) && !cu->slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr)) + { + ctuIdx++; + continue; + } + + // reload ALF APS each time the slice changes during raster scan filtering + if(ctuIdx == 0 || lastSliceIdx != cu->slice->getSliceID() || alfCtuFilterIndex==nullptr) + { + cs.slice = cu->slice; + reconstructCoeffAPSs(cs, true, cu->slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cu->slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr), false); + alfCtuFilterIndex = cu->slice->getPic()->getAlfCtbFilterIndex(); + } + lastSliceIdx = cu->slice->getSliceID(); + +#endif const int width = ( xPos + pcv.maxCUWidth > pcv.lumaWidth ) ? ( pcv.lumaWidth - xPos ) : pcv.maxCUWidth; const int height = ( yPos + pcv.maxCUHeight > pcv.lumaHeight ) ? ( pcv.lumaHeight - yPos ) : pcv.maxCUHeight; bool ctuEnableFlag = m_ctuEnableFlag[COMPONENT_Y][ctuIdx]; diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 34ff09077..163b72e96 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -145,8 +145,10 @@ static const int MAX_NUM_REF = 16; ///< max. static const int MAX_QP = 63; static const int NOT_VALID = -1; +#if !JVET_P1004_REMOVE_BRICKS static const int MAX_TILES = 128; ///< max. number of tiles for which a brick configuration can be read static const int MAX_NUM_BRICKS_PER_TILE = 8; ///< max. number brick per tile, for which a configuration can be read +#endif static const int AMVP_MAX_NUM_CANDS = 2; ///< AMVP: advanced motion vector prediction - max number of final candidates static const int AMVP_MAX_NUM_CANDS_MEM = 3; ///< AMVP: advanced motion vector prediction - max number of candidates @@ -214,6 +216,12 @@ static const int MAX_NUM_APS = 32; //Curren static const int NUM_APS_TYPE_LEN = 3; //Currently APS Type has 3 bits static const int MAX_NUM_APS_TYPE = 8; //Currently APS Type has 3 bits so the max type is 8 +#if JVET_P1004_REMOVE_BRICKS +static const int MAX_TILE_COLS = 20; ///< Maximum number of tile columns +static const int MAX_TILE_ROWS = 22; ///< Maximum number of tile rows +static const int MAX_TILES = MAX_TILE_COLS * MAX_TILE_ROWS; ///< Maximum number of tiles +static const int MAX_SLICES = 600; ///< Maximum number of slices per picture +#endif static const int MLS_GRP_NUM = 1024; ///< Max number of coefficient groups, max(16, 256) static const int MLS_CG_SIZE = 4; ///< Coefficient group size of 4x4; = MLS_CG_LOG2_WIDTH + MLS_CG_LOG2_HEIGHT diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index f1cad5688..bbd174e5f 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -141,7 +141,11 @@ unsigned DeriveCtx::CtxModeConsFlag( const CodingStructure& cs, Partitioner& par assert( partitioner.chType == CHANNEL_TYPE_LUMA ); const Position pos = partitioner.currArea().blocks[partitioner.chType]; const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const unsigned curTileIdx = cs.pps->getTileIdx( partitioner.currArea().lumaPos() ); +#else const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( partitioner.currArea().lumaPos() ); +#endif const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), pos, curSliceIdx, curTileIdx, partitioner.chType ); const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), pos, curSliceIdx, curTileIdx, partitioner.chType ); @@ -155,7 +159,11 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u { const Position pos = partitioner.currArea().blocks[partitioner.chType]; const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const unsigned curTileIdx = cs.pps->getTileIdx( partitioner.currArea().lumaPos() ); +#else const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( partitioner.currArea().lumaPos() ); +#endif // get left depth const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), pos, curSliceIdx, curTileIdx, partitioner.chType ); diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index ed8e3da57..1914b2da6 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -890,8 +890,13 @@ void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const Comp } const Position posLT = area; +#if JVET_P1004_REMOVE_BRICKS + bool isLeftAvail = (cs.getCURestricted(posLT.offset(-1, 0), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA); + bool isAboveAvail = (cs.getCURestricted(posLT.offset(0, -1), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA); +#else bool isLeftAvail = cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA); bool isAboveAvail = cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA); +#endif // ----- Step 1: unfiltered reference samples ----- if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y) { @@ -1290,7 +1295,11 @@ bool isAboveLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const return false; } +#if JVET_P1004_REMOVE_BRICKS + return (cs.getCURestricted(refPos, cu, chType) != NULL); +#else return true; +#endif } int isAboveAvailable(const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *bValidFlags) @@ -1310,8 +1319,14 @@ int isAboveAvailable(const CodingUnit &cu, const ChannelType &chType, const Posi break; } +#if JVET_P1004_REMOVE_BRICKS + const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL); + numIntra += valid ? 1 : 0; + *validFlags = valid; +#else ++numIntra; *validFlags = true; +#endif validFlags++; } @@ -1336,8 +1351,14 @@ int isLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const Posit break; } +#if JVET_P1004_REMOVE_BRICKS + const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL); + numIntra += valid ? 1 : 0; + *validFlags = valid; +#else ++numIntra; *validFlags = true; +#endif validFlags--; } @@ -1362,8 +1383,14 @@ int isAboveRightAvailable(const CodingUnit &cu, const ChannelType &chType, const break; } +#if JVET_P1004_REMOVE_BRICKS + const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL); + numIntra += valid ? 1 : 0; + *validFlags = valid; +#else ++numIntra; *validFlags = true; +#endif validFlags++; } @@ -1388,8 +1415,14 @@ int isBelowLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const break; } +#if JVET_P1004_REMOVE_BRICKS + const bool valid = (cs.getCURestricted(refPos, cu, chType) != NULL); + numIntra += valid ? 1 : 0; + *validFlags = valid; +#else ++numIntra; *validFlags = true; +#endif validFlags--; } diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index c75c3dff8..2d21dfd4b 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -700,6 +700,15 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu ) const Position& pos = cu.blocks[cu.chType].pos(); m_stLFCUParam.internalEdge = true; +#if JVET_P1004_REMOVE_BRICKS +#if JVET_P1006_PICTURE_HEADER + m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); + m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); +#else + m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); + m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); +#endif +#else #if JVET_P1006_PICTURE_HEADER m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); @@ -707,6 +716,7 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu ) m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); #endif +#endif } unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const @@ -972,10 +982,18 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg // Derive neighboring PU index if (edgeDir == EDGE_VER) { +#if JVET_P1004_REMOVE_BRICKS +#if JVET_P1006_PICTURE_HEADER + if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#else + if (!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#endif +#else #if JVET_P1006_PICTURE_HEADER if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag())) #else if (!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag())) +#endif #endif { m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0; @@ -984,10 +1002,18 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg } else // (iDir == EDGE_HOR) { +#if JVET_P1004_REMOVE_BRICKS +#if JVET_P1006_PICTURE_HEADER + if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#else + if (!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#endif +#else #if JVET_P1006_PICTURE_HEADER if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag())) #else if (!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag())) +#endif #endif { m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0; @@ -1255,18 +1281,34 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed if (edgeDir == EDGE_VER) { +#if JVET_P1004_REMOVE_BRICKS +#if JVET_P1006_PICTURE_HEADER + CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#else + CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#endif +#else #if JVET_P1006_PICTURE_HEADER CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); #else CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); +#endif #endif } else // (iDir == EDGE_HOR) { +#if JVET_P1004_REMOVE_BRICKS +#if JVET_P1006_PICTURE_HEADER + CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#else + CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#endif +#else #if JVET_P1006_PICTURE_HEADER CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); #else CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); +#endif #endif } diff --git a/source/Lib/CommonLib/MCTS.cpp b/source/Lib/CommonLib/MCTS.cpp index a8eb00149..0e5855bf4 100644 --- a/source/Lib/CommonLib/MCTS.cpp +++ b/source/Lib/CommonLib/MCTS.cpp @@ -90,6 +90,25 @@ void MCTSHelper::clipMvToArea( Mv& rcMv, const Area& block, const Area& clipArea Area MCTSHelper::getTileArea( const CodingStructure* cs, const int ctuAddr ) { +#if JVET_P1004_REMOVE_BRICKS + const PPS *pps = cs->pps; + const int maxCUWidth = cs->pcv->maxCUWidth; + const int maxCUHeight = cs->pcv->maxCUHeight; + + const uint32_t tileIdx = pps->getTileIdx( (uint32_t)ctuAddr ); + const uint32_t tileX = tileIdx % pps->getNumTileColumns(); + const uint32_t tileY = tileIdx / pps->getNumTileColumns(); + + const int tileWidthtInCtus = pps->getTileColumnWidth( tileX ); + const int tileHeightInCtus = pps->getTileRowHeight ( tileY ); + const int tileXPosInCtus = pps->getTileColumnBd( tileX ); + const int tileYPosInCtus = pps->getTileRowBd( tileY ); + + const int tileLeftTopPelPosX = maxCUWidth * tileXPosInCtus; + const int tileLeftTopPelPosY = maxCUHeight * tileYPosInCtus; + const int tileRightBottomPelPosX = std::min<int>( ( ( tileWidthtInCtus + tileXPosInCtus ) * maxCUWidth ), (int)cs->picture->lwidth() ) - 1; + const int tileRightBottomPelPosY = std::min<int>( ( ( tileHeightInCtus + tileYPosInCtus ) * maxCUHeight ), (int)cs->picture->lheight() ) - 1; +#else const BrickMap* tileMap = cs->picture->brickMap; const int tileIdx = tileMap->getBrickIdxRsMap( ctuAddr ); const Brick& currentTile = tileMap->bricks[tileIdx]; @@ -109,6 +128,7 @@ Area MCTSHelper::getTileArea( const CodingStructure* cs, const int ctuAddr ) const int tileLeftTopPelPosY = maxCUHeight * tileYPosInCtus; const int tileRightBottomPelPosX = std::min<int>( ( ( tileWidthtInCtus + tileXPosInCtus ) * maxCUWidth ), (int)cs->picture->lwidth() ) - 1; const int tileRightBottomPelPosY = std::min<int>( ( ( tileHeightInCtus + tileYPosInCtus ) * maxCUHeight ), (int)cs->picture->lheight() ) - 1; +#endif return Area( tileLeftTopPelPosX, tileLeftTopPelPosY, tileRightBottomPelPosX - tileLeftTopPelPosX + 1, tileRightBottomPelPosY - tileLeftTopPelPosY + 1 ); } diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 277d192b4..4be2aea8f 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -438,6 +438,7 @@ bool Scheduler::getNextCtu( Position& pos, int ctuLine, int offset) // --------------------------------------------------------------------------- +#if !JVET_P1004_REMOVE_BRICKS Brick::Brick() : m_widthInCtus (0) , m_heightInCtus (0) @@ -781,10 +782,13 @@ uint32_t BrickMap::getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool add return subStrm; } +#endif Picture::Picture() { +#if !JVET_P1004_REMOVE_BRICKS brickMap = nullptr; +#endif cs = nullptr; m_bIsBorderExtended = false; usedByCurr = false; @@ -867,12 +871,14 @@ void Picture::destroy() } SEIs.clear(); +#if !JVET_P1004_REMOVE_BRICKS if ( brickMap ) { brickMap->destroy(); delete brickMap; brickMap = nullptr; } +#endif if (m_spliceIdx) { delete[] m_spliceIdx; @@ -967,12 +973,14 @@ void Picture::finalInit( const SPS& sps, const PPS& pps, APS** alfApss, APS* lmc SEIs.clear(); clearSliceBuffer(); +#if !JVET_P1004_REMOVE_BRICKS if( brickMap ) { brickMap->destroy(); delete brickMap; brickMap = nullptr; } +#endif const ChromaFormat chromaFormatIDC = sps.getChromaFormatIdc(); const int iWidth = pps.getPicWidthInLumaSamples(); @@ -1003,8 +1011,10 @@ void Picture::finalInit( const SPS& sps, const PPS& pps, APS** alfApss, APS* lmc cs->pcv = pps.pcv; m_conformanceWindow = pps.getConformanceWindow(); +#if !JVET_P1004_REMOVE_BRICKS brickMap = new BrickMap; brickMap->create( sps, pps ); +#endif if (m_spliceIdx == NULL) { m_ctuNums = cs->pcv->sizeInCtus; diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 720940148..9645be4a9 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -116,6 +116,7 @@ class AQpLayer; typedef std::list<SEI*> SEIMessages; +#if !JVET_P1004_REMOVE_BRICKS class Brick { private: @@ -183,6 +184,7 @@ struct BrickMap void initBrickMap( const SPS& sps, const PPS& pps ); void initCtuBsRsAddrMap(); }; +#endif #if ENABLE_SPLIT_PARALLELISM #define M_BUFS(JID,PID) m_bufs[JID][PID] @@ -322,7 +324,9 @@ public: Slice *swapSliceObject(Slice * p, uint32_t i); void clearSliceBuffer(); +#if !JVET_P1004_REMOVE_BRICKS BrickMap* brickMap; +#endif MCTSInfo mctsInfo; std::vector<AQpLayer*> aqlayer; diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index 9886fc514..fcb7966dc 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -115,7 +115,11 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int const bool useJQP = ( abs(TU::getICTMode(tu)) == 2 ); chromaQpOffset += tu.cs->pps->getQpOffset ( useJQP ? JOINT_CbCr : compID ); +#if JVET_P1004_REMOVE_BRICKS + chromaQpOffset += tu.cu->slice->getSliceChromaQpDelta( useJQP ? JOINT_CbCr : compID ); +#else chromaQpOffset += tu.cs->slice->getSliceChromaQpDelta( useJQP ? JOINT_CbCr : compID ); +#endif chromaQpOffset += tu.cs->pps->getChromaQpOffsetListEntry( tu.cu->chromaQpAdj ).u.offset[int( useJQP ? JOINT_CbCr : compID ) - 1]; } diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index eb5a89edc..0abfb4994 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -839,7 +839,11 @@ void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& #endif // check cross tile flags +#if JVET_P1004_REMOVE_BRICKS + const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag(); +#else const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag(); +#endif if (!isLoopFilterAcrossTilePPS) { isLeftAvail = (!isLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuLeft); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 9d7bb24c8..d7b09f030 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -80,6 +80,9 @@ Slice::Slice() , m_pcSPS ( NULL ) , m_pcPPS ( NULL ) , m_pcPic ( NULL ) +#if JVET_P1006_PICTURE_HEADER +, m_pcPicHeader ( NULL ) +#endif , m_colFromL0Flag ( true ) #if !JVET_P1006_PICTURE_HEADER , m_noOutputPriorPicsFlag ( false ) @@ -97,21 +100,28 @@ Slice::Slice() #endif , m_uiTLayer ( 0 ) , m_bTLayerSwitchingFlag ( false ) +#if !JVET_P1004_REMOVE_BRICKS , m_sliceMode ( NO_SLICES ) , m_sliceArgument ( 0 ) , m_sliceCurStartCtuTsAddr ( 0 ) , m_sliceCurEndCtuTsAddr ( 0 ) +#endif , m_independentSliceIdx ( 0 ) , m_nextSlice ( false ) , m_sliceBits ( 0 ) , m_bFinalized ( false ) +#if !JVET_P1004_REMOVE_BRICKS , m_sliceCurStartBrickIdx ( 0 ) , m_sliceCurEndBrickIdx ( 0 ) , m_sliceNumBricks ( 0 ) , m_sliceIdx ( 0 ) +#endif , m_bTestWeightPred ( false ) , m_bTestWeightBiPred ( false ) , m_substreamSizes ( ) +#if JVET_P1004_REMOVE_BRICKS +, m_numEntryPoints ( 0 ) +#endif , m_cabacInitFlag ( false ) #if !JVET_P1006_PICTURE_HEADER , m_jointCbCrSignFlag ( false ) @@ -179,10 +189,17 @@ Slice::Slice() } memset(m_alfApss, 0, sizeof(m_alfApss)); +#if JVET_P1004_REMOVE_BRICKS + + m_sliceMap.initSliceMap(); +#endif } Slice::~Slice() { +#if JVET_P1004_REMOVE_BRICKS + m_sliceMap.initSliceMap(); +#endif } @@ -277,6 +294,27 @@ void Slice::inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SP setTileGroupApsIdChroma(picHeader->getAlfApsIdChroma()); } +#endif +#if JVET_P1004_REMOVE_BRICKS +void Slice::setNumEntryPoints( const PPS *pps ) +{ + uint32_t ctuAddr, ctuX, ctuY; + m_numEntryPoints = 0; + + // count the number of CTUs that align with either the start of a tile, or with an entropy coding sync point + // ignore the first CTU since it doesn't count as an entry point + for( uint32_t i = 1; i < m_sliceMap.getNumCtuInSlice(); i++ ) + { + ctuAddr = m_sliceMap.getCtuAddrInSlice( i ); + ctuX = ( ctuAddr % pps->getPicWidthInCtu() ); + ctuY = ( ctuAddr / pps->getPicWidthInCtu() ); + if( pps->ctuIsTileColBd( ctuX ) && (pps->ctuIsTileRowBd( ctuY ) || pps->getEntropyCodingSyncEnabledFlag() ) ) + { + m_numEntryPoints++; + } + } +} + #endif void Slice::setDefaultClpRng( const SPS& sps ) { @@ -815,6 +853,9 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) if( cpyAlmostAll ) m_pcPic = pSrc->m_pcPic; +#if JVET_P1006_PICTURE_HEADER + m_pcPicHeader = pSrc->m_pcPicHeader; +#endif m_colFromL0Flag = pSrc->m_colFromL0Flag; m_colRefIdx = pSrc->m_colRefIdx; @@ -834,10 +875,14 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) m_uiTLayer = pSrc->m_uiTLayer; m_bTLayerSwitchingFlag = pSrc->m_bTLayerSwitchingFlag; +#if JVET_P1004_REMOVE_BRICKS + m_sliceMap = pSrc->m_sliceMap; +#else m_sliceMode = pSrc->m_sliceMode; m_sliceArgument = pSrc->m_sliceArgument; m_sliceCurStartCtuTsAddr = pSrc->m_sliceCurStartCtuTsAddr; m_sliceCurEndCtuTsAddr = pSrc->m_sliceCurEndCtuTsAddr; +#endif m_independentSliceIdx = pSrc->m_independentSliceIdx; m_nextSlice = pSrc->m_nextSlice; m_clpRngs = pSrc->m_clpRngs; @@ -2202,6 +2247,35 @@ void ChromaQpMappingTable::derivedChromaQPMappingTables() } } +#if JVET_P1004_REMOVE_BRICKS +SliceMap::SliceMap() +: m_sliceID (0) +, m_numTilesInSlice (0) +, m_numCtuInSlice (0) +{ + m_ctuAddrInSlice.clear(); +} + +SliceMap::~SliceMap() +{ + m_numCtuInSlice = 0; + m_ctuAddrInSlice.clear(); +} + +RectSlice::RectSlice() +: m_tileIdx (0) +, m_sliceWidthInTiles (0) +, m_sliceHeightInTiles (0) +, m_numSlicesInTile (0) +, m_sliceHeightInCtu (0) +{ +} + +RectSlice::~RectSlice() +{ +} + +#endif PPSRExt::PPSRExt() : m_crossComponentPredictionEnabledFlag(false) // m_log2SaoOffsetScale initialized below @@ -2236,9 +2310,24 @@ PPS::PPS() , m_subPicIdSignallingPresentFlag (0) , m_subPicIdLen (16) #endif +#if JVET_P1004_REMOVE_BRICKS +, m_noPicPartitionFlag (1) +, m_log2CtuSize (0) +, m_ctuSize (0) +, m_picWidthInCtu (0) +, m_picHeightInCtu (0) +, m_numTileCols (1) +, m_numTileRows (1) +, m_rectSliceFlag (1) +, m_numSlicesInPic (1) +, m_tileIdxDeltaPresentFlag (0) +, m_loopFilterAcrossTilesEnabledFlag (1) +, m_loopFilterAcrossSlicesEnabledFlag(0) +#endif , m_TransquantBypassEnabledFlag (false) , m_log2MaxTransformSkipBlockSize (2) , m_entropyCodingSyncEnabledFlag (false) +#if !JVET_P1004_REMOVE_BRICKS , m_loopFilterAcrossBricksEnabledFlag (true) , m_uniformTileSpacingFlag (false) , m_numTileColumnsMinus1 (0) @@ -2254,6 +2343,7 @@ PPS::PPS() , m_numBricksInPic (1) , m_signalledSliceIdFlag (false) ,m_signalledSliceIdLengthMinus1 (0) +#endif , m_constantSliceHeaderParamsEnabledFlag (false) , m_PPSDepQuantEnabledIdc (0) , m_PPSRefPicListSPSIdc0 (0) @@ -2273,7 +2363,9 @@ PPS::PPS() , m_pictureHeaderExtensionPresentFlag(0) #endif , m_sliceHeaderExtensionPresentFlag (false) +#if !JVET_P1004_REMOVE_BRICKS , m_loopFilterAcrossSlicesEnabledFlag(false) +#endif , m_listsModificationPresentFlag (0) #if !JVET_P1006_PICTURE_HEADER , m_loopFilterAcrossVirtualBoundariesDisabledFlag(false) @@ -2292,13 +2384,275 @@ PPS::PPS() ::memset(m_virtualBoundariesPosX, 0, sizeof(m_virtualBoundariesPosX)); ::memset(m_virtualBoundariesPosY, 0, sizeof(m_virtualBoundariesPosY)); #endif +#if JVET_P1004_REMOVE_BRICKS + m_tileColWidth.clear(); + m_tileRowHeight.clear(); + m_tileColBd.clear(); + m_tileRowBd.clear(); + m_ctuToTileCol.clear(); + m_ctuToTileRow.clear(); + m_rectSlices.clear(); + m_sliceMap.clear(); +#endif } PPS::~PPS() { +#if JVET_P1004_REMOVE_BRICKS + m_tileColWidth.clear(); + m_tileRowHeight.clear(); + m_tileColBd.clear(); + m_tileRowBd.clear(); + m_ctuToTileCol.clear(); + m_ctuToTileRow.clear(); + m_rectSlices.clear(); + m_sliceMap.clear(); + +#endif delete pcv; } +#if JVET_P1004_REMOVE_BRICKS +/** + - reset tile and slice parameters and lists + */ +void PPS::resetTileSliceInfo() +{ + m_numExpTileCols = 0; + m_numExpTileRows = 0; + m_numTileCols = 0; + m_numTileRows = 0; + m_numSlicesInPic = 0; + m_tileColWidth.clear(); + m_tileRowHeight.clear(); + m_tileColBd.clear(); + m_tileRowBd.clear(); + m_ctuToTileCol.clear(); + m_ctuToTileRow.clear(); + m_rectSlices.clear(); + m_sliceMap.clear(); +} + +/** + - initialize tile row/column sizes and boundaries + */ +void PPS::initTiles() +{ + int colIdx, rowIdx; + int ctuX, ctuY; + + // check explicit tile column sizes + uint32_t remainingWidthInCtu = m_picWidthInCtu; + for( colIdx = 0; colIdx < m_numExpTileCols; colIdx++ ) + { + CHECK(m_tileColWidth[colIdx] > remainingWidthInCtu, "Tile column width exceeds picture width"); + remainingWidthInCtu -= m_tileColWidth[colIdx]; + } + + // divide remaining picture width into uniform tile columns + uint32_t uniformTileColWidth = m_tileColWidth[colIdx-1]; + while( remainingWidthInCtu > 0 ) + { + CHECK(colIdx >= MAX_TILE_COLS, "Number of tile columns exceeds valid range"); + uniformTileColWidth = std::min(remainingWidthInCtu, uniformTileColWidth); + m_tileColWidth.push_back( uniformTileColWidth ); + remainingWidthInCtu -= uniformTileColWidth; + colIdx++; + } + m_numTileCols = colIdx; + + // check explicit tile row sizes + uint32_t remainingHeightInCtu = m_picHeightInCtu; + for( rowIdx = 0; rowIdx < m_numExpTileRows; rowIdx++ ) + { + CHECK(m_tileRowHeight[rowIdx] > remainingHeightInCtu, "Tile row height exceeds picture height"); + remainingHeightInCtu -= m_tileRowHeight[rowIdx]; + } + + // divide remaining picture height into uniform tile rows + uint32_t uniformTileRowHeight = m_tileRowHeight[rowIdx - 1]; + while( remainingHeightInCtu > 0 ) + { + CHECK(rowIdx >= MAX_TILE_ROWS, "Number of tile rows exceeds valid range"); + uniformTileRowHeight = std::min(remainingHeightInCtu, uniformTileRowHeight); + m_tileRowHeight.push_back( uniformTileRowHeight ); + remainingHeightInCtu -= uniformTileRowHeight; + rowIdx++; + } + m_numTileRows = rowIdx; + + // set left column bounaries + m_tileColBd.push_back( 0 ); + for( colIdx = 0; colIdx < m_numTileCols; colIdx++ ) + { + m_tileColBd.push_back( m_tileColBd[ colIdx ] + m_tileColWidth[ colIdx ] ); + } + + // set top row bounaries + m_tileRowBd.push_back( 0 ); + for( rowIdx = 0; rowIdx < m_numTileRows; rowIdx++ ) + { + m_tileRowBd.push_back( m_tileRowBd[ rowIdx ] + m_tileRowHeight[ rowIdx ] ); + } + + // set mapping between horizontal CTU address and tile column index + colIdx = 0; + for( ctuX = 0; ctuX <= m_picWidthInCtu; ctuX++ ) + { + if( ctuX == m_tileColBd[ colIdx + 1 ] ) + { + colIdx++; + } + m_ctuToTileCol.push_back( colIdx ); + } + + // set mapping between vertical CTU address and tile row index + rowIdx = 0; + for( ctuY = 0; ctuY <= m_picHeightInCtu; ctuY++ ) + { + if( ctuY == m_tileRowBd[ rowIdx + 1 ] ) + { + rowIdx++; + } + m_ctuToTileRow.push_back( rowIdx ); + } +} + +/** + - initialize memory for rectangular slice parameters + */ +void PPS::initRectSlices() +{ + CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); + m_rectSlices.resize(m_numSlicesInPic); +} + +/** + - initialize mapping between rectangular slices and CTUs + */ +void PPS::initRectSliceMap() +{ + uint32_t ctuY; + uint32_t tileX, tileY; + + // allocate new memory for slice list + CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); + m_sliceMap.resize( m_numSlicesInPic ); + + // generate CTU maps for all rectangular slices in picture + for( uint32_t i = 0; i < m_numSlicesInPic; i++ ) + { + m_sliceMap[ i ].initSliceMap(); + + // get position of first tile in slice + tileX = m_rectSlices[ i ].getTileIdx() % m_numTileCols; + tileY = m_rectSlices[ i ].getTileIdx() / m_numTileCols; + + // infer slice size for last slice in picture + if( i == m_numSlicesInPic-1 ) + { + m_rectSlices[ i ].setSliceWidthInTiles ( m_numTileCols - tileX ); + m_rectSlices[ i ].setSliceHeightInTiles( m_numTileRows - tileY ); + m_rectSlices[ i ].setNumSlicesInTile( 1 ); + } + + // set slice index + m_sliceMap[ i ].setSliceID(i); + + // complete tiles within a single slice case + if( m_rectSlices[ i ].getSliceWidthInTiles( ) > 1 || m_rectSlices[ i ].getSliceHeightInTiles( ) > 1) + { + for( uint32_t j = 0; j < m_rectSlices[ i ].getSliceHeightInTiles( ); j++ ) + { + for( uint32_t k = 0; k < m_rectSlices[ i ].getSliceWidthInTiles( ); k++ ) + { + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX + k), getTileColumnBd(tileX + k +1), + getTileRowBd(tileY + j), getTileRowBd(tileY + j +1), m_picWidthInCtu); + } + } + } + // multiple slices within a single tile case + else + { + uint32_t numSlicesInTile = m_rectSlices[ i ].getNumSlicesInTile( ); + + ctuY = getTileRowBd( tileY ); + for( uint32_t j = 0; j < numSlicesInTile-1; j++ ) + { + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), + ctuY, ctuY + m_rectSlices[ i ].getSliceHeightInCtu(), m_picWidthInCtu); + ctuY += m_rectSlices[ i ].getSliceHeightInCtu(); + i++; + m_sliceMap[ i ].setSliceID(i); + } + + // infer slice height for last slice in tile + CHECK( ctuY >= getTileRowBd( tileY + 1 ), "Invalid rectangular slice signalling"); + m_rectSlices[ i ].setSliceHeightInCtu( getTileRowBd( tileY + 1 ) - ctuY ); + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), + ctuY, getTileRowBd( tileY + 1 ), m_picWidthInCtu); + } + } + + // check for valid rectangular slice map + checkSliceMap(); +} + +void PPS::initRasterSliceMap( std::vector<uint32_t> numTilesInSlice ) +{ + uint32_t tileIdx = 0; + setNumSlicesInPic( (uint32_t) numTilesInSlice.size() ); + + // allocate new memory for slice list + CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); + m_sliceMap.resize( m_numSlicesInPic ); + + for( uint32_t sliceIdx = 0; sliceIdx < numTilesInSlice.size(); sliceIdx++ ) + { + m_sliceMap[sliceIdx].initSliceMap(); + m_sliceMap[sliceIdx].setSliceID( tileIdx ); + m_sliceMap[sliceIdx].setNumTilesInSlice( numTilesInSlice[sliceIdx] ); + for( uint32_t idx = 0; idx < numTilesInSlice[sliceIdx]; idx++ ) + { + uint32_t tileX = tileIdx % getNumTileColumns(); + uint32_t tileY = tileIdx / getNumTileColumns(); + CHECK(tileY >= getNumTileRows(), "Number of tiles in slice exceeds the remaining number of tiles in picture"); + + m_sliceMap[sliceIdx].addCtusToSlice(getTileColumnBd(tileX), getTileColumnBd(tileX + 1), + getTileRowBd(tileY), getTileRowBd(tileY + 1), + getPicWidthInCtu()); + tileIdx++; + } + } + + // check for valid raster-scan slice map + checkSliceMap(); +} + +/** + - check if slice map covers the entire picture without skipping or duplicating any CTU positions + */ +void PPS::checkSliceMap() +{ + uint32_t i; + std::vector<uint32_t> ctuList, sliceList; + uint32_t picSizeInCtu = getPicWidthInCtu() * getPicHeightInCtu(); + for( i = 0; i < m_numSlicesInPic; i++ ) + { + sliceList = m_sliceMap[ i ].getCtuAddrList(); + ctuList.insert( ctuList.end(), sliceList.begin(), sliceList.end() ); + } + CHECK( ctuList.size() < picSizeInCtu, "Slice map contains too few CTUs"); + CHECK( ctuList.size() > picSizeInCtu, "Slice map contains too many CTUs"); + std::sort( ctuList.begin(), ctuList.end() ); + for( i = 1; i < ctuList.size(); i++ ) + { + CHECK( ctuList[i] > ctuList[i-1]+1, "CTU missing in slice map"); + CHECK( ctuList[i] == ctuList[i-1], "CTU duplicated in slice map"); + } +} + +#endif APS::APS() : m_APSId(0) , m_temporalId( 0 ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 589b64eb7..71521b3e9 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -633,6 +633,78 @@ struct ChromaQpMappingTable : ChromaQpMappingTableParams void derivedChromaQPMappingTables(); void setParams(const ChromaQpMappingTableParams ¶ms, const int qpBdOffset); }; +#if JVET_P1004_REMOVE_BRICKS + +class SliceMap +{ +private: + uint32_t m_sliceID; //!< slice identifier (slice index for rectangular slices, slice address for raser-scan slices) + uint32_t m_numTilesInSlice; //!< number of tiles in slice (raster-scan slices only) + uint32_t m_numCtuInSlice; //!< number of CTUs in the slice + std::vector<uint32_t> m_ctuAddrInSlice; //!< raster-scan addresses of all the CTUs in the slice + +public: + SliceMap(); + virtual ~SliceMap(); + + void setSliceID( uint32_t u ) { m_sliceID = u; } + uint32_t getSliceID() const { return m_sliceID; } + void setNumTilesInSlice( uint32_t u ) { m_numTilesInSlice = u; } + uint32_t getNumTilesInSlice() const { return m_numTilesInSlice; } + void setNumCtuInSlice( uint32_t u ) { m_numCtuInSlice = u; } + uint32_t getNumCtuInSlice() const { return m_numCtuInSlice; } + std::vector<uint32_t> getCtuAddrList( ) const { return m_ctuAddrInSlice; } + uint32_t getCtuAddrInSlice( int idx ) const { CHECK(idx >= m_ctuAddrInSlice.size(), "CTU index exceeds number of CTUs in slice."); return m_ctuAddrInSlice[idx]; } + + void initSliceMap() + { + m_sliceID = 0; + m_numTilesInSlice = 0; + m_numCtuInSlice = 0; + m_ctuAddrInSlice.clear(); + } + + void addCtusToSlice( uint32_t startX, uint32_t stopX, uint32_t startY, uint32_t stopY, uint32_t picWidthInCtbsY ) + { + CHECK( startX >= stopX || startY >= stopY, "Invalid slice definition"); + for( uint32_t ctbY = startY; ctbY < stopY; ctbY++ ) + { + for( uint32_t ctbX = startX; ctbX < stopX; ctbX++ ) + { + m_ctuAddrInSlice.push_back( ctbY * picWidthInCtbsY + ctbX ); + m_numCtuInSlice++; + } + } + } +}; + +class RectSlice +{ +private: + uint32_t m_tileIdx; //!< tile index corresponding to the first CTU in the slice + uint32_t m_sliceWidthInTiles; //!< slice width in units of tiles + uint32_t m_sliceHeightInTiles; //!< slice height in units of tiles + uint32_t m_numSlicesInTile; //!< number of slices in current tile for the special case of multiple slices inside a single tile + uint32_t m_sliceHeightInCtu; //!< slice height in units of CTUs for the special case of multiple slices inside a single tile + +public: + RectSlice(); + virtual ~RectSlice(); + + void setSliceWidthInTiles( uint32_t u ) { m_sliceWidthInTiles = u; } + uint32_t getSliceWidthInTiles( ) const { return m_sliceWidthInTiles; } + void setSliceHeightInTiles( uint32_t u ) { m_sliceHeightInTiles = u; } + uint32_t getSliceHeightInTiles( ) const { return m_sliceHeightInTiles; } + void setNumSlicesInTile( uint32_t u ) { m_numSlicesInTile = u; } + uint32_t getNumSlicesInTile( ) const { return m_numSlicesInTile; } + void setSliceHeightInCtu( uint32_t u ) { m_sliceHeightInCtu = u; } + uint32_t getSliceHeightInCtu( ) const { return m_sliceHeightInCtu; } + void setTileIdx( uint32_t u ) { m_tileIdx = u; } + uint32_t getTileIdx( ) const { return m_tileIdx; } + +}; +#endif + class DPS { private: @@ -1420,11 +1492,36 @@ private: bool m_subPicIdSignallingPresentFlag; //!< indicates the presence of sub-picture ID signalling in the PPS uint32_t m_subPicIdLen; //!< sub-picture ID length in bits uint8_t m_subPicId[MAX_NUM_SUB_PICS]; //!< sub-picture ID for each sub-picture in the sequence +#endif +#if JVET_P1004_REMOVE_BRICKS + bool m_noPicPartitionFlag; //!< no picture partitioning flag - single slice, single tile + uint8_t m_log2CtuSize; //!< log2 of the CTU size - required to match corresponding value in SPS + uint8_t m_ctuSize; //!< CTU size + uint32_t m_picWidthInCtu; //!< picture width in units of CTUs + uint32_t m_picHeightInCtu; //!< picture height in units of CTUs + uint32_t m_numExpTileCols; //!< number of explicitly specified tile columns + uint32_t m_numExpTileRows; //!< number of explicitly specified tile rows + uint32_t m_numTileCols; //!< number of tile columns + uint32_t m_numTileRows; //!< number of tile rows + std::vector<uint32_t> m_tileColWidth; //!< tile column widths in units of CTUs + std::vector<uint32_t> m_tileRowHeight; //!< tile row heights in units of CTUs + std::vector<uint32_t> m_tileColBd; //!< tile column left-boundaries in units of CTUs + std::vector<uint32_t> m_tileRowBd; //!< tile row top-boundaries in units of CTUs + std::vector<uint32_t> m_ctuToTileCol; //!< mapping between CTU horizontal address and tile column index + std::vector<uint32_t> m_ctuToTileRow; //!< mapping between CTU vertical address and tile row index + bool m_rectSliceFlag; //!< rectangular slice flag + uint32_t m_numSlicesInPic; //!< number of rectangular slices in the picture (raster-scan slice specified at slice level) + bool m_tileIdxDeltaPresentFlag; //!< tile index delta present flag + std::vector<RectSlice> m_rectSlices; //!< list of rectangular slice signalling parameters + std::vector<SliceMap> m_sliceMap; //!< list of CTU maps for each slice in the picture + bool m_loopFilterAcrossTilesEnabledFlag; //!< loop filtering applied across tiles flag + bool m_loopFilterAcrossSlicesEnabledFlag; //!< loop filtering applied across slices flag #endif bool m_TransquantBypassEnabledFlag; //!< Indicates presence of cu_transquant_bypass_flag in CUs. int m_log2MaxTransformSkipBlockSize; bool m_entropyCodingSyncEnabledFlag; //!< Indicates the presence of wavefronts +#if !JVET_P1004_REMOVE_BRICKS bool m_loopFilterAcrossBricksEnabledFlag; bool m_uniformTileSpacingFlag; int m_numTileColumnsMinus1; @@ -1454,6 +1551,7 @@ private: int m_signalledSliceIdLengthMinus1; std::vector<int> m_sliceId; +#endif bool m_constantSliceHeaderParamsEnabledFlag; int m_PPSDepQuantEnabledIdc; int m_PPSRefPicListSPSIdc0; @@ -1475,7 +1573,9 @@ private: bool m_pictureHeaderExtensionPresentFlag; //< picture header extension flags present in picture headers or not #endif bool m_sliceHeaderExtensionPresentFlag; +#if !JVET_P1004_REMOVE_BRICKS bool m_loopFilterAcrossSlicesEnabledFlag; +#endif bool m_deblockingFilterControlPresentFlag; bool m_deblockingFilterOverrideEnabledFlag; bool m_ppsDeblockingFilterDisabledFlag; @@ -1603,6 +1703,71 @@ public: uint32_t getSubPicIdLen() const { return m_subPicIdLen; } void setSubPicId( int i, uint8_t u ) { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); m_subPicId[i] = u; } uint8_t getSubPicId( int i ) const { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); return m_subPicId[i]; } +#endif +#if JVET_P1004_REMOVE_BRICKS + void setNoPicPartitionFlag( bool b ) { m_noPicPartitionFlag = b; } + bool getNoPicPartitionFlag( ) const { return m_noPicPartitionFlag; } + void setLog2CtuSize( uint8_t u ) { m_log2CtuSize = u; m_ctuSize = 1 << m_log2CtuSize; + m_picWidthInCtu = (m_picWidthInLumaSamples + m_ctuSize - 1) / m_ctuSize; + m_picHeightInCtu = (m_picHeightInLumaSamples + m_ctuSize - 1) / m_ctuSize; } + uint8_t getLog2CtuSize( ) const { return m_log2CtuSize; } + uint8_t getCtuSize( ) const { return m_ctuSize; } + uint8_t getPicWidthInCtu( ) const { return m_picWidthInCtu; } + uint8_t getPicHeightInCtu( ) const { return m_picHeightInCtu; } + void setNumExpTileColumns( uint32_t u ) { m_numExpTileCols = u; } + uint32_t getNumExpTileColumns( ) const { return m_numExpTileCols; } + void setNumExpTileRows( uint32_t u ) { m_numExpTileRows = u; } + uint32_t getNumExpTileRows( ) const { return m_numExpTileRows; } + void setNumTileColumns( uint32_t u ) { m_numTileCols = u; } + uint32_t getNumTileColumns( ) const { return m_numTileCols; } + void setNumTileRows( uint32_t u ) { m_numTileRows = u; } + uint32_t getNumTileRows( ) const { return m_numTileRows; } + uint32_t getNumTiles( ) const { return m_numTileCols * m_numTileRows; } + void setTileColumnWidths( std::vector<uint32_t> widths ) { m_tileColWidth = widths; } + void setTileRowHeights( std::vector<uint32_t> heights ) { m_tileRowHeight = heights; } + void addTileColumnWidth( uint32_t u ) { CHECK( m_tileColWidth.size() >= MAX_TILE_COLS, "Number of tile columns exceeds valid range" ); m_tileColWidth.push_back(u); } + void addTileRowHeight( uint32_t u ) { CHECK( m_tileRowHeight.size() >= MAX_TILE_ROWS, "Number of tile rows exceeds valid range" ); m_tileRowHeight.push_back(u); } + uint32_t getTileColumnWidth( int idx ) const { CHECK( idx >= m_tileColWidth.size(), "Tile column index exceeds valid range" ); return m_tileColWidth[idx]; } + uint32_t getTileRowHeight( int idx ) const { CHECK( idx >= m_tileRowHeight.size(), "Tile row index exceeds valid range" ); return m_tileRowHeight[idx]; } + uint32_t getTileColumnBd( int idx ) const { CHECK( idx >= m_tileColBd.size(), "Tile column index exceeds valid range" ); return m_tileColBd[idx]; } + uint32_t getTileRowBd( int idx ) const { CHECK( idx >= m_tileRowBd.size(), "Tile row index exceeds valid range" ); return m_tileRowBd[idx]; } + uint32_t ctuToTileCol( int ctuX ) const { CHECK( ctuX >= m_ctuToTileCol.size(), "CTU address index exceeds valid range" ); return m_ctuToTileCol[ctuX]; } + uint32_t ctuToTileRow( int ctuY ) const { CHECK( ctuY >= m_ctuToTileRow.size(), "CTU address index exceeds valid range" ); return m_ctuToTileRow[ctuY]; } + uint32_t ctuToTileColBd( int ctuX ) const { return getTileColumnBd(ctuToTileCol( ctuX )); } + uint32_t ctuToTileRowBd( int ctuY ) const { return getTileRowBd(ctuToTileRow( ctuY )); } + bool ctuIsTileColBd( int ctuX ) const { return ctuX == ctuToTileColBd( ctuX ); } + bool ctuIsTileRowBd( int ctuY ) const { return ctuY == ctuToTileRowBd( ctuY ); } + uint32_t getTileIdx( uint32_t ctuX, uint32_t ctuY ) const { return (ctuToTileRow( ctuY ) * getNumTileColumns()) + ctuToTileCol( ctuX ); } + uint32_t getTileIdx( uint32_t ctuRsAddr) const { return getTileIdx( ctuRsAddr % m_picWidthInCtu, ctuRsAddr / m_picWidthInCtu ); } + uint32_t getTileIdx( const Position& pos ) const { return getTileIdx( pos.x / m_ctuSize, pos.y / m_ctuSize ); } + void setRectSliceFlag( bool b ) { m_rectSliceFlag = b; } + bool getRectSliceFlag( ) const { return m_rectSliceFlag; } + void setNumSlicesInPic( uint32_t u ) { CHECK( u > MAX_SLICES, "Number of slices in picture exceeds valid range" ); m_numSlicesInPic = u; } + uint32_t getNumSlicesInPic( ) const { return m_numSlicesInPic; } + void setTileIdxDeltaPresentFlag( bool b ) { m_tileIdxDeltaPresentFlag = b; } + bool getTileIdxDeltaPresentFlag( ) const { return m_tileIdxDeltaPresentFlag; } + void setSliceWidthInTiles( int idx, uint32_t u ) { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); m_rectSlices[idx].setSliceWidthInTiles( u ); } + uint32_t getSliceWidthInTiles( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_rectSlices[idx].getSliceWidthInTiles( ); } + void setSliceHeightInTiles( int idx, uint32_t u ) { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); m_rectSlices[idx].setSliceHeightInTiles( u ); } + uint32_t getSliceHeightInTiles( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_rectSlices[idx].getSliceHeightInTiles( ); } + void setNumSlicesInTile( int idx, uint32_t u ) { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); m_rectSlices[idx].setNumSlicesInTile( u ); } + uint32_t getNumSlicesInTile( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_rectSlices[idx].getNumSlicesInTile( ); } + void setSliceHeightInCtu( int idx, uint32_t u ) { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); m_rectSlices[idx].setSliceHeightInCtu( u ); } + uint32_t getSliceHeightInCtu( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_rectSlices[idx].getSliceHeightInCtu( ); } + void setSliceTileIdx( int idx, uint32_t u ) { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); m_rectSlices[idx].setTileIdx( u ); } + uint32_t getSliceTileIdx( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_rectSlices[idx].getTileIdx( ); } + void setRectSlices( std::vector<RectSlice> rectSlices ) { m_rectSlices = rectSlices; } + void setLoopFilterAcrossTilesEnabledFlag( bool b ) { m_loopFilterAcrossTilesEnabledFlag = b; } + bool getLoopFilterAcrossTilesEnabledFlag( ) const { return m_loopFilterAcrossTilesEnabledFlag; } + void setLoopFilterAcrossSlicesEnabledFlag( bool b ) { m_loopFilterAcrossSlicesEnabledFlag = b; } + bool getLoopFilterAcrossSlicesEnabledFlag( ) const { return m_loopFilterAcrossSlicesEnabledFlag; } + void resetTileSliceInfo(); + void initTiles(); + void initRectSlices(); + void initRectSliceMap(); + void initRasterSliceMap( std::vector<uint32_t> sizes ); + void checkSliceMap(); + SliceMap getSliceMap( int idx ) const { CHECK( idx >= m_numSlicesInPic, "Slice index exceeds valid range" ); return m_sliceMap[idx]; } #endif void setTransquantBypassEnabledFlag( bool b ) { m_TransquantBypassEnabledFlag = b; } bool getTransquantBypassEnabledFlag() const { return m_TransquantBypassEnabledFlag; } @@ -1610,11 +1775,14 @@ public: uint32_t getLog2MaxTransformSkipBlockSize() const { return m_log2MaxTransformSkipBlockSize; } void setLog2MaxTransformSkipBlockSize(uint32_t u) { m_log2MaxTransformSkipBlockSize = u; } +#if !JVET_P1004_REMOVE_BRICKS void setLoopFilterAcrossBricksEnabledFlag(bool b) { m_loopFilterAcrossBricksEnabledFlag = b; } bool getLoopFilterAcrossBricksEnabledFlag() const { return m_loopFilterAcrossBricksEnabledFlag; } +#endif bool getEntropyCodingSyncEnabledFlag() const { return m_entropyCodingSyncEnabledFlag; } void setEntropyCodingSyncEnabledFlag(bool val) { m_entropyCodingSyncEnabledFlag = val; } +#if !JVET_P1004_REMOVE_BRICKS void setUniformTileSpacingFlag(bool b) { m_uniformTileSpacingFlag = b; } bool getUniformTileSpacingFlag() const { return m_uniformTileSpacingFlag; } void setNumTileColumnsMinus1(int i) { m_numTileColumnsMinus1 = i; } @@ -1668,6 +1836,7 @@ public: void setSignalledSliceIdLengthMinus1(int val) { m_signalledSliceIdLengthMinus1 = val; } int getSliceId(uint32_t columnIdx) const { return m_sliceId[columnIdx]; } void setSliceId(const std::vector<int>& val) { m_sliceId = val; } +#endif bool getConstantSliceHeaderParamsEnabledFlag() const { return m_constantSliceHeaderParamsEnabledFlag; } void setConstantSliceHeaderParamsEnabledFlag(bool b) { m_constantSliceHeaderParamsEnabledFlag = b; } @@ -1711,8 +1880,10 @@ public: int getDeblockingFilterTcOffsetDiv2() const { return m_deblockingFilterTcOffsetDiv2; } //!< get tc offset for deblocking filter bool getListsModificationPresentFlag() const { return m_listsModificationPresentFlag; } void setListsModificationPresentFlag( bool b ) { m_listsModificationPresentFlag = b; } +#if !JVET_P1004_REMOVE_BRICKS void setLoopFilterAcrossSlicesEnabledFlag( bool bValue ) { m_loopFilterAcrossSlicesEnabledFlag = bValue; } bool getLoopFilterAcrossSlicesEnabledFlag() const { return m_loopFilterAcrossSlicesEnabledFlag; } +#endif #if JVET_P1006_PICTURE_HEADER bool getPictureHeaderExtensionPresentFlag() const { return m_pictureHeaderExtensionPresentFlag; } void setPictureHeaderExtensionPresentFlag(bool val) { m_pictureHeaderExtensionPresentFlag = val; } @@ -2143,19 +2314,25 @@ private: uint32_t m_uiTLayer; bool m_bTLayerSwitchingFlag; +#if JVET_P1004_REMOVE_BRICKS + SliceMap m_sliceMap; //!< list of CTUs in current slice - raster scan CTU addresses +#else SliceConstraint m_sliceMode; uint32_t m_sliceArgument; uint32_t m_sliceCurStartCtuTsAddr; uint32_t m_sliceCurEndCtuTsAddr; +#endif uint32_t m_independentSliceIdx; bool m_nextSlice; uint32_t m_sliceBits; bool m_bFinalized; +#if !JVET_P1004_REMOVE_BRICKS uint32_t m_sliceCurStartBrickIdx; uint32_t m_sliceCurEndBrickIdx; uint32_t m_sliceNumBricks; uint32_t m_sliceIdx; +#endif bool m_bTestWeightPred; bool m_bTestWeightBiPred; @@ -2163,6 +2340,9 @@ private: WPACDCParam m_weightACDCParam[MAX_NUM_COMPONENT]; ClpRngs m_clpRngs; std::vector<uint32_t> m_substreamSizes; +#if JVET_P1004_REMOVE_BRICKS + uint32_t m_numEntryPoints; +#endif bool m_cabacInitFlag; @@ -2461,6 +2641,20 @@ public: void setHandleCraAsCvsStartFlag( bool val ) { m_handleCraAsCvsStartFlag = val; } bool getHandleCraAsCvsStartFlag() const { return m_handleCraAsCvsStartFlag; } +#if JVET_P1004_REMOVE_BRICKS + void setNumTilesInSlice( uint32_t u ) { m_sliceMap.setNumTilesInSlice( u ); } + uint32_t getNumTilesInSlice() const { return m_sliceMap.getNumTilesInSlice(); } + void setSliceMap( SliceMap map ) { m_sliceMap = map; } + uint32_t getFirstCtuRsAddrInSlice() const { return m_sliceMap.getCtuAddrInSlice(0); } + void setSliceID( uint32_t u ) { m_sliceMap.setSliceID( u ); } + uint32_t getSliceID() const { return m_sliceMap.getSliceID(); } + uint32_t getNumCtuInSlice() const { return m_sliceMap.getNumCtuInSlice(); } + uint32_t getCtuAddrInSlice( int idx ) const { return m_sliceMap.getCtuAddrInSlice( idx ); } + void initSliceMap() { m_sliceMap.initSliceMap(); } + void addCtusToSlice( uint32_t startX, uint32_t stopX, + uint32_t startY, uint32_t stopY, + uint32_t picWidthInCtbsY ) { m_sliceMap.addCtusToSlice(startX, stopX, startY, stopY, picWidthInCtbsY); } +#else void setSliceMode( SliceConstraint mode ) { m_sliceMode = mode; } SliceConstraint getSliceMode() const { return m_sliceMode; } void setSliceArgument( uint32_t uiArgument ) { m_sliceArgument = uiArgument; } @@ -2469,6 +2663,7 @@ public: uint32_t getSliceCurStartCtuTsAddr() const { return m_sliceCurStartCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) void setSliceCurEndCtuTsAddr( uint32_t ctuTsAddr ) { m_sliceCurEndCtuTsAddr = ctuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) uint32_t getSliceCurEndCtuTsAddr() const { return m_sliceCurEndCtuTsAddr; } // CTU Tile-scan address (as opposed to raster-scan) +#endif void setIndependentSliceIdx( uint32_t i) { m_independentSliceIdx = i; } uint32_t getIndependentSliceIdx() const { return m_independentSliceIdx; } void copySliceInfo(Slice *pcSliceSrc, bool cpyAlmostAll = true); @@ -2476,6 +2671,7 @@ public: uint32_t getSliceBits() const { return m_sliceBits; } void setFinalized( bool uiVal ) { m_bFinalized = uiVal; } bool getFinalized() const { return m_bFinalized; } +#if !JVET_P1004_REMOVE_BRICKS void setSliceCurStartBrickIdx(uint32_t brickIdx) { m_sliceCurStartBrickIdx = brickIdx; } uint32_t getSliceCurStartBrickIdx() const { return m_sliceCurStartBrickIdx; } void setSliceCurEndBrickIdx(uint32_t brickIdx) { m_sliceCurEndBrickIdx = brickIdx; } @@ -2484,6 +2680,7 @@ public: uint32_t getSliceNumBricks() const { return m_sliceNumBricks; } void setSliceIndex(uint32_t idx) { m_sliceIdx = idx; } uint32_t getSliceIndex() const { return m_sliceIdx; } +#endif bool testWeightPred( ) const { return m_bTestWeightPred; } void setTestWeightPred( bool bValue ) { m_bTestWeightPred = bValue; } bool testWeightBiPred( ) const { return m_bTestWeightBiPred; } @@ -2572,6 +2769,10 @@ public: void setNonRefPictFlag(bool value) { m_nonReferencePicFlag = value; } bool getNonRefPictFlag() const { return m_nonReferencePicFlag; } #endif +#if JVET_P1004_REMOVE_BRICKS + void setNumEntryPoints( const PPS *pps ); + uint32_t getNumEntryPoints( ) const { return m_numEntryPoints; } +#endif protected: #if JVET_N0278_FIXES diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index c9b72c627..2d305845a 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_P1004_REMOVE_BRICKS 1 // JVET-P1004: Removal of bricks + #define JVET_P0202_P0203_FIX_HRD_RELATED_SEI 1 // JVET-P0202 and JVET-P0203: CPB timing for sub-layers with DU and parsing independency to SPS #define JVET_P0551_ALF_SLICE_BOUNDARY 1 // JVET-P0053/P0157/P0551: Applying picturce boundary padding to slice boundaries @@ -817,6 +819,7 @@ enum ScalingList1dStartIdx SCALING_LIST_1D_START_64x64 = 26, }; #endif +#if !JVET_P1004_REMOVE_BRICKS // Slice / Slice segment encoding modes enum SliceConstraint { @@ -827,6 +830,7 @@ enum SliceConstraint SINGLE_BRICK_PER_SLICE = 4, ///< each brick is coded as separate NAL unit (slice) NUMBER_OF_SLICE_CONSTRAINT_MODES = 5 }; +#endif // For use with decoded picture hash SEI messages, generated by encoder. enum HashType diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index 7714d436e..798859c78 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -169,7 +169,11 @@ void AdaptiveDepthPartitioner::setMaxMinDepth( unsigned& minDepth, unsigned& max unsigned stdMaxDepth = ( floorLog2(cs.sps->getCTUSize()) - floorLog2(cs.sps->getMinQTSize( cs.slice->getSliceType(), chType ))); const Position pos = currArea().blocks[chType].pos(); const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const unsigned curTileIdx = cs.pps->getTileIdx( currArea().lumaPos() ); +#else const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea().lumaPos() ); +#endif const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), pos, curSliceIdx, curTileIdx, chType ); const CodingUnit* cuBelowLeft = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), pos, curSliceIdx, curTileIdx, chType ); diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 62ff927ba..afe71bc74 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -155,6 +155,7 @@ bool CU::isSameTile(const CodingUnit& cu, const CodingUnit& cu2) return cu.tileIdx == cu2.tileIdx; } +#if !JVET_P1004_REMOVE_BRICKS #if JVET_O0625_ALF_PADDING bool CU::isSameBrick( const CodingUnit& cu, const CodingUnit& cu2 ) { @@ -166,6 +167,7 @@ bool CU::isSameBrick( const CodingUnit& cu, const CodingUnit& cu2 ) return brickIdx == brickIdx2; } #endif +#endif bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2) { @@ -200,7 +202,19 @@ int CU::predictQP( const CodingUnit& cu, const int prevQP ) { const CodingStructure &cs = *cu.cs; +#if JVET_P1004_REMOVE_BRICKS + uint32_t ctuRsAddr = getCtuAddr( cu ); + uint32_t ctuXPosInCtus = ctuRsAddr % cs.pcv->widthInCtus; + uint32_t tileColIdx = cu.slice->getPPS()->ctuToTileCol( ctuXPosInCtus ); + uint32_t tileXPosInCtus = cu.slice->getPPS()->getTileColumnBd( tileColIdx ); + if( ctuXPosInCtus == tileXPosInCtus && + !( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) && + !( 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) != NULL ) && + CU::isSameSliceAndTile( *cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType), cu ) ) +#else if ( !cu.blocks[cu.chType].x && !( 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) != NULL ) && CU::isSameSliceAndTile( *cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType), cu ) ) +#endif { return ( ( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType ) )->qp ); } diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 590d7c599..d2ff1fcff 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -70,7 +70,9 @@ namespace CU bool isLastSubCUOfCtu (const CodingUnit &cu); uint32_t getCtuAddr (const CodingUnit &cu); #if JVET_O0625_ALF_PADDING || JVET_P0551_ALF_SLICE_BOUNDARY +#if !JVET_P1004_REMOVE_BRICKS bool isSameBrick ( const CodingUnit& cu, const CodingUnit& cu2 ); +#endif #endif int predictQP (const CodingUnit& cu, const int prevQP ); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index ae2554ab2..ec7a33c8c 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -130,10 +130,18 @@ void CABACReader::remaining_bytes( bool noTrailingBytesExpected ) //================================================================================ // clause 7.3.8.2 //-------------------------------------------------------------------------------- +#if JVET_P1004_REMOVE_BRICKS +// void coding_tree_unit( cs, area, qpL, qpC, ctuRsAddr ) +#else // bool coding_tree_unit( cs, area, qpL, qpC, ctuRsAddr ) +#endif //================================================================================ +#if JVET_P1004_REMOVE_BRICKS +void CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, int (&qps)[2], unsigned ctuRsAddr ) +#else bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, int (&qps)[2], unsigned ctuRsAddr ) +#endif { CUCtx cuCtx( qps[CH_L] ); QTBTPartitioner partitioner; @@ -152,7 +160,11 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const uint32_t curTileIdx = cs.pps->getTileIdx( pos ); +#else const uint32_t curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#endif bool leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; @@ -195,26 +207,44 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i } } +#if !JVET_P1004_REMOVE_BRICKS bool isLast = false; +#endif if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 ) { QTBTPartitioner chromaPartitioner; chromaPartitioner.initCtu(area, CH_C, *cs.slice); CUCtx cuCtxChroma(qps[CH_C]); +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, partitioner, cuCtx, &chromaPartitioner, &cuCtxChroma); +#else isLast = coding_tree(cs, partitioner, cuCtx, &chromaPartitioner, &cuCtxChroma); +#endif qps[CH_L] = cuCtx.qp; qps[CH_C] = cuCtxChroma.qp; } else { +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, partitioner, cuCtx); +#else isLast = coding_tree(cs, partitioner, cuCtx); +#endif qps[CH_L] = cuCtx.qp; +#if JVET_P1004_REMOVE_BRICKS + if( CS::isDualITree( cs ) && cs.pcv->chrFormat != CHROMA_400 ) +#else if( !isLast && CS::isDualITree( cs ) && cs.pcv->chrFormat != CHROMA_400 ) +#endif { CUCtx cuCtxChroma( qps[CH_C] ); partitioner.initCtu(area, CH_C, *cs.slice); +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, partitioner, cuCtxChroma); +#else isLast = coding_tree(cs, partitioner, cuCtxChroma); +#endif qps[CH_C] = cuCtxChroma.qp; } } @@ -222,7 +252,9 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i DTRACE_COND( ctuRsAddr == 0, g_trace_ctx, D_QP_PER_CTU, "\n%4d %2d", cs.picture->poc, cs.slice->getSliceQpBase() ); DTRACE ( g_trace_ctx, D_QP_PER_CTU, " %3d", qps[CH_L] - cs.slice->getSliceQpBase() ); +#if !JVET_P1004_REMOVE_BRICKS return isLast; +#endif } void CABACReader::readAlfCtuFilterIndex(CodingStructure& cs, unsigned ctuRsAddr) @@ -321,7 +353,11 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SAO ); +#if JVET_P1004_REMOVE_BRICKS + const unsigned curTileIdx = cs.pps->getTileIdx( pos ); +#else const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#endif if( cs.getCURestricted( pos.offset(-(int)cs.pcv->maxCUWidth, 0), pos, curSliceIdx, curTileIdx, CH_L ) ) { // sao_merge_left_flag @@ -436,16 +472,26 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) //================================================================================ // clause 7.3.8.4 //-------------------------------------------------------------------------------- +#if JVET_P1004_REMOVE_BRICKS +// void coding_tree ( cs, partitioner, cuCtx ) +#else // bool coding_tree ( cs, partitioner, cuCtx ) +#endif // bool split_cu_flag ( cs, partitioner ) // split split_cu_mode_mt ( cs, partitioner ) //================================================================================ +#if JVET_P1004_REMOVE_BRICKS +void CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, Partitioner* pPartitionerChroma, CUCtx* pCuCtxChroma) +#else bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, Partitioner* pPartitionerChroma, CUCtx* pCuCtxChroma) +#endif { const PPS &pps = *cs.pps; const UnitArea &currArea = partitioner.currArea(); +#if !JVET_P1004_REMOVE_BRICKS bool lastSegment = false; +#endif // Reset delta QP coding flag and ChromaQPAdjustemt coding flag //Note: do not reset qg at chroma CU @@ -516,15 +562,25 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU bool beContinue = true; bool lumaContinue = true; bool chromaContinue = true; +#if !JVET_P1004_REMOVE_BRICKS bool lastSegmentC = false; +#endif while (beContinue) { if (partitioner.currArea().lwidth() > 64 || partitioner.currArea().lheight() > 64) { +#if JVET_P1004_REMOVE_BRICKS + if (cs.area.blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos())) +#else if (!lastSegmentC && cs.area.blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos())) +#endif { +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, partitioner, cuCtx, pPartitionerChroma, pCuCtxChroma); +#else lastSegmentC = coding_tree(cs, partitioner, cuCtx, pPartitionerChroma, pCuCtxChroma); +#endif } lumaContinue = partitioner.nextPart(cs); chromaContinue = pPartitionerChroma->nextPart(cs); @@ -534,18 +590,36 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU else { //dual tree coding under 64x64 block +#if JVET_P1004_REMOVE_BRICKS + if (cs.area.blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos())) +#else if (!lastSegment && cs.area.blocks[partitioner.chType].contains(partitioner.currArea().blocks[partitioner.chType].pos())) +#endif { +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, partitioner, cuCtx); +#else lastSegment = coding_tree(cs, partitioner, cuCtx); +#endif } lumaContinue = partitioner.nextPart(cs); +#if JVET_P1004_REMOVE_BRICKS + if (cs.area.blocks[pPartitionerChroma->chType].contains(pPartitionerChroma->currArea().blocks[pPartitionerChroma->chType].pos())) +#else if (!lastSegmentC && cs.area.blocks[pPartitionerChroma->chType].contains(pPartitionerChroma->currArea().blocks[pPartitionerChroma->chType].pos())) +#endif { +#if JVET_P1004_REMOVE_BRICKS + coding_tree(cs, *pPartitionerChroma, *pCuCtxChroma); +#else lastSegmentC = coding_tree(cs, *pPartitionerChroma, *pCuCtxChroma); +#endif } chromaContinue = pPartitionerChroma->nextPart(cs); CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched"); +#if !JVET_P1004_REMOVE_BRICKS CHECK(lastSegment == true, "luma should not be the last segment"); +#endif beContinue = lumaContinue; } } @@ -584,7 +658,9 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU CodingUnit* chromaFirstCu = cs.getCU(pPartitionerChroma->currArea().chromaPos(), CHANNEL_TYPE_CHROMA); tempLastLumaCu->next = chromaFirstCu; +#if !JVET_P1004_REMOVE_BRICKS lastSegment = lastSegmentC; +#endif } else { @@ -600,9 +676,17 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU partitioner.splitCurrArea( splitMode, cs ); do { +#if JVET_P1004_REMOVE_BRICKS + if( cs.area.blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) +#else if( !lastSegment && cs.area.blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) +#endif { +#if JVET_P1004_REMOVE_BRICKS + coding_tree( cs, partitioner, cuCtx ); +#else lastSegment = coding_tree( cs, partitioner, cuCtx ); +#endif } } while( partitioner.nextPart( cs ) ); @@ -613,9 +697,17 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU partitioner.chType = CHANNEL_TYPE_CHROMA; cs.treeType = partitioner.treeType = TREE_C; +#if JVET_P1004_REMOVE_BRICKS + if( cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) +#else if( !lastSegment && cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) +#endif { +#if JVET_P1004_REMOVE_BRICKS + coding_tree( cs, partitioner, cuCtx ); +#else lastSegment = coding_tree( cs, partitioner, cuCtx ); +#endif } //recover treeType @@ -630,14 +722,22 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU if (startShareThisLevel == 1) shareStateDec = NO_SHARE; #endif +#if JVET_P1004_REMOVE_BRICKS + return; +#else return lastSegment; +#endif } CodingUnit& cu = cs.addCU( CS::getArea( cs, currArea, partitioner.chType ), partitioner.chType ); partitioner.setCUData( cu ); cu.slice = cs.slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = cs.pps->getTileIdx( currArea.lumaPos() ); +#else cu.tileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea.lumaPos() ); +#endif CHECK( cu.cs->treeType != partitioner.treeType, "treeType mismatch" ); int lumaQPinLocalDualTree = -1; @@ -670,7 +770,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU cu.shareParentSize = (shareStateDec == SHARING) ? shareParentSize : partitioner.currArea().lumaSize(); #endif +#if JVET_P1004_REMOVE_BRICKS + coding_unit( cu, partitioner, cuCtx ); +#else bool isLastCtu = coding_unit( cu, partitioner, cuCtx ); +#endif //recover cuCtx.qp to luma qp after decoding the chroma CU if( pps.getUseDQP() && partitioner.isSepTree( cs ) && isChroma( cu.chType ) ) { @@ -715,7 +819,9 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU if (startShareThisLevel == 1) shareStateDec = NO_SHARE; #endif +#if !JVET_P1004_REMOVE_BRICKS return isLastCtu; +#endif } ModeType CABACReader::mode_constraint( CodingStructure& cs, Partitioner &partitioner, PartSplit splitMode ) @@ -811,7 +917,11 @@ PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitio //================================================================================ // clause 7.3.8.5 //-------------------------------------------------------------------------------- +#if JVET_P1004_REMOVE_BRICKS +// void coding_unit ( cu, partitioner, cuCtx ) +#else // bool coding_unit ( cu, partitioner, cuCtx ) +#endif // void cu_transquant_bypass_flag ( cu ) // void cu_skip_flag ( cu ) // void pred_mode ( cu ) @@ -822,10 +932,18 @@ PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitio // void intra_chroma_pred_mode ( pu ) // void cu_residual ( cu, partitioner, cuCtx ) // void rqt_root_cbf ( cu ) +#if JVET_P1004_REMOVE_BRICKS +// void end_of_ctu ( cu, cuCtx ) +#else // bool end_of_ctu ( cu, cuCtx ) +#endif //================================================================================ +#if JVET_P1004_REMOVE_BRICKS +void CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& cuCtx ) +#else bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& cuCtx ) +#endif { CodingStructure& cs = *cu.cs; CHECK( cu.treeType != partitioner.treeType || cu.modeType != partitioner.modeType, "treeType or modeType mismatch" ); @@ -855,7 +973,12 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& #endif MergeCtx mrgCtx; prediction_unit ( pu, mrgCtx ); +#if JVET_P1004_REMOVE_BRICKS + end_of_ctu( cu, cuCtx ); + return; +#else return end_of_ctu( cu, cuCtx ); +#endif } // prediction mode and partitioning data @@ -887,7 +1010,12 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& { cu_palette_info(cu, COMPONENT_Y, 3, cuCtx); } +#if JVET_P1004_REMOVE_BRICKS + end_of_ctu(cu, cuCtx); + return; +#else return end_of_ctu(cu, cuCtx); +#endif } bdpcm_mode( cu, ComponentID( partitioner.chType ) ); #if JVET_P0059_CHROMA_BDPCM @@ -904,7 +1032,11 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& cu_residual( cu, partitioner, cuCtx ); // check end of cu +#if JVET_P1004_REMOVE_BRICKS + end_of_ctu( cu, cuCtx ); +#else return end_of_ctu( cu, cuCtx ); +#endif } @@ -1711,7 +1843,11 @@ void CABACReader::sbt_mode( CodingUnit& cu ) } +#if JVET_P1004_REMOVE_BRICKS +void CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) +#else bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) +#endif { const Position rbPos = recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].bottomRight().offset( 1, 1 ) ); @@ -1722,10 +1858,14 @@ bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) { cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ); +#if !JVET_P1004_REMOVE_BRICKS return terminating_bit(); +#endif } +#if !JVET_P1004_REMOVE_BRICKS return false; +#endif } void CABACReader::cu_palette_info(CodingUnit& cu, ComponentID compBegin, uint32_t numComp, CUCtx& cuCtx) diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 190794e65..5fe581c30 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -67,7 +67,11 @@ public: void remaining_bytes ( bool noTrailingBytesExpected ); // coding tree unit (clause 7.3.8.2) +#if JVET_P1004_REMOVE_BRICKS + void coding_tree_unit ( CodingStructure& cs, const UnitArea& area, int (&qps)[2], unsigned ctuRsAddr ); +#else bool coding_tree_unit ( CodingStructure& cs, const UnitArea& area, int (&qps)[2], unsigned ctuRsAddr ); +#endif // sao (clause 7.3.8.3) void sao ( CodingStructure& cs, unsigned ctuRsAddr ); @@ -75,12 +79,20 @@ public: void readAlfCtuFilterIndex(CodingStructure& cs, unsigned ctuRsAddr); // coding (quad)tree (clause 7.3.8.4) +#if JVET_P1004_REMOVE_BRICKS + void coding_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); +#else bool coding_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); +#endif PartSplit split_cu_mode ( CodingStructure& cs, Partitioner& pm ); ModeType mode_constraint ( CodingStructure& cs, Partitioner& pm, const PartSplit splitMode ); // coding unit (clause 7.3.8.5) +#if JVET_P1004_REMOVE_BRICKS + void coding_unit ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); +#else bool coding_unit ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); +#endif void cu_transquant_bypass_flag ( CodingUnit& cu ); void cu_skip_flag ( CodingUnit& cu ); void pred_mode ( CodingUnit& cu ); @@ -98,7 +110,11 @@ public: void adaptive_color_transform(CodingUnit& cu); #endif void sbt_mode ( CodingUnit& cu ); +#if JVET_P1004_REMOVE_BRICKS + void end_of_ctu ( CodingUnit& cu, CUCtx& cuCtx ); +#else bool end_of_ctu ( CodingUnit& cu, CUCtx& cuCtx ); +#endif void mip_flag ( CodingUnit& cu ); void mip_pred_modes ( CodingUnit& cu ); void mip_pred_mode ( PredictionUnit& pu ); diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index fab6ddc44..e5be6204b 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -601,13 +601,17 @@ void DecLib::executeLoopFilters() if( cs.sps->getALFEnabledFlag() ) { +#if !JVET_P1004_REMOVE_BRICKS if (cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)) { +#endif // ALF decodes the differentially coded coefficients and stores them in the parameters structure. // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const // copy in case the APS gets used more than once. m_cALF.ALFProcess(cs); +#if !JVET_P1004_REMOVE_BRICKS } +#endif } @@ -1098,10 +1102,12 @@ void DecLib::xActivateParameterSets() #else m_pcPic->finalInit( *sps, *pps, apss, lmcsAPS, scalinglistAPS ); #endif +#if !JVET_P1004_REMOVE_BRICKS #if JVET_P1006_PICTURE_HEADER m_parameterSetManager.getPPS(m_picHeader.getPPSId())->setNumBricksInPic((int)m_pcPic->brickMap->bricks.size()); #else m_parameterSetManager.getPPS(m_apcSlicePilot->getPPSId())->setNumBricksInPic((int)m_pcPic->brickMap->bricks.size()); +#endif #endif m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth ); m_pcPic->cs->createCoeffs((bool)m_pcPic->cs->sps->getPLTMode()); @@ -1341,10 +1347,12 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl m_apcSlicePilot->copySliceInfo( m_pcPic->slices[m_uiSliceSegmentIdx-1] ); } +#if !JVET_P1004_REMOVE_BRICKS m_apcSlicePilot->setSliceCurStartCtuTsAddr(0); m_apcSlicePilot->setSliceCurEndCtuTsAddr(0); m_apcSlicePilot->setSliceCurStartBrickIdx(0); m_apcSlicePilot->setSliceCurEndBrickIdx(0); +#endif m_apcSlicePilot->setNalUnitType(nalu.m_nalUnitType); m_apcSlicePilot->setTLayer(nalu.m_temporalId); @@ -1502,7 +1510,11 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl m_prevSliceSkipped = false; //we should only get a different poc for a new picture (with CTU address==0) +#if JVET_P1004_REMOVE_BRICKS + if(m_apcSlicePilot->getPOC() != m_prevPOC && !m_bFirstSliceInSequence && (m_apcSlicePilot->getFirstCtuRsAddrInSlice() != 0)) +#else if(m_apcSlicePilot->getPOC() != m_prevPOC && !m_bFirstSliceInSequence && (m_apcSlicePilot->getSliceCurStartCtuTsAddr() != 0)) +#endif { msg( WARNING, "Warning, the first slice of a picture might have been lost!\n"); } @@ -1511,7 +1523,11 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl #endif // leave when a new picture is found +#if JVET_P1004_REMOVE_BRICKS + if(m_apcSlicePilot->getFirstCtuRsAddrInSlice() == 0 && !m_bFirstSliceInPicture) +#else if(m_apcSlicePilot->getSliceCurStartCtuTsAddr() == 0 && !m_bFirstSliceInPicture) +#endif { if (m_prevPOC >= m_pocRandomAccess) { @@ -1601,6 +1617,7 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl m_pcPic->subLayerNonReferencePictureDueToSTSA = false; #endif +#if !JVET_P1004_REMOVE_BRICKS if (pcSlice->getPPS()->getRectSliceFlag()) { int sliceIdx = pcSlice->getSliceIndex(); @@ -1639,6 +1656,7 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl pcSlice->setSliceCurStartCtuTsAddr(startCtuIdx); pcSlice->setSliceCurEndCtuTsAddr(endCtuIdx); +#endif pcSlice->checkCRA(pcSlice->getRPL0(), pcSlice->getRPL1(), m_pocCRA, m_associatedIRAPType, m_cListPic); pcSlice->constructRefPicList(m_cListPic); diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index ff0b2c915..75d9c56fd 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -77,7 +77,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb const SPS* sps = slice->getSPS(); Picture* pic = slice->getPic(); +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *pic->brickMap; +#endif CABACReader& cabacReader = *m_CABACDecoder->getCABACReader( 0 ); // setup coding structure @@ -102,7 +104,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb cs.resetPrevPLT(cs.prevPLT); +#if JVET_P1004_REMOVE_BRICKS + if (slice->getFirstCtuRsAddrInSlice() == 0) +#else if (slice->getSliceCurStartCtuTsAddr() == 0) +#endif { cs.picture->resizeAlfCtuEnableFlag( cs.pcv->sizeInCtus ); cs.picture->resizeAlfCtbFilterIndex(cs.pcv->sizeInCtus); @@ -119,9 +125,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb ppcSubstreams[idx] = bitstream->extractSubstream( idx+1 < numSubstreams ? ( slice->getSubstreamSize(idx) << 3 ) : bitstream->getNumBitsLeft() ); } +#if !JVET_P1004_REMOVE_BRICKS const int startCtuTsAddr = slice->getSliceCurStartCtuTsAddr(); const unsigned numCtusInFrame = cs.pcv->sizeInCtus; +#endif const unsigned widthInCtus = cs.pcv->widthInCtus; const bool wavefrontsEnabled = cs.pps->getEntropyCodingSyncEnabledFlag(); @@ -136,14 +144,32 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb // for every CTU in the slice segment... +#if !JVET_P1004_REMOVE_BRICKS bool isLastCtuOfSliceSegment = false; uint32_t startSliceRsRow = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) / widthInCtus; uint32_t startSliceRsCol = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) % widthInCtus; uint32_t endSliceRsRow = tileMap.getCtuBsToRsAddrMap(slice->getSliceCurEndCtuTsAddr() - 1) / widthInCtus; uint32_t endSliceRsCol = tileMap.getCtuBsToRsAddrMap(slice->getSliceCurEndCtuTsAddr() - 1) % widthInCtus; +#endif unsigned subStrmId = 0; +#if JVET_P1004_REMOVE_BRICKS + for( unsigned ctuIdx = 0; ctuIdx < slice->getNumCtuInSlice(); ctuIdx++ ) +#else for( unsigned ctuTsAddr = startCtuTsAddr; !isLastCtuOfSliceSegment && ctuTsAddr < numCtusInFrame; ctuTsAddr++ ) +#endif { +#if JVET_P1004_REMOVE_BRICKS + const unsigned ctuRsAddr = slice->getCtuAddrInSlice(ctuIdx); + const unsigned ctuXPosInCtus = ctuRsAddr % widthInCtus; + const unsigned ctuYPosInCtus = ctuRsAddr / widthInCtus; + const unsigned tileColIdx = slice->getPPS()->ctuToTileCol( ctuXPosInCtus ); + const unsigned tileRowIdx = slice->getPPS()->ctuToTileRow( ctuYPosInCtus ); + const unsigned tileXPosInCtus = slice->getPPS()->getTileColumnBd( tileColIdx ); + const unsigned tileYPosInCtus = slice->getPPS()->getTileRowBd( tileRowIdx ); + const unsigned tileColWidth = slice->getPPS()->getTileColumnWidth( tileColIdx ); + const unsigned tileRowHeight = slice->getPPS()->getTileRowHeight( tileRowIdx ); + const unsigned tileIdx = slice->getPPS()->getTileIdx( ctuXPosInCtus, ctuYPosInCtus); +#else const unsigned ctuRsAddr = tileMap.getCtuBsToRsAddrMap(ctuTsAddr); const Brick& currentTile = tileMap.bricks[ tileMap.getBrickIdxRsMap(ctuRsAddr) ]; if (slice->getPPS()->getRectSliceFlag() && @@ -155,6 +181,7 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb const unsigned tileYPosInCtus = firstCtuRsAddrOfTile / widthInCtus; const unsigned ctuXPosInCtus = ctuRsAddr % widthInCtus; const unsigned ctuYPosInCtus = ctuRsAddr / widthInCtus; +#endif const unsigned maxCUSize = sps->getMaxCUWidth(); Position pos( ctuXPosInCtus*maxCUSize, ctuYPosInCtus*maxCUSize) ; UnitArea ctuArea(cs.area.chromaFormat, Area( pos.x, pos.y, maxCUSize, maxCUSize ) ); @@ -164,9 +191,15 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb cabacReader.initBitstream( ppcSubstreams[subStrmId] ); // set up CABAC contexts' state for this CTU +#if JVET_P1004_REMOVE_BRICKS + if( ctuXPosInCtus == tileXPosInCtus && ctuYPosInCtus == tileYPosInCtus ) + { + if( ctuIdx != 0 ) // if it is the first CTU, then the entropy coder has already been reset +#else if( ctuRsAddr == firstCtuRsAddrOfTile ) { if( ctuTsAddr != startCtuTsAddr ) // if it is the first CTU, then the entropy coder has already been reset +#endif { cabacReader.initCtxModels( *slice ); cs.resetPrevPLT(cs.prevPLT); @@ -176,12 +209,20 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb else if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled ) { // Synchronize cabac probabilities with top CTU if it's available and at the start of a line. +#if JVET_P1004_REMOVE_BRICKS + if( ctuIdx != 0 ) // if it is the first CTU, then the entropy coder has already been reset +#else if( ctuTsAddr != startCtuTsAddr ) // if it is the first CTU, then the entropy coder has already been reset +#endif { cabacReader.initCtxModels( *slice ); cs.resetPrevPLT(cs.prevPLT); } +#if JVET_P1004_REMOVE_BRICKS + if( cs.getCURestricted( pos.offset(0, -1), pos, slice->getIndependentSliceIdx(), tileIdx, CH_L ) ) +#else if( cs.getCURestricted( pos.offset(0, -1), pos, slice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#endif { // Top is available, so use it. cabacReader.getCtx() = m_entropyCodingSyncContextState; @@ -189,7 +230,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb pic->m_prevQP[0] = pic->m_prevQP[1] = slice->getSliceQp(); } +#if JVET_P1004_REMOVE_BRICKS + bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuIdx == 0; +#else bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuTsAddr == startCtuTsAddr; +#endif if(updateGbiCodingOrder) { resetGbiCodingOrder(true, cs); @@ -209,10 +254,16 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb if( ctuRsAddr == debugCTU ) { +#if !JVET_P1004_REMOVE_BRICKS isLastCtuOfSliceSegment = true; // get out here +#endif break; } +#if JVET_P1004_REMOVE_BRICKS + cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr ); +#else isLastCtuOfSliceSegment = cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr ); +#endif m_pcCuDecoder->decompressCtu( cs, ctuArea ); @@ -222,15 +273,30 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb } +#if JVET_P1004_REMOVE_BRICKS + if( ctuIdx == slice->getNumCtuInSlice()-1 ) +#else if( isLastCtuOfSliceSegment ) +#endif { +#if JVET_P1004_REMOVE_BRICKS + unsigned binVal = cabacReader.terminating_bit(); + CHECK( !binVal, "Expecting a terminating bit" ); +#endif #if DECODER_CHECK_SUBSTREAM_AND_SLICE_TRAILING_BYTES cabacReader.remaining_bytes( false ); #endif +#if !JVET_P1004_REMOVE_BRICKS slice->setSliceCurEndCtuTsAddr( ctuTsAddr+1 ); +#endif } +#if JVET_P1004_REMOVE_BRICKS + else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + tileColWidth ) && + ( ctuYPosInCtus + 1 == tileYPosInCtus + tileRowHeight || wavefrontsEnabled ) ) +#else else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getWidthInCtus () ) && ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getHeightInCtus() || wavefrontsEnabled ) ) +#endif { // The sub-stream/stream should be terminated after this CTU. // (end of slice-segment, end of tile, end of wavefront-CTU-row) @@ -242,7 +308,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb subStrmId++; } } +#if !JVET_P1004_REMOVE_BRICKS CHECK( !isLastCtuOfSliceSegment, "Last CTU of slice segment not signalled as such" ); +#endif // deallocate all created substreams, including internal buffers. for( auto substr: ppcSubstreams ) diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 00d56c245..f9f05a0c6 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -412,7 +412,102 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetMana } #endif +#if JVET_P1004_REMOVE_BRICKS + READ_FLAG( uiCode, "no_pic_partition_flag" ); pcPPS->setNoPicPartitionFlag( uiCode == 1 ); + if(!pcPPS->getNoPicPartitionFlag()) + { + int colIdx, rowIdx; + pcPPS->resetTileSliceInfo(); + + // CTU size - required to match size in SPS + READ_CODE(2, uiCode, "log2_pps_ctu_size_minus5"); pcPPS->setLog2CtuSize(uiCode + 5); + CHECK(uiCode > 2, "log2_pps_ctu_size_minus5 must be less than or equal to 2"); + + // number of explicit tile columns/rows + READ_UVLC( uiCode, "num_exp_tile_columns_minus1" ); pcPPS->setNumExpTileColumns( uiCode + 1 ); + READ_UVLC( uiCode, "num_exp_tile_rows_minus1" ); pcPPS->setNumExpTileRows( uiCode + 1 ); + CHECK(pcPPS->getNumExpTileColumns() > MAX_TILE_COLS, "Number of explicit tile columns exceeds valid range"); + CHECK(pcPPS->getNumExpTileRows() > MAX_TILE_ROWS, "Number of explicit tile rows exceeds valid range"); + + // tile sizes + for( colIdx = 0; colIdx < pcPPS->getNumExpTileColumns(); colIdx++ ) + { + READ_UVLC( uiCode, "tile_column_width_minus1[i]" ); pcPPS->addTileColumnWidth( uiCode + 1 ); + } + for( rowIdx = 0; rowIdx < pcPPS->getNumExpTileRows(); rowIdx++ ) + { + READ_UVLC( uiCode, "tile_row_height_minus1[i]" ); pcPPS->addTileRowHeight( uiCode + 1 ); + } + pcPPS->initTiles(); + + // rectangular slice signalling + READ_CODE(1, uiCode, "rect_slice_flag"); pcPPS->setRectSliceFlag( uiCode == 1 ); + if( pcPPS->getRectSliceFlag() ) + { + int32_t tileIdx = 0; + + READ_UVLC( uiCode, "num_slices_in_pic_minus1" ); pcPPS->setNumSlicesInPic( uiCode + 1 ); + CHECK(pcPPS->getNumSlicesInPic() > MAX_SLICES, "Number of slices in picture exceeds valid range"); + READ_CODE(1, uiCode, "tile_idx_delta_present_flag"); pcPPS->setTileIdxDeltaPresentFlag( uiCode == 1 ); + pcPPS->initRectSlices(); + + // read rectangular slice parameters + for( int i = 0; i < pcPPS->getNumSlicesInPic()-1; i++ ) + { + pcPPS->setSliceTileIdx( i, tileIdx ); + + // complete tiles within a single slice + READ_UVLC( uiCode, "slice_width_in_tiles_minus1[i]" ); pcPPS->setSliceWidthInTiles ( i, uiCode + 1 ); + READ_UVLC( uiCode, "slice_height_in_tiles_minus1[i]" ); pcPPS->setSliceHeightInTiles( i, uiCode + 1 ); + + // multiple slices within a single tile special case + if( pcPPS->getSliceWidthInTiles( i ) == 1 && pcPPS->getSliceHeightInTiles( i ) == 1 ) + { + READ_UVLC( uiCode, "num_slices_in_tile_minus1[i]" ); pcPPS->setNumSlicesInTile( i, uiCode + 1 ); + uint32_t numSlicesInTile = pcPPS->getNumSlicesInTile( i ); + for( int j = 0; j < numSlicesInTile-1; j++ ) + { + READ_UVLC( uiCode, "slice_height_in_ctu_minus1[i]" ); pcPPS->setSliceHeightInCtu( i, uiCode + 1 ); + i++; + pcPPS->setSliceWidthInTiles ( i, 1 ); + pcPPS->setSliceHeightInTiles( i, 1 ); + pcPPS->setNumSlicesInTile ( i, numSlicesInTile ); + pcPPS->setSliceTileIdx ( i, tileIdx ); + } + } + + // tile index offset to start of next slice + if( i < pcPPS->getNumSlicesInPic()-1 ) + { + if( pcPPS->getTileIdxDeltaPresentFlag() ) + { + int32_t tileIdxDelta; + READ_SVLC( tileIdxDelta, "tile_idx_delta[i]" ); + tileIdx += tileIdxDelta; + CHECK( tileIdx < 0 || tileIdx >= pcPPS->getNumTiles(), "Invalid tile_idx_delta."); + } + else + { + tileIdx += pcPPS->getSliceWidthInTiles( i ); + if( tileIdx % pcPPS->getNumTileColumns() == 0) + { + tileIdx += (pcPPS->getSliceHeightInTiles( i ) - 1) * pcPPS->getNumTileColumns(); + } + } + } + } + pcPPS->setSliceTileIdx(pcPPS->getNumSlicesInPic()-1, tileIdx ); + + // initialize mapping between rectangular slices and CTUs + pcPPS->initRectSliceMap(); + } + + // loop filtering across slice/tile controls + READ_CODE(1, uiCode, "loop_filter_across_tiles_enabled_flag"); pcPPS->setLoopFilterAcrossTilesEnabledFlag( uiCode == 1 ); + READ_CODE(1, uiCode, "loop_filter_across_slices_enabled_flag"); pcPPS->setLoopFilterAcrossSlicesEnabledFlag( uiCode == 1 ); + } +#endif READ_FLAG( uiCode, "cabac_init_present_flag" ); pcPPS->setCabacInitPresentFlag( uiCode ? true : false ); READ_UVLC(uiCode, "num_ref_idx_l0_default_active_minus1"); @@ -566,6 +661,7 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetMana READ_FLAG( uiCode, "transquant_bypass_enabled_flag"); pcPPS->setTransquantBypassEnabledFlag(uiCode ? true : false); +#if !JVET_P1004_REMOVE_BRICKS READ_FLAG( uiCode, "single_tile_in_pic_flag" ); pcPPS->setSingleTileInPicFlag(uiCode == 1); if(!pcPPS->getSingleTileInPicFlag()) @@ -826,6 +922,7 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS, ParameterSetManager *parameterSetMana } } +#endif READ_FLAG(uiCode, "entropy_coding_sync_enabled_flag"); pcPPS->setEntropyCodingSyncEnabledFlag(uiCode == 1); READ_FLAG( uiCode, "deblocking_filter_control_present_flag" ); pcPPS->setDeblockingFilterControlPresentFlag( uiCode ? true : false ); @@ -1879,6 +1976,30 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag sps = parameterSetManager->getSPS(picHeader->getSPSId()); CHECK(sps==0, "Invalid SPS"); +#if JVET_P1004_REMOVE_BRICKS + // initialize tile/slice info for no partitioning case + if( pps->getNoPicPartitionFlag() ) + { + pps->resetTileSliceInfo(); + pps->setLog2CtuSize( ceilLog2(sps->getCTUSize()) ); + pps->setNumExpTileColumns(1); + pps->setNumExpTileRows(1); + pps->addTileColumnWidth( pps->getPicWidthInCtu( ) ); + pps->addTileRowHeight( pps->getPicHeightInCtu( ) ); + pps->initTiles(); + pps->setRectSliceFlag( 1 ); + pps->setNumSlicesInPic( 1 ); + pps->initRectSlices( ); + pps->setTileIdxDeltaPresentFlag( 0 ); + pps->setSliceTileIdx( 0, 0 ); + pps->initRectSliceMap( ); + } + else + { + CHECK(pps->getCtuSize() != sps->getCTUSize(), "PPS CTU size does not match CTU size in SPS"); + } + +#endif // sub-picture IDs if( sps->getSubPicIdPresentFlag() ) { @@ -2607,6 +2728,58 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para pcSlice->setPOC(iPOCmsb + iPOClsb); } #endif +#if JVET_P1004_REMOVE_BRICKS + + // raster scan slices + if(pps->getRectSliceFlag() == 0) + { + uint32_t sliceAddr, numTilesInSlice; + + // slice address is the raster scan tile index of first tile in slice + if( pps->getNumTiles() > 1 ) + { + int bitsSliceAddress = ceilLog2(pps->getNumTiles()); + READ_CODE(bitsSliceAddress, uiCode, "slice_address"); sliceAddr = uiCode; + READ_UVLC(uiCode, "num_tiles_in_slice_minus1"); numTilesInSlice = uiCode + 1; + } + else { + sliceAddr = 0; + numTilesInSlice = 1; + } + CHECK(sliceAddr >= pps->getNumTiles(), "Invalid slice address"); + pcSlice->initSliceMap(); + pcSlice->setSliceID(sliceAddr); + + for( uint32_t tileIdx = sliceAddr; tileIdx < sliceAddr + numTilesInSlice; tileIdx++ ) + { + uint32_t tileX = tileIdx % pps->getNumTileColumns(); + uint32_t tileY = tileIdx / pps->getNumTileColumns(); + CHECK(tileY >= pps->getNumTileRows(), "Number of tiles in slice exceeds the remaining number of tiles in picture"); + + pcSlice->addCtusToSlice(pps->getTileColumnBd(tileX), pps->getTileColumnBd(tileX + 1), + pps->getTileRowBd(tileY), pps->getTileRowBd(tileY + 1), pps->getPicWidthInCtu()); + } + } + // rectangular slices + else + { + uint32_t sliceAddr; + + // slice address is the index of the slice within the current sub-picture + if( pps->getNumSlicesInPic() > 1 ) + { + int bitsSliceAddress = ceilLog2(pps->getNumSlicesInPic()); // change to NumSlicesInSubPic when available + READ_CODE(bitsSliceAddress, uiCode, "slice_address"); sliceAddr = uiCode; + CHECK(sliceAddr >= pps->getNumSlicesInPic(), "Invalid slice address"); + } + else { + sliceAddr = 0; + } + pcSlice->setSliceMap( pps->getSliceMap(sliceAddr) ); + pcSlice->setSliceID(sliceAddr); + } + +#else int bitsSliceAddress = 1; if (!pps->getRectSliceFlag()) { @@ -2667,6 +2840,7 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para } pcSlice->setSliceCurStartCtuTsAddr(pcSlice->getSliceCurStartBrickIdx()); +#endif #if !JVET_P1006_PICTURE_HEADER READ_FLAG(uiCode, "non_reference_picture_flag"); pcSlice->setNonRefPictFlag(uiCode); #endif @@ -3483,7 +3657,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para } #endif +#if JVET_P1004_REMOVE_BRICKS + if( pcSlice->getFirstCtuRsAddrInSlice() == 0 ) +#else if( pcSlice->getSliceCurStartBrickIdx() == 0 ) +#endif { pcSlice->setDefaultClpRng( *sps ); @@ -3500,6 +3678,20 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para } std::vector<uint32_t> entryPointOffset; +#if JVET_P1004_REMOVE_BRICKS + pcSlice->setNumEntryPoints( pps ); + if( pcSlice->getNumEntryPoints() > 0 ) + { + uint32_t offsetLenMinus1; + READ_UVLC( offsetLenMinus1, "offset_len_minus1" ); + entryPointOffset.resize( pcSlice->getNumEntryPoints() ); + for( uint32_t idx = 0; idx < pcSlice->getNumEntryPoints(); idx++ ) + { + READ_CODE( offsetLenMinus1 + 1, uiCode, "entry_point_offset_minus1" ); + entryPointOffset[idx] = uiCode + 1; + } + } +#else if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() ) { uint32_t numEntryPointOffsets; @@ -3535,6 +3727,7 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para } } } +#endif #if RExt__DECODER_DEBUG_BIT_STATISTICS CodingStatistics::IncrementStatisticEP(STATS__BYTE_ALIGNMENT_BITS,m_pcBitstream->readByteAlignment(),0); @@ -3544,7 +3737,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para pcSlice->clearSubstreamSizes(); +#if JVET_P1004_REMOVE_BRICKS + if( pcSlice->getNumEntryPoints() > 0 ) +#else if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() ) +#endif { int endOfSliceHeaderLocation = m_pcBitstream->getByteLocation(); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 68859306b..344de27c5 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -246,7 +246,11 @@ void CABACWriter::sao( const Slice& slice, unsigned ctuRsAddr ) int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos ( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const unsigned curSliceIdx = slice.getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const unsigned curTileIdx = cs.pps->getTileIdx( pos ); +#else const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#endif bool leftMergeAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveMergeAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; sao_block_pars( sao_ctu_pars, sps.getBitDepths(), sliceEnabled, leftMergeAvail, aboveMergeAvail, false ); @@ -1448,8 +1452,10 @@ void CABACWriter::sbt_mode( const CodingUnit& cu ) void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) { + #if !JVET_P1004_REMOVE_BRICKS const Slice* slice = cu.cs->slice; const int currentCTUTsAddr = cu.cs->picture->brickMap->getCtuRsToBsAddrMap( CU::getCtuAddr( cu ) ); +#endif const bool isLastSubCUOfCtu = CU::isLastSubCUOfCtu( cu ); if ( isLastSubCUOfCtu @@ -1458,12 +1464,14 @@ void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) { cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ); + #if !JVET_P1004_REMOVE_BRICKS // The 1-terminating bit is added to all streams, so don't add it here when it's 1. // i.e. when the slice segment CurEnd CTU address is the current CTU address+1. if(slice->getSliceCurEndCtuTsAddr() != currentCTUTsAddr + 1) { m_BinEncoder.encodeBinTrm( 0 ); } +#endif } } @@ -3983,7 +3991,11 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_P1004_REMOVE_BRICKS + const uint32_t curTileIdx = cs.pps->getTileIdx( pos ); +#else const uint32_t curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#endif bool leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), pos, curSliceIdx, curTileIdx, CH_L ) ? true : false; diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index 463536022..591c45cd7 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -850,7 +850,11 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons setEnableFlag(m_alfParamTemp, channel, true); #if ENABLE_QPA +#if JVET_P1004_REMOVE_BRICKS + CHECK ((chromaWeight > 0.0) && (cs.slice->getFirstCtuRsAddrInSlice() != 0), "incompatible start CTU address, must be 0"); +#else CHECK ((chromaWeight > 0.0) && (cs.slice->getSliceCurStartCtuTsAddr() != 0), "incompatible start CTU address, must be 0"); +#endif #endif reconstructCoeff(m_alfParamTemp, channel, true, isLuma(channel)); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 07a9f2df6..635c3f0fb 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -133,6 +133,7 @@ struct RPLEntry std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry); //input +#if !JVET_P1004_REMOVE_BRICKS struct BrickSplit { int m_tileIdx; @@ -154,6 +155,7 @@ typedef std::map<int, BrickSplit> BrickSplitMap; std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry); //input +#endif //! \ingroup EncoderLib //! \{ @@ -480,6 +482,18 @@ protected: #if JVET_O0549_ENCODER_ONLY_FILTER bool m_gopBasedTemporalFilterEnabled; #endif +#if JVET_P1004_REMOVE_BRICKS + bool m_noPicPartitionFlag; ///< no picture partitioning flag (single tile, single slice) + std::vector<uint32_t> m_tileColumnWidth; ///< tile column widths in units of CTUs (last column width will be repeated uniformly to cover any remaining picture width) + std::vector<uint32_t> m_tileRowHeight; ///< tile row heights in units of CTUs (last row height will be repeated uniformly to cover any remaining picture height) + bool m_rectSliceFlag; ///< indicates if using rectangular or raster-scan slices + uint32_t m_numSlicesInPic; ///< number of rectangular slices in the picture (raster-scan slice specified at slice level) + bool m_tileIdxDeltaPresentFlag; ///< rectangular slice tile index delta present flag + std::vector<RectSlice> m_rectSlices; ///< list of rectanglar slice syntax parameters + std::vector<uint32_t> m_rasterSliceSize; ///< raster-scan slice sizes in units of tiles + bool m_bLFCrossTileBoundaryFlag; ///< 1: filter across tile boundaries 0: do not filter across tile boundaries + bool m_bLFCrossSliceBoundaryFlag; ///< 1: filter across slice boundaries 0: do not filter across slice boundaries +#else //====== Slice ======== SliceConstraint m_sliceMode; int m_sliceArgument; @@ -487,8 +501,10 @@ protected: SliceConstraint m_sliceSegmentMode; int m_sliceSegmentArgument; bool m_bLFCrossSliceBoundaryFlag; +#endif bool m_intraSmoothingDisabledFlag; +#if !JVET_P1004_REMOVE_BRICKS bool m_loopFilterAcrossBricksEnabledFlag; bool m_tileUniformSpacingFlag; int m_iNumColumnsMinus1; @@ -497,9 +513,11 @@ protected: int m_uniformTileRowHeightMinus1; std::vector<int> m_tileColumnWidth; std::vector<int> m_tileRowHeight; +#endif bool m_entropyCodingSyncEnabledFlag; +#if !JVET_P1004_REMOVE_BRICKS bool m_rectSliceFlag; int m_numSlicesInPicMinus1; std::vector<int> m_topLeftBrickIdx; @@ -509,6 +527,7 @@ protected: int m_signalledSliceIdLengthMinus1; std::vector<int> m_sliceId; BrickSplitMap m_brickSplitMap; +#endif HashType m_decodedPictureHashSEIType; bool m_bufferingPeriodSEIEnabled; @@ -727,8 +746,10 @@ protected: public: EncCfg() +#if !JVET_P1004_REMOVE_BRICKS : m_tileColumnWidth() , m_tileRowHeight() +#endif { } @@ -1319,6 +1340,29 @@ public: uint32_t getDeltaQpRD () const { return m_uiDeltaQpRD; } bool getFastDeltaQp () const { return m_bFastDeltaQP; } +#if JVET_P1004_REMOVE_BRICKS + //====== Tiles and Slices ======== + void setNoPicPartitionFlag( bool b ) { m_noPicPartitionFlag = b; } + bool getNoPicPartitionFlag() { return m_noPicPartitionFlag; } + void setTileColWidths( std::vector<uint32_t> tileColWidths ) { m_tileColumnWidth = tileColWidths; } + const std::vector<uint32_t>* getTileColWidths() const { return &m_tileColumnWidth; } + void setTileRowHeights( std::vector<uint32_t> tileRowHeights ) { m_tileRowHeight = tileRowHeights; } + const std::vector<uint32_t>* getTileRowHeights() const { return &m_tileRowHeight; } + void setRectSliceFlag( bool b ) { m_rectSliceFlag = b; } + bool getRectSliceFlag() { return m_rectSliceFlag; } + void setNumSlicesInPic( uint32_t u ) { m_numSlicesInPic = u; } + uint32_t getNumSlicesInPic() { return m_numSlicesInPic; } + void setTileIdxDeltaPresentFlag( bool b ) { m_tileIdxDeltaPresentFlag = b; } + bool getTileIdxDeltaPresentFlag() { return m_tileIdxDeltaPresentFlag; } + void setRectSlices( std::vector<RectSlice> rectSlices ) { m_rectSlices = rectSlices; } + const std::vector<RectSlice>* getRectSlices() const { return &m_rectSlices; } + void setRasterSliceSizes( std::vector<uint32_t> rasterSliceSizes ) { m_rasterSliceSize = rasterSliceSizes; } + const std::vector<uint32_t>* getRasterSliceSizes() const { return &m_rasterSliceSize; } + void setLFCrossTileBoundaryFlag( bool b ) { m_bLFCrossTileBoundaryFlag = b; } + bool getLFCrossTileBoundaryFlag() { return m_bLFCrossTileBoundaryFlag; } + void setLFCrossSliceBoundaryFlag( bool b ) { m_bLFCrossSliceBoundaryFlag = b; } + bool getLFCrossSliceBoundaryFlag() { return m_bLFCrossSliceBoundaryFlag; } +#else //====== Slice ======== void setSliceMode ( SliceConstraint i ) { m_sliceMode = i; } void setSliceArgument ( int i ) { m_sliceArgument = i; } @@ -1331,6 +1375,7 @@ public: int getSliceSegmentArgument () { return m_sliceSegmentArgument;} void setLFCrossSliceBoundaryFlag ( bool bValue ) { m_bLFCrossSliceBoundaryFlag = bValue; } bool getLFCrossSliceBoundaryFlag () { return m_bLFCrossSliceBoundaryFlag; } +#endif void setUseSAO (bool bVal) { m_bUseSAO = bVal; } bool getUseSAO () { return m_bUseSAO; } @@ -1348,6 +1393,7 @@ public: void setSaoGreedyMergeEnc (bool val) { m_saoGreedyMergeEnc = val; } bool getSaoGreedyMergeEnc () { return m_saoGreedyMergeEnc; } +#if !JVET_P1004_REMOVE_BRICKS void setLFCrossTileBoundaryFlag ( bool val ) { m_loopFilterAcrossBricksEnabledFlag = val; } bool getLFCrossTileBoundaryFlag () { return m_loopFilterAcrossBricksEnabledFlag; } void setTileUniformSpacingFlag ( bool b ) { m_tileUniformSpacingFlag = b; } @@ -1385,6 +1431,7 @@ public: void setBrickSplitMap(const BrickSplitMap& val) { m_brickSplitMap = val; } void xCheckGSParameters(); +#endif void setEntropyCodingSyncEnabledFlag(bool b) { m_entropyCodingSyncEnabledFlag = b; } bool getEntropyCodingSyncEnabledFlag() const { return m_entropyCodingSyncEnabledFlag; } void setDecodedPictureHashSEIType(HashType m) { m_decodedPictureHashSEIType = m; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 9a3db3edc..d37f058c4 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1049,7 +1049,11 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #endif if (bestCS->cus.size() == 1) // no partition { +#if JVET_P1004_REMOVE_BRICKS + CHECK(bestCS->cus[0]->tileIdx != bestCS->pps->getTileIdx(bestCS->area.lumaPos()), "Wrong tile index!"); +#else CHECK(bestCS->cus[0]->tileIdx != bestCS->picture->brickMap->getBrickIdxRsMap(bestCS->area.lumaPos()), "Wrong tile index!"); +#endif if (bestCS->cus[0]->predMode == MODE_PLT) { for (int i = compBegin; i < (compBegin + numComp); i++) @@ -1711,6 +1715,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, // The exception is each slice / slice-segment must have at least one CTU. if (bestCS->cost != MAX_DOUBLE) { +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *tempCS->picture->brickMap; const uint32_t CtuAddr = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) ); const bool isEndOfSlice = slice.getSliceMode() == FIXED_NUMBER_OF_BYTES @@ -1722,6 +1727,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, bestCS->cost = MAX_DOUBLE; bestCS->costDbOffset = 0; } +#endif } else { @@ -1860,7 +1866,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.predMode = MODE_INTRA; @@ -2211,7 +2221,11 @@ void EncCu::xCheckPLT(CodingStructure *&tempCS, CodingStructure *&bestCS, Partit CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType); partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos()); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap(tempCS->area.lumaPos()); +#endif cu.skip = false; cu.mmvdSkip = false; cu.predMode = MODE_PLT; @@ -2409,7 +2423,11 @@ void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&b partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos()); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap(tempCS->area.lumaPos()); +#endif cu.skip = false; cu.predMode = MODE_INTER; cu.transQuantBypass = encTestMode.lossless; @@ -2470,7 +2488,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif PredictionUnit pu( tempCS->area ); pu.cu = &cu; @@ -2590,7 +2612,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) * FRAC_BITS_SCALE; partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.triangle = false; @@ -2871,7 +2897,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.triangle = false; @@ -3095,7 +3125,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.triangle = true; cu.mmvdSkip = false; cu.GBiIdx = GBI_DEFAULT; @@ -3133,7 +3167,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_INTER; cu.transQuantBypass = encTestMode.lossless; @@ -3247,7 +3285,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_INTER; cu.transQuantBypass = encTestMode.lossless; @@ -3323,7 +3365,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.mmvdSkip = false; PredictionUnit pu( tempCS->area ); @@ -3378,7 +3424,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.affine = true; cu.predMode = MODE_INTER; @@ -3491,7 +3541,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.affine = true; cu.predMode = MODE_INTER; @@ -3614,7 +3668,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct cu.cs = tempCS; cu.predMode = MODE_IBC; cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif PredictionUnit pu(tempCS->area); pu.cu = &cu; pu.cs = tempCS; @@ -3653,7 +3711,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3772,7 +3834,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3856,7 +3922,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3994,7 +4064,11 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; //cu.affine @@ -4131,7 +4205,11 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_P1004_REMOVE_BRICKS + cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; //cu.affine diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 4040bfe13..ea632aa70 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -2784,9 +2784,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, // Allocate some coders, now the number of tiles are known. const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus; +#if JVET_P1004_REMOVE_BRICKS + const int numSubstreamsColumns = pcSlice->getPPS()->getNumTileColumns(); + const int numSubstreamRows = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRows()); + const int numSubstreams = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->cs->pps->getNumSlicesInPic()); +#else const int numSubstreamsColumns = (pcSlice->getPPS()->getNumTileColumnsMinus1() + 1); const int numSubstreamRows = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRowsMinus1() + 1); const int numSubstreams = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->brickMap->bricks.size()); +#endif std::vector<OutputBitstream> substreamsOut(numSubstreams); #if ENABLE_QPA @@ -2896,18 +2902,28 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, { DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) ); +#if JVET_P1004_REMOVE_BRICKS + for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ ) + { + pcSlice->setSliceMap( pcPic->cs->pps->getSliceMap( sliceIdx ) ); +#else pcSlice->setSliceCurStartCtuTsAddr( 0 ); uint32_t sliceIdx = 0; const BrickMap& tileMap = *(pcPic->brickMap); for(uint32_t nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; ) { +#endif m_pcSliceEncoder->precompressSlice( pcPic ); m_pcSliceEncoder->compressSlice ( pcPic, false, false ); +#if JVET_P1004_REMOVE_BRICKS + if(sliceIdx < pcPic->cs->pps->getNumSlicesInPic() - 1) +#else const uint32_t curSliceEnd = pcSlice->getSliceCurEndCtuTsAddr(); pcSlice->setSliceIndex(sliceIdx); if(curSliceEnd < numberOfCtusInFrame) +#endif { uint32_t independentSliceIdx = pcSlice->getIndependentSliceIdx(); pcPic->allocateNewSlice(); @@ -2916,6 +2932,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcSlice = pcPic->slices[uiNumSliceSegments]; CHECK(!(pcSlice->getPPS() != 0), "Unspecified error"); pcSlice->copySliceInfo(pcPic->slices[uiNumSliceSegments - 1]); +#if !JVET_P1004_REMOVE_BRICKS sliceIdx++; if (pcSlice->getPPS()->getRectSliceFlag()) { @@ -2933,12 +2950,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, { pcSlice->setSliceCurStartCtuTsAddr(curSliceEnd); } +#endif pcSlice->setSliceBits(0); independentSliceIdx++; pcSlice->setIndependentSliceIdx(independentSliceIdx); uiNumSliceSegments++; } +#if !JVET_P1004_REMOVE_BRICKS nextCtuTsAddr = curSliceEnd; +#endif } duData.clear(); @@ -3307,7 +3327,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, std::size_t binCountsInNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10) std::size_t numBytesInVclNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10) +#if JVET_P1004_REMOVE_BRICKS + for(uint32_t sliceSegmentIdxCount = 0; sliceSegmentIdxCount < pcPic->cs->pps->getNumSlicesInPic(); sliceSegmentIdxCount++ ) +#else for(uint32_t sliceSegmentStartCtuTsAddr = 0, sliceSegmentIdxCount = 0; sliceSegmentStartCtuTsAddr < numberOfCtusInFrame; sliceSegmentIdxCount++, sliceSegmentStartCtuTsAddr = pcSlice->getSliceCurEndCtuTsAddr()) +#endif { pcSlice = pcPic->slices[sliceSegmentIdxCount]; if(sliceSegmentIdxCount > 0 && pcSlice->getSliceType()!= I_SLICE) diff --git a/source/Lib/EncoderLib/EncHRD.cpp b/source/Lib/EncoderLib/EncHRD.cpp index 5ed238f8f..794b63748 100644 --- a/source/Lib/EncoderLib/EncHRD.cpp +++ b/source/Lib/EncoderLib/EncHRD.cpp @@ -57,7 +57,11 @@ int EncHRD::xCalcScale(int x) void EncHRD::initHRDParameters (EncCfg* encCfg) { +#if JVET_P1004_REMOVE_BRICKS + bool useSubCpbParams = encCfg->getNoPicPartitionFlag() == false; +#else bool useSubCpbParams = (encCfg->getSliceMode() > 0) || (encCfg->getSliceSegmentMode() > 0); +#endif int bitRate = encCfg->getTargetBitrate(); # if U0132_TARGET_BITS_SATURATION int cpbSize = encCfg->getCpbSize(); diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index fe589b7c7..f08f77741 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -309,6 +309,11 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) conformanceWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) ); +#if JVET_P1004_REMOVE_BRICKS + // disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution) + m_noPicPartitionFlag = true; + +#endif pps.setConformanceWindow( conformanceWindow ); xInitPPS( pps, sps0 ); // will allocate memory for and initialize pps.pcv inside @@ -457,7 +462,9 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) #else picBg->finalInit( sps0, pps0, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif +#if !JVET_P1004_REMOVE_BRICKS pps0.setNumBricksInPic((int)picBg->brickMap->bricks.size()); +#endif picBg->allocateNewSlice(); picBg->createSpliceIdx(pps0.pcv->sizeInCtus); m_cGOPEncoder.setPicBg(picBg); @@ -708,8 +715,10 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu #else pcPicCurr->finalInit( *pSPS, *pPPS, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif +#if !JVET_P1004_REMOVE_BRICKS PPS *ptrPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); ptrPPS->setNumBricksInPic( (int)pcPicCurr->brickMap->bricks.size() ); +#endif pcPicCurr->poc = m_iPOCLast; @@ -1761,7 +1770,51 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setEntropyCodingSyncEnabledFlag( m_entropyCodingSyncEnabledFlag ); +#if JVET_P1004_REMOVE_BRICKS + pps.setNoPicPartitionFlag( m_noPicPartitionFlag ); + if( m_noPicPartitionFlag == false ) + { + pps.setLog2CtuSize( ceilLog2( sps.getCTUSize()) ); + pps.setNumExpTileColumns( (uint32_t) m_tileColumnWidth.size() ); + pps.setNumExpTileRows( (uint32_t) m_tileRowHeight.size() ); + pps.setTileColumnWidths( m_tileColumnWidth ); + pps.setTileRowHeights( m_tileRowHeight ); + pps.initTiles(); + pps.setRectSliceFlag( m_rectSliceFlag ); + if( m_rectSliceFlag ) + { + pps.setNumSlicesInPic( m_numSlicesInPic ); + pps.setTileIdxDeltaPresentFlag( m_tileIdxDeltaPresentFlag ); + pps.setRectSlices( m_rectSlices ); + pps.initRectSliceMap( ); + } + else + { + pps.initRasterSliceMap( m_rasterSliceSize ); + } + pps.setLoopFilterAcrossTilesEnabledFlag( m_bLFCrossTileBoundaryFlag ); + pps.setLoopFilterAcrossSlicesEnabledFlag( m_bLFCrossSliceBoundaryFlag ); + } + else + { + pps.setLog2CtuSize( ceilLog2( sps.getCTUSize()) ); + pps.setNumExpTileColumns(1); + pps.setNumExpTileRows(1); + pps.addTileColumnWidth( pps.getPicWidthInCtu( ) ); + pps.addTileRowHeight( pps.getPicHeightInCtu( ) ); + pps.initTiles(); + pps.setRectSliceFlag( 1 ); + pps.setNumSlicesInPic( 1 ); + pps.initRectSlices( ); + pps.setTileIdxDeltaPresentFlag( 0 ); + pps.setSliceTileIdx( 0, 0 ); + pps.initRectSliceMap( ); + pps.setLoopFilterAcrossTilesEnabledFlag( true ); + pps.setLoopFilterAcrossSlicesEnabledFlag( true ); + } +#else pps.setSingleTileInPicFlag((m_iNumColumnsMinus1 == 0 && m_iNumRowsMinus1 == 0)); +#endif pps.setUseWP( m_useWeightedPred ); pps.setWPBiPred( m_useWeightedBiPred ); @@ -1827,10 +1880,12 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setNumRefIdxL1DefaultActive(bestPos); pps.setTransquantBypassEnabledFlag(getTransquantBypassEnabledFlag()); pps.setLog2MaxTransformSkipBlockSize(m_log2MaxTransformSkipBlockSize); +#if !JVET_P1004_REMOVE_BRICKS xInitPPSforTiles(pps); +#endif #if JVET_P1006_PICTURE_HEADER pps.setPictureHeaderExtensionPresentFlag(false); #else @@ -2150,6 +2205,7 @@ void EncLib::selectReferencePictureList(Slice* slice, int POCCurr, int GOPid, in slice->setRPL1(rpl1); } +#if !JVET_P1004_REMOVE_BRICKS void EncLib::xInitPPSforTiles(PPS &pps) { if ( (m_iNumColumnsMinus1==0) && (m_iNumRowsMinus1==0) ) @@ -2380,6 +2436,7 @@ void EncCfg::xCheckGSParameters() } } } +#endif void EncLib::setParamSetChanged(int spsId, int ppsId) { diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index 8045eb45b..ad7db2fae 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -193,7 +193,9 @@ protected: void xInitPPSforLT(PPS& pps); void xInitHrdParameters(SPS &sps); ///< initialize HRDParameters parameters +#if !JVET_P1004_REMOVE_BRICKS void xInitPPSforTiles (PPS &pps); +#endif void xInitRPL(SPS &sps, bool isFieldCoding); ///< initialize SPS from encoder options public: diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp index 4755f9c8a..8f01f19d0 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp @@ -838,7 +838,11 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn int ctuRsAddr = 0; #if ENABLE_QPA +#if JVET_P1004_REMOVE_BRICKS + CHECK ((chromaWeight > 0.0) && (cs.slice->getFirstCtuRsAddrInSlice() != 0), "incompatible start CTU address, must be 0"); +#else CHECK ((chromaWeight > 0.0) && (cs.slice->getSliceCurStartCtuTsAddr() != 0), "incompatible start CTU address, must be 0"); +#endif #endif for( uint32_t yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight ) @@ -1548,7 +1552,11 @@ void EncSampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructu #if JVET_P1006_PICTURE_HEADER bool isLoopFiltAcrossSlicePPS = cs.pps->getLoopFilterAcrossSlicesEnabledFlag(); #endif +#if JVET_P1004_REMOVE_BRICKS + bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag(); +#else bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag(); +#endif const int width = cs.pcv->maxCUWidth; const int height = cs.pcv->maxCUHeight; diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 0da1160a5..0fa4a2105 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -203,7 +203,11 @@ static double getAveragePictureEnergy (const CPelBuf picOrig, const uint32_t uBi } #endif +#if JVET_P1004_REMOVE_BRICKS +static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, Slice* const pcSlice, +#else static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, const uint32_t startAddr, const uint32_t boundingAddr, +#endif const int bitDepth, uint32_t &avgLumaValue) { const PreCalcValues& pcv = *pcPic->cs->pcv; @@ -212,20 +216,38 @@ 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; +#if JVET_P1004_REMOVE_BRICKS + avgLumaValue = (pcSlice != nullptr) ? 0 : (uint32_t)pcPic->getOrigBuf().Y().computeAvg(); +#else avgLumaValue = (startAddr < boundingAddr) ? 0 : (uint32_t)pcPic->getOrigBuf().Y().computeAvg(); +#endif if (ctuAddr >= 0) // luma { avgLumaValue = (uint32_t)pcPic->m_iOffsetCtu[ctuAddr]; } +#if JVET_P1004_REMOVE_BRICKS + else if (pcSlice != nullptr) +#else else if (startAddr < boundingAddr) +#endif { +#if JVET_P1004_REMOVE_BRICKS + for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { const uint32_t ctuRsAddr = pcPic->brickMap->getCtuBsToRsAddrMap (ctuTsAddr); +#endif avgLumaValue += pcPic->m_iOffsetCtu[ctuRsAddr]; } +#if JVET_P1004_REMOVE_BRICKS + avgLumaValue = (avgLumaValue + (pcSlice->getNumCtuInSlice() >> 1)) / pcSlice->getNumCtuInSlice(); +#else avgLumaValue = (avgLumaValue + ((boundingAddr - startAddr) >> 1)) / (boundingAddr - startAddr); +#endif } for (uint32_t comp = COMPONENT_Cb; comp < MAX_NUM_COMPONENT; comp++) @@ -279,7 +301,11 @@ static int applyQPAdaptationChroma (Picture* const pcPic, Slice* const pcSlice, int averageAdaptedLumaQP = Clip3 (0, MAX_QP, sliceQP); // mean slice QP #endif +#if JVET_P1004_REMOVE_BRICKS + averageAdaptedLumaQP += getGlaringColorQPOffset (pcPic, -1 /*ctuRsAddr*/, nullptr /*pcSlice*/, bitDepth, meanLuma); +#else averageAdaptedLumaQP += getGlaringColorQPOffset (pcPic, -1 /*ctuRsAddr*/, 0 /*startAddr*/, 0 /*boundingAddr*/, bitDepth, meanLuma); +#endif if (averageAdaptedLumaQP > MAX_QP #if SHARP_LUMA_DELTA_QP @@ -659,8 +685,10 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr } rpcSlice->setTLayer( pcPic->layer ); +#if !JVET_P1004_REMOVE_BRICKS rpcSlice->setSliceMode ( m_pcCfg->getSliceMode() ); rpcSlice->setSliceArgument ( m_pcCfg->getSliceArgument() ); +#endif #if !JVET_P1006_PICTURE_HEADER rpcSlice->setMaxNumMergeCand ( m_pcCfg->getMaxNumMergeCand() ); rpcSlice->setMaxNumAffineMergeCand( m_pcCfg->getMaxNumAffineMergeCand() ); @@ -794,12 +822,18 @@ void EncSlice::resetQP( Picture* pic, int sliceQP, double lambda ) #if ENABLE_QPA static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, const PreCalcValues& pcv, +#if JVET_P1004_REMOVE_BRICKS + const bool useSharpLumaDQP, +#else const uint32_t startAddr, const uint32_t boundingAddr, const bool useSharpLumaDQP, +#endif const bool useFrameWiseQPA, const int previouslyAdaptedLumaQP = -1) { const int bitDepth = pcSlice->getSPS()->getBitDepth (CHANNEL_TYPE_LUMA); const int iQPIndex = pcSlice->getSliceQp(); // initial QP index for current slice, used in following loops +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *pcPic->brickMap; +#endif bool sliceQPModified = false; uint32_t meanLuma = MAX_UINT; double hpEnerAvg = 0.0; @@ -808,9 +842,15 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, if (!useFrameWiseQPA || previouslyAdaptedLumaQP < 0) // mean visual activity value and luma value in each CTU #endif { +#if JVET_P1004_REMOVE_BRICKS + for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#endif const Position pos ((ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight); const CompArea ctuArea = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight)), pcPic->Y()); const CompArea fltArea = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x > 0 ? pos.x - 1 : 0, pos.y > 0 ? pos.y - 1 : 0, pcv.maxCUWidth + (pos.x > 0 ? 2 : 1), pcv.maxCUHeight + (pos.y > 0 ? 2 : 1))), pcPic->Y()); @@ -824,7 +864,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, pcPic->m_iOffsetCtu[ctuRsAddr] = pcPic->getOrigBuf (ctuArea).computeAvg(); } +#if JVET_P1004_REMOVE_BRICKS + hpEnerAvg /= double (pcSlice->getNumCtuInSlice()); +#else hpEnerAvg /= double (boundingAddr - startAddr); +#endif } #if GLOBAL_AVERAGING const double hpEnerPic = 1.0 / getAveragePictureEnergy (pcPic->getOrigBuf().Y(), bitDepth); // inverse, speed @@ -838,7 +882,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, if (isChromaEnabled (pcPic->chromaFormat) && (iQPIndex < MAX_QP) && (previouslyAdaptedLumaQP < 0)) { +#if JVET_P1004_REMOVE_BRICKS + iQPFixed += getGlaringColorQPOffset (pcPic, -1 /*ctuRsAddr*/, pcSlice, bitDepth, meanLuma); +#else iQPFixed += getGlaringColorQPOffset (pcPic, -1 /*ctuRsAddr*/, startAddr, boundingAddr, bitDepth, meanLuma); +#endif if (iQPFixed > MAX_QP #if SHARP_LUMA_DELTA_QP @@ -855,13 +903,23 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, { meanLuma = 0; +#if JVET_P1004_REMOVE_BRICKS + for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#endif meanLuma += pcPic->m_iOffsetCtu[ctuRsAddr]; // CTU mean } +#if JVET_P1004_REMOVE_BRICKS + meanLuma = (meanLuma + (pcSlice->getNumCtuInSlice() >> 1)) / pcSlice->getNumCtuInSlice(); +#else meanLuma = (meanLuma + ((boundingAddr - startAddr) >> 1)) / (boundingAddr - startAddr); +#endif } iQPFixed = Clip3 (0, MAX_QP, iQPFixed + lumaDQPOffset (meanLuma, bitDepth)); } @@ -883,18 +941,30 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, sliceQPModified = true; } +#if JVET_P1004_REMOVE_BRICKS + for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#endif pcPic->m_iOffsetCtu[ctuRsAddr] = (Pel)iQPFixed; // fixed QPs } } else // CTU-wise QPA { +#if JVET_P1004_REMOVE_BRICKS + for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#endif int iQPAdapt = Clip3 (0, MAX_QP, iQPIndex + apprI3Log2 (pcPic->m_uEnerHpCtu[ctuRsAddr] * hpEnerPic)); @@ -904,7 +974,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, if (isChromaEnabled (pcPic->chromaFormat)) { +#if JVET_P1004_REMOVE_BRICKS + iQPAdapt += getGlaringColorQPOffset (pcPic, (int)ctuRsAddr, nullptr, bitDepth, meanLuma); +#else iQPAdapt += getGlaringColorQPOffset (pcPic, (int)ctuRsAddr, startAddr, boundingAddr, bitDepth, meanLuma); +#endif if (iQPAdapt > MAX_QP #if SHARP_LUMA_DELTA_QP @@ -993,7 +1067,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, { pcPic->m_iOffsetCtu[ctuRsAddr - 1] = (Pel)iQPAdapt; } +#if JVET_P1004_REMOVE_BRICKS + if ((ctuIdx == pcSlice->getNumCtuInSlice() - 1) && (ctuRsAddr > pcv.widthInCtus)) // last CTU in the given slice +#else if ((ctuTsAddr == boundingAddr - 1) && (ctuRsAddr > pcv.widthInCtus)) // last CTU in the given slice +#endif { iQPAdapt = std::min (pcPic->m_iOffsetCtu[ctuRsAddr - 1], pcPic->m_iOffsetCtu[ctuRsAddr - pcv.widthInCtus]); if (pcPic->m_iOffsetCtu[ctuRsAddr] < (Pel)iQPAdapt) @@ -1157,11 +1235,13 @@ void EncSlice::precompressSlice( Picture* pcPic ) Slice* pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if !JVET_P1004_REMOVE_BRICKS if (pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES) { // TODO: investigate use of average cost per CTU so that this Slice Mode can be used. THROW( "Unable to optimise Slice-level QP if Slice Mode is set to FIXED_NUMBER_OF_BYTES\n" ); } +#endif double dPicRdCostBest = MAX_DOUBLE; uint32_t uiQpIdxBest = 0; @@ -1218,19 +1298,27 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir { double iSumHadSlice = 0; Slice * const pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if !JVET_P1004_REMOVE_BRICKS const BrickMap &tileMap = *pcPic->brickMap; +#endif const PreCalcValues& pcv = *pcPic->cs->pcv; const SPS &sps = *(pcSlice->getSPS()); const int shift = sps.getBitDepth(CHANNEL_TYPE_LUMA)-8; const int offset = (shift>0)?(1<<(shift-1)):0; +#if JVET_P1004_REMOVE_BRICKS + for( uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++ ) + { + uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else uint32_t startCtuTsAddr, boundingCtuTsAddr; xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic ); for( uint32_t ctuTsAddr = startCtuTsAddr, ctuRsAddr = tileMap.getCtuBsToRsAddrMap( startCtuTsAddr); ctuTsAddr < boundingCtuTsAddr; ctuRsAddr = tileMap.getCtuBsToRsAddrMap(++ctuTsAddr) ) { +#endif Position pos( (ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight); const int height = std::min( pcv.maxCUHeight, pcv.lumaHeight - pos.y ); @@ -1253,6 +1341,7 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c // effectively disabling the slice-segment-mode. Slice* const pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if !JVET_P1004_REMOVE_BRICKS uint32_t startCtuTsAddr; uint32_t boundingCtuTsAddr; @@ -1261,6 +1350,7 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c { boundingCtuTsAddr = pcSlice->getSliceCurEndCtuTsAddr(); } +#endif // initialize cost values - these are used by precompressSlice (they should be parameters). m_uiPicTotalBits = 0; @@ -1294,6 +1384,7 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c if ( bWp_explicit ) { +#if !JVET_P1004_REMOVE_BRICKS //------------------------------------------------------------------------------ // Weighted Prediction implemented at Slice level. SliceMode=2 is not supported yet. //------------------------------------------------------------------------------ @@ -1301,6 +1392,7 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c { EXIT("Weighted Prediction is not yet supported with slice mode determined by max number of bins."); } +#endif xEstimateWPParamSlice( pcSlice, m_pcCfg->getWeightedPredictionMethod() ); pcSlice->initWpScaling(pcSlice->getSPS()); @@ -1320,16 +1412,29 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c cs.pcv = pcSlice->getPPS()->pcv; cs.fracBits = 0; +#if JVET_P1004_REMOVE_BRICKS + if( pcSlice->getFirstCtuRsAddrInSlice() == 0 && ( pcSlice->getPOC() != m_pcCfg->getSwitchPOC() || -1 == m_pcCfg->getDebugCTU() ) ) +#else if( startCtuTsAddr == 0 && ( pcSlice->getPOC() != m_pcCfg->getSwitchPOC() || -1 == m_pcCfg->getDebugCTU() ) ) +#endif { cs.initStructData (pcSlice->getSliceQp(), pcSlice->getPPS()->getTransquantBypassEnabledFlag()); } #if ENABLE_QPA +#if JVET_P1004_REMOVE_BRICKS + if (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl()) +#else if (m_pcCfg->getUsePerceptQPA() && !m_pcCfg->getUseRateCtrl() && (boundingCtuTsAddr > startCtuTsAddr)) +#endif { +#if JVET_P1004_REMOVE_BRICKS + if (applyQPAdaptation (pcPic, pcSlice, *cs.pcv, m_pcCfg->getLumaLevelToDeltaQPMapping().mode == LUMALVL_TO_DQP_NUM_MODES, + (m_pcCfg->getBaseQP() >= 38) || (m_pcCfg->getSourceWidth() <= 512 && m_pcCfg->getSourceHeight() <= 320), m_adaptedLumaQP)) +#else if (applyQPAdaptation (pcPic, pcSlice, *cs.pcv, startCtuTsAddr, boundingCtuTsAddr, m_pcCfg->getLumaLevelToDeltaQPMapping().mode == LUMALVL_TO_DQP_NUM_MODES, (m_pcCfg->getBaseQP() >= 38) || (m_pcCfg->getSourceWidth() <= 512 && m_pcCfg->getSourceHeight() <= 320), m_adaptedLumaQP)) +#endif { m_CABACEstimator->initCtxModels (*pcSlice); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM @@ -1340,7 +1445,11 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c } #endif pcPic->m_prevQP[0] = pcPic->m_prevQP[1] = pcSlice->getSliceQp(); +#if JVET_P1004_REMOVE_BRICKS + if (pcSlice->getFirstCtuRsAddrInSlice() == 0) +#else if (startCtuTsAddr == 0) +#endif { cs.currQP[0] = cs.currQP[1] = pcSlice->getSliceQp(); // cf code above } @@ -1363,21 +1472,33 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c bool bUseThreads = m_pcCfg->getNumWppThreads() > 1; if( bUseThreads ) { +#if JVET_P1004_REMOVE_BRICKS + CHECK( pcSlice->getFirstCtuRsAddrInSlice() != 0 || pcSlice->getNumCtuInSlice() != pcPic->cs->pcv->sizeInCtus, "not intended" ); +#else CHECK( startCtuTsAddr != 0 || boundingCtuTsAddr != pcPic->cs->pcv->sizeInCtus, "not intended" ); +#endif pcPic->cs->allocateVectorsAtPicLevel(); omp_set_num_threads( m_pcCfg->getNumWppThreads() + m_pcCfg->getNumWppExtraLines() ); #pragma omp parallel for schedule(static,1) if(bUseThreads) +#if JVET_P1004_REMOVE_BRICKS + for( int ctuTsAddr = 0; ctuTsAddr < pcSlice->getNumCtuInSlice(); ctuTsAddr += pcPic->cs->pcv->widthInCtus ) +#else for( int ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr += widthInCtus ) +#endif { // wpp thread start pcPic->scheduler.setWppThreadId(); #if ENABLE_SPLIT_PARALLELISM pcPic->scheduler.setSplitThreadId( 0 ); #endif +#if JVET_P1004_REMOVE_BRICKS + encodeCtus( pcPic, bCompressEntireSlice, bFastDeltaQP, m_pcLib ); +#else encodeCtus( pcPic, bCompressEntireSlice, bFastDeltaQP, ctuTsAddr, ctuTsAddr + widthInCtus, m_pcLib ); +#endif // wpp thread stop } } @@ -1391,7 +1512,11 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c m_pcInterSearch->resetAffineMVList(); m_pcInterSearch->resetUniMvList(); ::memset(g_isReusedUniMVsFilled, 0, sizeof(g_isReusedUniMVsFilled)); +#if JVET_P1004_REMOVE_BRICKS + encodeCtus( pcPic, bCompressEntireSlice, bFastDeltaQP, m_pcLib ); +#else encodeCtus( pcPic, bCompressEntireSlice, bFastDeltaQP, startCtuTsAddr, boundingCtuTsAddr, m_pcLib ); +#endif if (checkPLTRatio) m_pcLib->checkPltStats( pcPic ); } @@ -1401,7 +1526,9 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32 Slice* pcSlice = cs.slice; const PreCalcValues& pcv = *cs.pcv; const uint32_t widthInCtus = pcv.widthInCtus; +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *pcPic->brickMap; +#endif const uint32_t hashThreshold = 20; uint32_t totalCtu = 0; uint32_t hashRatio = 0; @@ -1411,9 +1538,15 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32 return; } +#if JVET_P1004_REMOVE_BRICKS + for ( uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++ ) + { + const uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else for ( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) { const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap( ctuTsAddr ); +#endif const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; @@ -1492,13 +1625,19 @@ void setJointCbCrModes( CodingStructure& cs, const Position topLeftLuma, const S } +#if JVET_P1004_REMOVE_BRICKS +void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, EncLib* pEncLib ) +#else void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr, EncLib* pEncLib ) +#endif { CodingStructure& cs = *pcPic->cs; Slice* pcSlice = cs.slice; const PreCalcValues& pcv = *cs.pcv; const uint32_t widthInCtus = pcv.widthInCtus; +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *pcPic->brickMap; +#endif #if ENABLE_QPA const int iQPIndex = pcSlice->getSliceQpBase(); #endif @@ -1555,6 +1694,12 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons } #endif +#if JVET_P1004_REMOVE_BRICKS + // for every CTU in the slice + for( uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++ ) + { + const int32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment) uint32_t startSliceRsRow = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) / widthInCtus; uint32_t startSliceRsCol = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) % widthInCtus; @@ -1567,10 +1712,13 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons ((ctuRsAddr / widthInCtus) < startSliceRsRow || (ctuRsAddr / widthInCtus) > endSliceRsRow || (ctuRsAddr % widthInCtus) < startSliceRsCol || (ctuRsAddr % widthInCtus) > endSliceRsCol)) continue; +#endif // update CABAC state +#if !JVET_P1004_REMOVE_BRICKS const uint32_t firstCtuRsAddrOfTile = tileMap.bricks[tileMap.getBrickIdxRsMap(ctuRsAddr)].getFirstCtuRsAddr(); const uint32_t tileXPosInCtus = firstCtuRsAddrOfTile % widthInCtus; +#endif const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; @@ -1579,7 +1727,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) ); if( pCfg->getSwitchPOC() != pcPic->poc || -1 == pCfg->getDebugCTU() ) +#if JVET_P1004_REMOVE_BRICKS + if ((cs.slice->getSliceType() != I_SLICE || cs.sps->getIBCFlag()) && cs.pps->ctuIsTileColBd( ctuXPosInCtus )) +#else if ((cs.slice->getSliceType() != I_SLICE || cs.sps->getIBCFlag()) && ctuXPosInCtus == tileXPosInCtus) +#endif { cs.motionLut.lut.resize(0); cs.motionLut.lutIbc.resize(0); @@ -1589,18 +1741,30 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons pcPic->scheduler.wait( ctuXPosInCtus, ctuYPosInCtus ); #endif +#if JVET_P1004_REMOVE_BRICKS + if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && cs.pps->ctuIsTileRowBd( ctuYPosInCtus )) +#else if (ctuRsAddr == firstCtuRsAddrOfTile) +#endif { pCABACWriter->initCtxModels( *pcSlice ); cs.resetPrevPLT(cs.prevPLT); prevQP[0] = prevQP[1] = pcSlice->getSliceQp(); } +#if JVET_P1004_REMOVE_BRICKS + else if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && pEncLib->getEntropyCodingSyncEnabledFlag()) +#else else if (ctuXPosInCtus == tileXPosInCtus && pEncLib->getEntropyCodingSyncEnabledFlag()) +#endif { // reset and then update contexts to the state at the end of the top CTU (if within current slice and tile). pCABACWriter->initCtxModels( *pcSlice ); cs.resetPrevPLT(cs.prevPLT); +#if JVET_P1004_REMOVE_BRICKS + if( cs.getCURestricted( pos.offset(0, -1), pos, pcSlice->getIndependentSliceIdx(), cs.pps->getTileIdx( pos ), CH_L ) ) +#else if( cs.getCURestricted( pos.offset(0, -1), pos, pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#endif { // Top is available, we use it. pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState; @@ -1688,7 +1852,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons } #endif +#if JVET_P1004_REMOVE_BRICKS + bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuIdx == 0; +#else bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuTsAddr == startCtuTsAddr; +#endif if( updateGbiCodingOrder ) { resetGbiCodingOrder(false, cs); @@ -1725,6 +1893,7 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons pCABACWriter->coding_tree_unit( cs, ctuArea, prevQP, ctuRsAddr, true, true ); const int numberOfWrittenBits = int( pCABACWriter->getEstFracBits() >> SCALE_BITS ); +#if !JVET_P1004_REMOVE_BRICKS // Calculate if this CTU puts us over slice bit size. // cannot terminate if current slice/slice-segment would be 0 Ctu in size, const uint32_t validEndOfSliceCtuTsAddr = ctuTsAddr + (ctuTsAddr == startCtuTsAddr ? 1 : 0); @@ -1739,6 +1908,7 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons break; } +#endif #if ENABLE_WPP_PARALLELISM || ENABLE_SPLIT_PARALLELISM #pragma omp critical #endif @@ -1748,7 +1918,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons #endif // Store probabilities of first CTU in line into buffer - used only if wavefront-parallel-processing is enabled. +#if JVET_P1004_REMOVE_BRICKS + if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && pEncLib->getEntropyCodingSyncEnabledFlag() ) +#else if( ctuXPosInCtus == tileXPosInCtus && pEncLib->getEntropyCodingSyncEnabledFlag() ) +#endif { pEncLib->m_entropyCodingSyncContextState = pCABACWriter->getCtx(); } @@ -1834,9 +2008,11 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui { Slice *const pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if !JVET_P1004_REMOVE_BRICKS const BrickMap& tileMap = *pcPic->brickMap; const uint32_t startCtuTsAddr = pcSlice->getSliceCurStartCtuTsAddr(); const uint32_t boundingCtuTsAddr = pcSlice->getSliceCurEndCtuTsAddr(); +#endif const bool wavefrontsEnabled = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag(); @@ -1852,12 +2028,20 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui const PreCalcValues& pcv = *cs.pcv; const uint32_t widthInCtus = pcv.widthInCtus; +#if !JVET_P1004_REMOVE_BRICKS uint32_t startSliceRsRow = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) / widthInCtus; uint32_t startSliceRsCol = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) % widthInCtus; uint32_t endSliceRsRow = tileMap.getCtuBsToRsAddrMap(boundingCtuTsAddr - 1) / widthInCtus; uint32_t endSliceRsCol = tileMap.getCtuBsToRsAddrMap(boundingCtuTsAddr - 1) % widthInCtus; +#endif uint32_t uiSubStrm = 0; +#if JVET_P1004_REMOVE_BRICKS + // for every CTU in the slice... + for( uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx++ ) + { + const uint32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx ); +#else // for every CTU in the slice segment... for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) @@ -1870,6 +2054,7 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui continue; const uint32_t firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); const uint32_t tileXPosInCtus = firstCtuRsAddrOfTile % widthInCtus; +#endif const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; @@ -1880,30 +2065,54 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui m_CABACWriter->initBitstream( &pcSubstreams[uiSubStrm] ); // set up CABAC contexts' state for this CTU +#if JVET_P1004_REMOVE_BRICKS + if ( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && cs.pps->ctuIsTileRowBd( ctuYPosInCtus ) ) +#else if (ctuRsAddr == firstCtuRsAddrOfTile) +#endif { +#if JVET_P1004_REMOVE_BRICKS + if (ctuIdx != 0) // if it is the first CTU, then the entropy coder has already been reset +#else if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset +#endif { m_CABACWriter->initCtxModels( *pcSlice ); cs.resetPrevPLT(cs.prevPLT); } } +#if JVET_P1004_REMOVE_BRICKS + else if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && wavefrontsEnabled) +#else else if (ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled) +#endif { // Synchronize cabac probabilities with upper CTU if it's available and at the start of a line. +#if JVET_P1004_REMOVE_BRICKS + if (ctuIdx != 0) // if it is the first CTU, then the entropy coder has already been reset +#else if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset +#endif { m_CABACWriter->initCtxModels( *pcSlice ); cs.resetPrevPLT(cs.prevPLT); } +#if JVET_P1004_REMOVE_BRICKS + if( cs.getCURestricted( pos.offset( 0, -1 ), pos, pcSlice->getIndependentSliceIdx(), cs.pps->getTileIdx( pos ), CH_L ) ) +#else if( cs.getCURestricted( pos.offset( 0, -1 ), pos, pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#endif { // Top is available, so use it. m_CABACWriter->getCtx() = m_entropyCodingSyncContextState; } } +#if JVET_P1004_REMOVE_BRICKS + bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuIdx == 0; +#else bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuTsAddr == startCtuTsAddr; +#endif if( updateGbiCodingOrder ) { resetGbiCodingOrder(false, cs); @@ -1912,23 +2121,42 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui m_CABACWriter->coding_tree_unit( cs, ctuArea, pcPic->m_prevQP, ctuRsAddr ); // store probabilities of first CTU in line into buffer +#if JVET_P1004_REMOVE_BRICKS + if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && wavefrontsEnabled ) +#else if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled ) +#endif { m_entropyCodingSyncContextState = m_CABACWriter->getCtx(); } // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row): +#if JVET_P1004_REMOVE_BRICKS + bool isLastCTUsinSlice = ctuIdx == pcSlice->getNumCtuInSlice()-1; + bool isLastCTUinTile = !isLastCTUsinSlice && cs.pps->getTileIdx( ctuRsAddr ) != cs.pps->getTileIdx( pcSlice->getCtuAddrInSlice( ctuIdx + 1 ) ); + bool isLastCTUinWPP = !isLastCTUsinSlice && !isLastCTUinTile && wavefrontsEnabled && cs.pps->ctuIsTileColBd( pcSlice->getCtuAddrInSlice( ctuIdx + 1 ) % cs.pps->getPicWidthInCtu() ); + if (isLastCTUsinSlice || isLastCTUinTile || isLastCTUinWPP ) // this the the last CTU of the slice, tile, or WPP +#else bool isLastCTUinBrick = tileMap.getBrickIdxBsMap(ctuTsAddr) != tileMap.getBrickIdxBsMap(ctuTsAddr + 1); bool isLastCTUinWPP = wavefrontsEnabled && (((ctuRsAddr + 1) % widthInCtus) == tileXPosInCtus); bool isMoreCTUsinSlice = ctuRsAddr != tileMap.getCtuBsToRsAddrMap(boundingCtuTsAddr - 1); if (isLastCTUinBrick || isLastCTUinWPP || !isMoreCTUsinSlice) // this the the last CTU of either tile/brick/WPP/slice +#endif { +#if JVET_P1004_REMOVE_BRICKS + m_CABACWriter->end_of_slice(); // end_of_slice_one_bit, end_of_tile_one_bit, or end_of_subset_one_bit +#else m_CABACWriter->end_of_slice(); //This is actually end_of_brick_one_bit or end_of_subset_one_bit +#endif // Byte-alignment in slice_data() when new tile pcSubstreams[uiSubStrm].writeByteAlignment(); +#if JVET_P1004_REMOVE_BRICKS + if (!isLastCTUsinSlice) //Byte alignment only when it is not the last substream in the slice +#else if (isMoreCTUsinSlice) //Byte alignment only when it is not the last substream in the slice +#endif { // write sub-stream size pcSlice->addSubstreamSize((pcSubstreams[uiSubStrm].getNumberOfWrittenBits() >> 3) + pcSubstreams[uiSubStrm].countStartCodeEmulations()); @@ -1950,6 +2178,7 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui } +#if !JVET_P1004_REMOVE_BRICKS void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice, uint32_t &boundingCtuTSAddrSlice, bool &haveReachedTileBoundary, Picture* pcPic, const int sliceMode, const int sliceArgument) { @@ -2119,6 +2348,7 @@ void EncSlice::xDetermineStartAndBoundingCtuTsAddr ( uint32_t& startCtuTsAddr, startCtuTsAddr = startCtuTsAddrSlice; boundingCtuTsAddr = boundingCtuTsAddrSlice; } +#endif double EncSlice::xGetQPValueAccordingToLambda ( double lambda ) { diff --git a/source/Lib/EncoderLib/EncSlice.h b/source/Lib/EncoderLib/EncSlice.h index 07f157a91..869219471 100644 --- a/source/Lib/EncoderLib/EncSlice.h +++ b/source/Lib/EncoderLib/EncSlice.h @@ -104,11 +104,13 @@ public: #endif void setUpLambda( Slice* slice, const double dLambda, int iQP ); +#if !JVET_P1004_REMOVE_BRICKS private: void calculateBoundingCtuTsAddrForSlice( uint32_t &startCtuTSAddrSlice, uint32_t &boundingCtuTSAddrSlice, bool &haveReachedTileBoundary, Picture* pcPic, const int sliceMode, const int sliceArgument ); public: +#endif #if ENABLE_QPA int m_adaptedLumaQP; @@ -137,7 +139,11 @@ public: #if ENABLE_WPP_PARALLELISM static #endif +#if JVET_P1004_REMOVE_BRICKS + void encodeCtus ( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, EncLib* pcEncLib ); +#else void encodeCtus ( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr, EncLib* pcEncLib ); +#endif void checkDisFracMmvd ( Picture* pcPic, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr ); #if JVET_P1006_PICTURE_HEADER void setJointCbCrModes( CodingStructure& cs, const Position topLeftLuma, const Size sizeLuma ); @@ -147,7 +153,9 @@ public: void setSearchRange ( Slice* pcSlice ); ///< set ME range adaptively EncCu* getCUEncoder () { return m_pcCuEncoder; } ///< CU encoder +#if !JVET_P1004_REMOVE_BRICKS void xDetermineStartAndBoundingCtuTsAddr ( uint32_t& startCtuTsAddr, uint32_t& boundingCtuTsAddr, Picture* pcPic ); +#endif uint32_t getSliceSegmentIdx () { return m_uiSliceSegmentIdx; } void setSliceSegmentIdx (uint32_t i) { m_uiSliceSegmentIdx = i; } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index c667b2810..e997f9d81 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -8259,23 +8259,40 @@ bool InterSearch::searchBv(PredictionUnit& pu, int xPos, int yPos, int width, in return false; } +#if JVET_P1004_REMOVE_BRICKS + unsigned curTileIdx = pu.cs->pps->getTileIdx(pu.lumaPos()); + unsigned refTileIdx = pu.cs->pps->getTileIdx(Position(refLeftX, refTopY)); +#else unsigned curTileIdx = pu.cs->picture->brickMap->getBrickIdxRsMap(pu.lumaPos()); unsigned refTileIdx = pu.cs->picture->brickMap->getBrickIdxRsMap(Position(refLeftX, refTopY)); +#endif if (curTileIdx != refTileIdx) { return false; } +#if JVET_P1004_REMOVE_BRICKS + refTileIdx = pu.cs->pps->getTileIdx(Position(refLeftX, refBottomY)); +#else refTileIdx = pu.cs->picture->brickMap->getBrickIdxRsMap(Position(refLeftX, refBottomY)); +#endif if (curTileIdx != refTileIdx) { return false; } +#if JVET_P1004_REMOVE_BRICKS + refTileIdx = pu.cs->pps->getTileIdx(Position(refRightX, refTopY)); +#else refTileIdx = pu.cs->picture->brickMap->getBrickIdxRsMap(Position(refRightX, refTopY)); +#endif if (curTileIdx != refTileIdx) { return false; } +#if JVET_P1004_REMOVE_BRICKS + refTileIdx = pu.cs->pps->getTileIdx(Position(refRightX, refBottomY)); +#else refTileIdx = pu.cs->picture->brickMap->getBrickIdxRsMap(Position(refRightX, refBottomY)); +#endif if (curTileIdx != refTileIdx) { return false; diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index fa64ac94e..4aaee611a 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -221,7 +221,11 @@ void SEIEncoder::initSEIBufferingPeriod(SEIBufferingPeriod *bufferingPeriodSEI, } #if JVET_P0202_P0203_FIX_HRD_RELATED_SEI +#if JVET_P1004_REMOVE_BRICKS + bufferingPeriodSEI->m_bpDecodingUnitHrdParamsPresentFlag = m_pcCfg->getNoPicPartitionFlag() == false; +#else bufferingPeriodSEI->m_bpDecodingUnitHrdParamsPresentFlag = (m_pcCfg->getSliceMode() > 0) || (m_pcCfg->getSliceSegmentMode() > 0); +#endif bufferingPeriodSEI->m_decodingUnitCpbParamsInPicTimingSeiFlag = !m_pcCfg->getDecodingUnitInfoSEIEnabled(); #endif diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 8ba07f50c..d3d0f8f36 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -242,6 +242,74 @@ void HLSWriter::codePPS( const PPS* pcPPS, const SPS* pcSPS ) WRITE_CODE( pcPPS->getSubPicId(picIdx), pcPPS->getSubPicIdLen( ), "pps_subpic_id[i]" ); } } +#endif +#if JVET_P1004_REMOVE_BRICKS + + WRITE_FLAG( pcPPS->getNoPicPartitionFlag( ) ? 1 : 0, "no_pic_partition_flag" ); + if( !pcPPS->getNoPicPartitionFlag() ) + { + int colIdx, rowIdx; + + // CTU size - required to match size in SPS + WRITE_CODE( pcPPS->getLog2CtuSize() - 5, 2, "log2_pps_ctu_size_minus5" ); + + // number of explicit tile columns/rows + WRITE_UVLC( pcPPS->getNumExpTileColumns() - 1, "num_exp_tile_columns_minus1" ); + WRITE_UVLC( pcPPS->getNumExpTileRows() - 1, "num_exp_tile_rows_minus1" ); + + // tile sizes + for( colIdx = 0; colIdx < pcPPS->getNumExpTileColumns(); colIdx++ ) + { + WRITE_UVLC( pcPPS->getTileColumnWidth( colIdx ) - 1, "tile_column_width_minus1[i]" ); + } + for( rowIdx = 0; rowIdx < pcPPS->getNumExpTileRows(); rowIdx++ ) + { + WRITE_UVLC( pcPPS->getTileRowHeight( rowIdx ) - 1, "tile_row_height_minus1[i]" ); + } + + // rectangular slice signalling + WRITE_FLAG( pcPPS->getRectSliceFlag( ) ? 1 : 0, "rect_slice_flag"); + if( pcPPS->getRectSliceFlag() ) + { + WRITE_UVLC( pcPPS->getNumSlicesInPic( ) - 1, "num_slices_in_pic_minus1" ); + WRITE_FLAG( pcPPS->getTileIdxDeltaPresentFlag( ) ? 1 : 0, "tile_idx_delta_present_flag"); + + // write rectangular slice parameters + for( int i = 0; i < pcPPS->getNumSlicesInPic()-1; i++ ) + { + // complete tiles within a single slice + WRITE_UVLC( pcPPS->getSliceWidthInTiles( i ) - 1, "slice_width_in_tiles_minus1[i]" ); + WRITE_UVLC( pcPPS->getSliceHeightInTiles( i ) - 1, "slice_height_in_tiles_minus1[i]" ); + + // multiple slices within a single tile special case + if( pcPPS->getSliceWidthInTiles( i ) == 1 && pcPPS->getSliceHeightInTiles( i ) == 1 ) + { + WRITE_UVLC( pcPPS->getNumSlicesInTile( i ) - 1, "num_slices_in_tile_minus1[i]" ); + uint32_t numSlicesInTile = pcPPS->getNumSlicesInTile( i ); + for( int j = 0; j < numSlicesInTile-1; j++ ) + { + WRITE_UVLC( pcPPS->getSliceHeightInCtu( i ) - 1, "slice_height_in_ctu_minus1[i]" ); + i++; + } + } + + // tile index offset to start of next slice + if( i < pcPPS->getNumSlicesInPic()-1 ) + { + if( pcPPS->getTileIdxDeltaPresentFlag() ) + { + int32_t tileIdxDelta = pcPPS->getSliceTileIdx( i + 1 ) - pcPPS->getSliceTileIdx( i ); + WRITE_SVLC( tileIdxDelta, "tile_idx_delta[i]" ); + } + } + } + } + + // loop filtering across slice/tile controls + WRITE_FLAG( pcPPS->getLoopFilterAcrossTilesEnabledFlag(), "loop_filter_across_tiles_enabled_flag"); + WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag(), "loop_filter_across_slices_enabled_flag"); + } + #endif WRITE_FLAG( pcPPS->getCabacInitPresentFlag() ? 1 : 0, "cabac_init_present_flag" ); WRITE_UVLC( pcPPS->getNumRefIdxL0DefaultActive()-1, "num_ref_idx_l0_default_active_minus1"); @@ -323,6 +391,7 @@ void HLSWriter::codePPS( const PPS* pcPPS, const SPS* pcSPS ) WRITE_FLAG( pcPPS->getWPBiPred() ? 1 : 0, "weighted_bipred_flag" ); // Use of Weighting Bi-Prediction (B_SLICE) WRITE_FLAG( pcPPS->getTransquantBypassEnabledFlag() ? 1 : 0, "transquant_bypass_enabled_flag" ); +#if !JVET_P1004_REMOVE_BRICKS WRITE_FLAG( pcPPS->getSingleTileInPicFlag() ? 1 : 0, "single_tile_in_pic_flag" ); if (!pcPPS->getSingleTileInPicFlag()) { @@ -439,6 +508,7 @@ void HLSWriter::codePPS( const PPS* pcPPS, const SPS* pcSPS ) } +#endif WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" ); WRITE_FLAG( pcPPS->getDeblockingFilterControlPresentFlag()?1 : 0, "deblocking_filter_control_present_flag"); @@ -1803,6 +1873,30 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) #if !JVET_P1006_PICTURE_HEADER WRITE_UVLC( pcSlice->getPPS()->getPPSId(), "slice_pic_parameter_set_id" ); #endif +#if JVET_P1004_REMOVE_BRICKS + // raster scan slices + if( pcSlice->getPPS()->getRectSliceFlag() == 0 ) + { + // slice address is the raster scan tile index of first tile in slice + if( pcSlice->getPPS()->getNumTiles() > 1 ) + { + int bitsSliceAddress = ceilLog2(pcSlice->getPPS()->getNumTiles()); + WRITE_CODE( pcSlice->getSliceID(), bitsSliceAddress, "slice_address"); + WRITE_UVLC( pcSlice->getNumTilesInSlice() - 1, "num_tiles_in_slice_minus1"); + } + } + // rectangular slices + else + { + // slice address is the index of the slice within the current sub-picture + if( pcSlice->getPPS()->getNumSlicesInPic() > 1 ) + { + int bitsSliceAddress = ceilLog2(pcSlice->getPPS()->getNumSlicesInPic()); // change to NumSlicesInSubPic when available + WRITE_CODE( pcSlice->getSliceID(), bitsSliceAddress, "slice_address"); + } + } + +#else int bitsSliceAddress = 1; if (!pcSlice->getPPS()->getRectSliceFlag()) { @@ -1841,6 +1935,7 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) WRITE_UVLC(pcSlice->getSliceNumBricks() - 1, "num_bricks_in_slice_minus1"); } +#endif #if !JVET_P1006_PICTURE_HEADER WRITE_FLAG(pcSlice->getNonRefPictFlag() ? 1 : 0, "non_reference_picture_flag"); #endif @@ -2444,7 +2539,12 @@ void HLSWriter::codeProfileTierLevel ( const ProfileTierLevel* ptl, int maxN */ void HLSWriter::codeTilesWPPEntryPoint( Slice* pSlice ) { +#if JVET_P1004_REMOVE_BRICKS + pSlice->setNumEntryPoints( pSlice->getPPS() ); + if( pSlice->getNumEntryPoints() == 0 ) +#else if (pSlice->getPPS()->getSingleTileInPicFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) +#endif { return; } @@ -2466,8 +2566,10 @@ void HLSWriter::codeTilesWPPEntryPoint( Slice* pSlice ) CHECK(offsetLenMinus1 + 1 >= 32, "Invalid offset length minus 1"); } +#if !JVET_P1004_REMOVE_BRICKS #if !JVET_O0145_ENTRYPOINT_SIGNALLING WRITE_UVLC(pSlice->getNumberOfSubstreamSizes(), "num_entry_point_offsets"); +#endif #endif if (pSlice->getNumberOfSubstreamSizes()>0) { -- GitLab