From e650821fb49a70ba998b8130ea443e5a45ac56d9 Mon Sep 17 00:00:00 2001
From: Karl Sharman <karl.sharman@sony.com>
Date: Mon, 22 Jun 2020 22:07:50 +0100
Subject: [PATCH] Added support for still picture profiles.

---
 doc/software-manual.tex                   | 16 ++-------
 source/App/EncoderApp/EncApp.cpp          |  7 ++--
 source/App/EncoderApp/EncAppCfg.cpp       | 42 +++++++++++++++++++++++
 source/App/EncoderApp/EncAppCfg.h         |  3 ++
 source/Lib/CommonLib/ProfileLevelTier.cpp | 15 ++++++++
 source/Lib/CommonLib/ProfileLevelTier.h   |  3 ++
 source/Lib/CommonLib/TypeDef.h            |  2 ++
 source/Lib/DecoderLib/VLCReader.cpp       |  3 ++
 source/Lib/EncoderLib/EncCfg.h            |  9 +++++
 source/Lib/EncoderLib/EncLib.cpp          |  3 ++
 source/Lib/EncoderLib/VLCWriter.cpp       |  3 ++
 11 files changed, 91 insertions(+), 15 deletions(-)

diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 92d138e03..fd102af34 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -954,18 +954,8 @@ multiple matches.
 \Default{none} &
 Specifies the profile to which the encoded bitstream complies.
 
-Valid HEVC Ver. 1 values are: none, main, main10, main-still-picture
-
-Valid HEVC Ver. 2 (RExt) values are: main-RExt, high-throughput-RExt,
-monochrome, monochrome12, monochrome16, main12, main_422_10,
-main_422_12, main_444, main_444_10, main_444_12, main_444_16,
-main_intra, main_10_intra, main_12_intra, main_422_10_intra, main_422_12_intra,
-main_444_intra, main_444_10_intra, main_444_12_intra, main_444_16_intra.
-
-When main-RExt is specified, the constraint flags are either manually specified, or calculated via the other supplied settings.
-
-Compatibility flags are automatically determined according to the profile.
-NB: There is currently only limited validation that the encoder configuration complies with the profile, level and tier constraints.
+Valid VVC Ver. 1 values are: none, main_10, main_10_still_picture, main_444_10, main_444_10_still_picture.
+When one of the still picture profiles are selected, the OnePictureOnlyConstraintFlag setting will be forced to 1.
 \\
 
 \Option{Level} &
@@ -1019,7 +1009,7 @@ For --profile=main-RExt, specifies the value of general_intra_constraint_flag to
 \Option{OnePictureOnlyConstraintFlag} &
 %\ShortOption{\None} &
 \Default{false} &
-For --profile=main-RExt, specifies the value of general_one_picture_only_constraint_flag to use for RExt profiles.
+Specifies the value of general_one_picture_only_constraint_flag.
 \\
 
 \Option{LowerBitRateConstraintFlag} &
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index a0d08c1f7..d99205950 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -264,10 +264,13 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setFramesToBeEncoded                                 ( m_framesToBeEncoded );
 
   //====== SPS constraint flags =======
-  m_cEncLib.setIntraOnlyConstraintFlag                           ( m_intraConstraintFlag );
+#if STILL_PICTURE_PROFILES
+  m_cEncLib.setOnePictureOnlyConstraintFlag                      ( m_onePictureOnlyConstraintFlag );
+#endif
+  m_cEncLib.setIntraOnlyConstraintFlag                           ( m_intraConstraintFlag );  // NOTE: This setting is not used, and is confused with setIntraConstraintFlag
   m_cEncLib.setMaxBitDepthConstraintIdc                          ( m_bitDepthConstraint - 8 );
   m_cEncLib.setMaxChromaFormatConstraintIdc                      ( m_chromaFormatConstraint );
-  m_cEncLib.setFrameConstraintFlag                               ( m_bFrameConstraintFlag );
+  m_cEncLib.setFrameConstraintFlag                               ( m_bFrameConstraintFlag ); // NOTE: This setting is neither used nor setup, and is confused with setFrameOnlyConstraintFlag
   m_cEncLib.setNoQtbttDualTreeIntraConstraintFlag                ( !m_dualTree );
   m_cEncLib.setNoPartitionConstraintsOverrideConstraintFlag      ( !m_SplitConsOverrideEnabledFlag );
   m_cEncLib.setNoSaoConstraintFlag                               ( !m_bUseSAO );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 9fa5b1a7f..fd6929190 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -60,9 +60,17 @@ namespace po = df::program_options_lite;
 
 enum ExtendedProfileName // this is used for determining profile strings, where multiple profiles map to a single profile idc with various constraint flag combinations
 {
+#if STILL_PICTURE_PROFILES
+  NONE,
+  MAIN_10,
+  MAIN_10_STILL_PICTURE,
+  MAIN_444_10,
+  MAIN_444_10_STILL_PICTURE,
+#else
   NONE        = Profile::NONE,
   MAIN_10     = Profile::MAIN_10,
   MAIN_444_10 = Profile::MAIN_444_10,
+#endif
   AUTO = -1
 };
 
@@ -237,6 +245,10 @@ strToExtendedProfile[] =
     {"none",                      NONE             },
     {"main_10",                   MAIN_10          },
     {"main_444_10",               MAIN_444_10      },
+#if STILL_PICTURE_PROFILES
+    {"main_10_still_picture",     MAIN_10_STILL_PICTURE },
+    {"main_444_10_still_picture", MAIN_444_10_STILL_PICTURE },
+#endif
     {"auto",                      AUTO             }
 };
 
@@ -819,14 +831,23 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("HarmonizeGopFirstFieldCoupleEnabled",             m_bHarmonizeGopFirstFieldCoupleEnabled,            true, "Enables harmonization of Gop first field couple")
 
   // Profile and level
+#if STILL_PICTURE_PROFILES
+  ("Profile",                                         extendedProfile,              ExtendedProfileName::NONE, "Profile name to use for encoding. Use main_10, main_10_still_picture, main_444_10, main_444_10_still_picture, auto, or none")
+#else
   ("Profile",                                         extendedProfile,              ExtendedProfileName::NONE, "Profile name to use for encoding. Use main_10, main_444_10, auto, or none")
+#endif
   ("Level",                                           m_level,                                    Level::NONE, "Level limit to be used, eg 5.1, or none")
   ("Tier",                                            m_levelTier,                                Level::MAIN, "Tier to use for interpretation of --Level (main or high only)")
   ("SubProfile",                                      cfg_SubProfile,                          cfg_SubProfile,  "Sub-profile idc")
   ("EnableDecodingCapabilityInformation",             m_DCIEnabled,                                     false, "Enables writing of Decoding Capability Information")
   ("MaxBitDepthConstraint",                           m_bitDepthConstraint,                                0u, "Bit depth to use for profile-constraint for RExt profiles. 0=automatically choose based upon other parameters")
   ("MaxChromaFormatConstraint",                       tmpConstraintChromaFormat,                            0, "Chroma-format to use for the profile-constraint for RExt profiles. 0=automatically choose based upon other parameters")
+#if STILL_PICTURE_PROFILES
+  ("OnePictureOnlyConstraintFlag",                    m_onePictureOnlyConstraintFlag,                   false, "Value of general_intra_constraint_flag. Can only be used for single frame encodings. Will be set to true for still picture profiles")
+  ("IntraConstraintFlag",                             m_intraConstraintFlag,                            false, "Value of intra_only_constraint_flag")
+#else
   ("IntraConstraintFlag",                             m_intraConstraintFlag,                            false, "Value of general_intra_constraint_flag to use for RExt profiles (not used if an explicit RExt sub-profile is specified)")
+#endif
 
 #if !JVET_R0090_VUI
   ("ProgressiveSource",                               m_progressiveSourceFlag,                          false, "Indicate that source is progressive")
@@ -1812,7 +1833,21 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   }
   else
   {
+#if STILL_PICTURE_PROFILES
+    switch (extendedProfile)
+    {
+      case ExtendedProfileName::NONE:                      m_profile = Profile::NONE; break;
+      case ExtendedProfileName::MAIN_10:                   m_profile = Profile::MAIN_10; break;
+      case ExtendedProfileName::MAIN_444_10:               m_profile = Profile::MAIN_444_10; break;
+      case ExtendedProfileName::MAIN_10_STILL_PICTURE:     m_profile = Profile::MAIN_10;     m_onePictureOnlyConstraintFlag = true; break;
+      case ExtendedProfileName::MAIN_444_10_STILL_PICTURE: m_profile = Profile::MAIN_444_10; m_onePictureOnlyConstraintFlag = true; break;
+      default:
+        EXIT( "Unable to determine profile from configured settings");
+        break;
+    }
+#else
     m_profile = Profile::Name(extendedProfile);
+#endif
   }
 
   {
@@ -2557,6 +2592,13 @@ bool EncAppCfg::xCheckParameter()
 
   xConfirmPara (m_log2MaxTransformSkipBlockSize < 2, "Transform Skip Log2 Max Size must be at least 2 (4x4)");
 
+#if STILL_PICTURE_PROFILES
+  xConfirmPara ( m_onePictureOnlyConstraintFlag && m_framesToBeEncoded!=1, "When onePictureOnlyConstraintFlag is true, the number of frames to be encoded must be 1" );
+  if (m_profile == Profile::MAIN_10 || m_profile==Profile::MAIN_444_10)
+  {
+    xConfirmPara ( m_level==Level::LEVEL15_5 && !m_onePictureOnlyConstraintFlag, "Currently the only profiles that support level 15.5 are still pictures, which require onePictureOnlyConstraintFlag to be 1" );
+  }
+#endif
 
   if( m_SubPuMvpMode == 3 && m_maxNumMergeCand < 7 )
   {
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 7d2f9bc60..a8ae374f1 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -196,6 +196,9 @@ protected:
 
   uint32_t          m_bitDepthConstraint;
   ChromaFormat  m_chromaFormatConstraint;
+#if STILL_PICTURE_PROFILES
+  bool          m_onePictureOnlyConstraintFlag;
+#endif
   bool          m_intraConstraintFlag;
 #if !JVET_R0090_VUI
   bool          m_progressiveSourceFlag;
diff --git a/source/Lib/CommonLib/ProfileLevelTier.cpp b/source/Lib/CommonLib/ProfileLevelTier.cpp
index d482eb656..2469621fd 100644
--- a/source/Lib/CommonLib/ProfileLevelTier.cpp
+++ b/source/Lib/CommonLib/ProfileLevelTier.cpp
@@ -87,8 +87,16 @@ static const LevelTierFeatures mainLevelTierInfo[] =
 static const ProfileFeatures validProfiles[] =
 #if JVET_R0244_CPB_AND_MINCR
 {   //  profile,                   pNameString,             maxBitDepth, maxChrFmt, lvl15.5, cpbvcl, cpbnal, fcf*1000, mincr*100, levelInfo
+#if STILL_PICTURE_PROFILES
+    // most constrained profiles must appear first.
+    { Profile::MAIN_10,            "Main_10_Still_Picture",          10, CHROMA_420,  true,   1000,   1100,     1875,    100    , mainLevelTierInfo,  true },
+    { Profile::MAIN_444_10,        "Main_444_10_Still_Picture",      10, CHROMA_444,  true,   2500,   2750,     3750,     75    , mainLevelTierInfo,  true },
+    { Profile::MAIN_10,            "Main_10",                        10, CHROMA_420, false,   1000,   1100,     1875,    100    , mainLevelTierInfo, false },
+    { Profile::MAIN_444_10,        "Main_444_10",                    10, CHROMA_444, false,   2500,   2750,     3750,     75    , mainLevelTierInfo, false },
+#else
     { Profile::MAIN_10,            "Main_10",                        10, CHROMA_420, false,   1000,   1100,     1875,    100    , mainLevelTierInfo },
     { Profile::MAIN_444_10,        "Main_444_10",                    10, CHROMA_444, false,   2500,   2750,     3750,     75    , mainLevelTierInfo },
+#endif
 #else
 {   //  profile,                   pNameString,             maxBitDepth, maxChrFmt,  lvl8.5, cpbvcl, cpbnal, fcf*1000, mincr*10, levelInfo
     { Profile::MAIN_10,            "Main_10",                        10, CHROMA_420, false,   1000,   1100,     1875,   10    , mainLevelTierInfo },
@@ -105,9 +113,16 @@ ProfileLevelTierFeatures::extractPTLInformation(const SPS &sps)
   m_tier = spsPtl.getTierFlag();
 
   // Identify the profile from the profile Idc, and possibly other constraints.
+#if STILL_PICTURE_PROFILES
+  bool onePictureOnlyConstraintFlag=spsPtl.getConstraintInfo()->getOnePictureOnlyConstraintFlag();
+#endif
   for(int32_t i=0; validProfiles[i].profile != Profile::NONE; i++)
   {
+#if STILL_PICTURE_PROFILES
+    if (spsPtl.getProfileIdc() == validProfiles[i].profile && !(validProfiles[i].onePictureOnlyFlagMustBe1 && !onePictureOnlyConstraintFlag))
+#else
     if (spsPtl.getProfileIdc() == validProfiles[i].profile)
+#endif
     {
       m_pProfile = &(validProfiles[i]);
       break;
diff --git a/source/Lib/CommonLib/ProfileLevelTier.h b/source/Lib/CommonLib/ProfileLevelTier.h
index 68149beb4..596963f6a 100644
--- a/source/Lib/CommonLib/ProfileLevelTier.h
+++ b/source/Lib/CommonLib/ProfileLevelTier.h
@@ -84,6 +84,9 @@ struct ProfileFeatures
   uint32_t                 minCrScaleFactorx10;
 #endif
   const LevelTierFeatures *pLevelTiersListInfo;
+#if STILL_PICTURE_PROFILES
+  bool                     onePictureOnlyFlagMustBe1;
+#endif
 };
 
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index fda661919..3efce71b4 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -245,6 +245,8 @@
 
 #define JVET_R0245_LEVEL_CODING                           1 // JVET-R0245: level coding numbering scheme
 
+#define STILL_PICTURE_PROFILES                            1 // Adds support for still picture profiles
+
 //########### place macros to be be kept below this line ###############
 
 #define JVET_R0164_MEAN_SCALED_SATD                       1 // JVET-R0164: Use a mean scaled version of SATD in encoder decisions
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index a4d1a75d8..e35ef1bf6 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -4978,6 +4978,9 @@ void HLSyntaxReader::parseConstraintInfo(ConstraintInfo *cinfo)
   READ_FLAG(symbol,  "general_non_packed_constraint_flag"       ); cinfo->setNonPackedConstraintFlag(symbol ? true : false);
   READ_FLAG(symbol,  "general_frame_only_constraint_flag"       ); cinfo->setFrameOnlyConstraintFlag(symbol ? true : false);
   READ_FLAG(symbol,  "general_non_projected_constraint_flag"    ); cinfo->setNonProjectedConstraintFlag(symbol ? true : false);
+#if STILL_PICTURE_PROFILES
+  READ_FLAG(symbol,  "general_one_picture_only_constraint_flag"    ); cinfo->setOnePictureOnlyConstraintFlag(symbol ? true : false);
+#endif
   READ_FLAG(symbol,  "intra_only_constraint_flag"               ); cinfo->setIntraOnlyConstraintFlag(symbol ? true : false);
 
   READ_CODE(4, symbol,  "max_bitdepth_constraint_idc"              ); cinfo->setMaxBitDepthConstraintIdc(symbol);
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 05e943559..39080be66 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -175,6 +175,9 @@ protected:
   bool      m_printSequenceMSE;
   bool      m_cabacZeroWordPaddingEnabled;
 
+#if STILL_PICTURE_PROFILES
+  bool      m_onePictureOnlyConstraintFlag;
+#endif
   bool      m_bIntraOnlyConstraintFlag;
   uint32_t  m_maxBitDepthConstraintIdc;
   uint32_t  m_maxChromaFormatConstraintIdc;
@@ -790,6 +793,12 @@ public:
   void setLevel(Level::Tier tier, Level::Name level) { m_levelTier = tier; m_level = level; }
   void setNumSubProfile( uint8_t numSubProfile) { m_numSubProfile = numSubProfile; m_subProfile.resize(m_numSubProfile); }
   void setSubProfile( int i, uint32_t subProfile) { m_subProfile[i] = subProfile; }
+
+#if STILL_PICTURE_PROFILES
+  bool      getOnePictureOnlyConstraintFlag() const                        { return m_onePictureOnlyConstraintFlag; }
+  void      setOnePictureOnlyConstraintFlag(bool b)                        { m_onePictureOnlyConstraintFlag=b; }
+#endif
+
   bool      getIntraOnlyConstraintFlag() const { return m_bIntraOnlyConstraintFlag; }
   void      setIntraOnlyConstraintFlag(bool bVal) { m_bIntraOnlyConstraintFlag = bVal; }
   uint32_t  getMaxBitDepthConstraintIdc() const { return m_maxBitDepthConstraintIdc; }
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 9be7d2a03..dbeb05e88 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1142,6 +1142,9 @@ void EncLib::xInitSPS( SPS& sps )
   cinfo->setOneSlicePerPicConstraintFlag(m_oneSlicePerPicConstraintFlag);
   cinfo->setOneSubpicPerPicConstraintFlag(m_oneSubpicPerPicConstraintFlag);
   cinfo->setFrameOnlyConstraintFlag     (m_frameOnlyConstraintFlag);
+#if STILL_PICTURE_PROFILES
+  cinfo->setOnePictureOnlyConstraintFlag(m_onePictureOnlyConstraintFlag);
+#endif
   cinfo->setIntraOnlyConstraintFlag         (m_intraConstraintFlag);
   cinfo->setMaxBitDepthConstraintIdc    (m_maxBitDepthConstraintIdc);
   cinfo->setMaxChromaFormatConstraintIdc((ChromaFormat)m_maxChromaFormatConstraintIdc);
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index c5ee7bac6..f43537092 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -2887,6 +2887,9 @@ void  HLSWriter::codeConstraintInfo  ( const ConstraintInfo* cinfo )
   WRITE_FLAG(cinfo->getNonPackedConstraintFlag(), "general_non_packed_constraint_flag"      );
   WRITE_FLAG(cinfo->getFrameOnlyConstraintFlag(), "general_frame_only_constraint_flag"      );
   WRITE_FLAG(cinfo->getNonProjectedConstraintFlag(), "general_non_projected_constraint_flag");
+#if STILL_PICTURE_PROFILES
+  WRITE_FLAG(cinfo->getOnePictureOnlyConstraintFlag(), "general_one_picture_only_constraint_flag" );
+#endif
   WRITE_FLAG(cinfo->getIntraOnlyConstraintFlag(),     "intra_only_constraint_flag"      );
 
   WRITE_CODE(cinfo->getMaxBitDepthConstraintIdc(), 4, "max_bitdepth_constraint_idc" );
-- 
GitLab