[x265] [PATCH] add experimental support for interlaced content (field encoding) (refs #15)

Steve Borho steve at borho.org
Thu Mar 20 04:21:31 CET 2014


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1395285660 18000
#      Wed Mar 19 22:21:00 2014 -0500
# Node ID 0f771f867e9cd60a4a57f25156a65be87928d308
# Parent  221d8aee9aa18d049ad533fd893ca863d0416ffb
add experimental support for interlaced content (field encoding) (refs #15)

* adds param.interlaceMode
* removes VUI params that are now handled automatically
* adds --no-interlace --interlace=tff|bff|prog|false CLI options
* signals interlace source flag, clears progressive source flag

This initial implementation requires the user to provide fields (half-height) in
the correct temporal order; so not very useful for exisitng Y4M or YUV
interlaced input files.

When interlacing is enabled, the encoder emits PictureTiming SEI messages that
indicate top or bottom field for the decoder.

diff -r 221d8aee9aa1 -r 0f771f867e9c source/CMakeLists.txt
--- a/source/CMakeLists.txt	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/CMakeLists.txt	Wed Mar 19 22:21:00 2014 -0500
@@ -18,7 +18,7 @@
 include(CheckCXXCompilerFlag)
 
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 9)
+set(X265_BUILD 10)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 221d8aee9aa1 -r 0f771f867e9c source/common/common.h
--- a/source/common/common.h	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/common/common.h	Wed Mar 19 22:21:00 2014 -0500
@@ -104,7 +104,7 @@
 #define X265_LOWRES_CU_SIZE   8
 #define X265_LOWRES_CU_BITS   3
 
-#define MAX_NAL_UNITS 5
+#define MAX_NAL_UNITS 6
 #define MIN_FIFO_SIZE 1000
 
 #define X265_MALLOC(type, count)    (type*)x265_malloc(sizeof(type) * (count))
diff -r 221d8aee9aa1 -r 0f771f867e9c source/common/param.cpp
--- a/source/common/param.cpp	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/common/param.cpp	Wed Mar 19 22:21:00 2014 -0500
@@ -193,8 +193,6 @@
     param->vui.bEnableChromaLocInfoPresentFlag = 0;
     param->vui.chromaSampleLocTypeTopField = 0;
     param->vui.chromaSampleLocTypeBottomField = 0;
-    param->vui.bEnableFieldSeqFlag = 0;
-    param->vui.bEnableFrameFieldInfoPresentFlag = 0;
     param->vui.bEnableDefaultDisplayWindowFlag = 0;
     param->vui.defDispWinLeftOffset = 0;
     param->vui.defDispWinRightOffset = 0;
@@ -572,6 +570,16 @@
             p->bFrameAdaptive = atoi(value);
         }
     }
+    OPT("interlace")
+    {
+        p->interlaceMode = atobool(value);
+        if (bError || p->interlaceMode)
+        {
+            bError = false;
+            p->interlaceMode = parseName(value, x265_interlace_names, bError);
+        }
+        p->vui.bEnableVuiParametersPresentFlag |= !!p->interlaceMode;
+    }
     OPT("ref") p->maxNumReferences = atoi(value);
     OPT("weightp") p->bEnableWeightedPred = atobool(value);
     OPT("cbqpoffs") p->cbQpOffset = atoi(value);
@@ -620,8 +628,6 @@
         p->vui.bEnableVideoSignalTypePresentFlag = bvalue;
         p->vui.bEnableColorDescriptionPresentFlag = bvalue;
         p->vui.bEnableChromaLocInfoPresentFlag = bvalue;
-        p->vui.bEnableFieldSeqFlag = bvalue;
-        p->vui.bEnableFrameFieldInfoPresentFlag = bvalue;
         p->vui.bEnableDefaultDisplayWindowFlag = bvalue;
         p->vui.bEnableVuiTimingInfoPresentFlag = bvalue;
         p->vui.bEnableVuiHrdParametersPresentFlag = bvalue;
@@ -694,16 +700,6 @@
         p->vui.chromaSampleLocTypeTopField = atoi(value);
         p->vui.chromaSampleLocTypeBottomField = p->vui.chromaSampleLocTypeTopField;
     }
-    OPT("fieldseq")
-    {
-        p->vui.bEnableVuiParametersPresentFlag = 1;
-        p->vui.bEnableFieldSeqFlag = atobool(value);
-    }
-    OPT("framefieldinfo")
-    {
-        p->vui.bEnableVuiParametersPresentFlag = 1;
-        p->vui.bEnableFrameFieldInfoPresentFlag = atobool(value);
-    }
     OPT("crop-rect")
     {
         p->vui.bEnableVuiParametersPresentFlag = 1;
@@ -909,6 +905,8 @@
           "QP exceeds supported range (-QpBDOffsety to 51)");
     CHECK(param->fpsNum == 0 || param->fpsDenom == 0,
           "Frame rate numerator and denominator must be specified");
+    CHECK(param->interlaceMode < 0 || param->interlaceMode > 2,
+          "Interlace mode must be 0 (progressive) 1 (top-field first) or 2 (bottom field first)");
     CHECK(param->searchMethod<0 || param->searchMethod> X265_FULL_SEARCH,
           "Search method is not supported value (0:DIA 1:HEX 2:UMH 3:HM 5:FULL)");
     CHECK(param->searchRange < 0,
@@ -1086,6 +1084,10 @@
 #if HIGH_BIT_DEPTH
     x265_log(param, X265_LOG_INFO, "Internal bit depth                  : %d\n", param->internalBitDepth);
 #endif
+    if (param->interlaceMode)
+    {
+        x265_log(param, X265_LOG_INFO, "Interlaced field inputs             : %s\n", x265_interlace_names[param->interlaceMode]);
+    }
     x265_log(param, X265_LOG_INFO, "CU size                             : %d\n", param->maxCUSize);
     x265_log(param, X265_LOG_INFO, "Max RQT depth inter / intra         : %d / %d\n", param->tuQTMaxInterDepth, param->tuQTMaxIntraDepth);
 
@@ -1190,6 +1192,7 @@
     BOOL(p->bEnableStrongIntraSmoothing, "strong-intra-smoothing");
     BOOL(p->bEnableConstrainedIntra, "constrained-intra");
     BOOL(p->bOpenGOP, "open-gop");
+    s += sprintf(s, " interlace=%d", p->interlaceMode);
     s += sprintf(s, " keyint=%d", p->keyframeMax);
     s += sprintf(s, " min-keyint=%d", p->keyframeMin);
     s += sprintf(s, " scenecut=%d", p->scenecutThreshold);
diff -r 221d8aee9aa1 -r 0f771f867e9c source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/encoder/encoder.cpp	Wed Mar 19 22:21:00 2014 -0500
@@ -959,8 +959,8 @@
     profileTierLevel.setTierFlag(m_levelTier ? true : false);
     profileTierLevel.setProfileIdc(m_profile);
     profileTierLevel.setProfileCompatibilityFlag(m_profile, 1);
-    profileTierLevel.setProgressiveSourceFlag(m_progressiveSourceFlag);
-    profileTierLevel.setInterlacedSourceFlag(m_interlacedSourceFlag);
+    profileTierLevel.setProgressiveSourceFlag(!param->interlaceMode);
+    profileTierLevel.setInterlacedSourceFlag(!!param->interlaceMode);
     profileTierLevel.setNonPackedConstraintFlag(m_nonPackedConstraintFlag);
     profileTierLevel.setFrameOnlyConstraintFlag(m_frameOnlyConstraintFlag);
 
@@ -1072,8 +1072,8 @@
         vui->setChromaSampleLocTypeBottomField(param->vui.chromaSampleLocTypeBottomField);
         vui->setNeutralChromaIndicationFlag(m_neutralChromaIndicationFlag);
         vui->setDefaultDisplayWindow(m_defaultDisplayWindow);
-        vui->setFrameFieldInfoPresentFlag(param->vui.bEnableFrameFieldInfoPresentFlag);
-        vui->setFieldSeqFlag(param->vui.bEnableFieldSeqFlag);
+        vui->setFrameFieldInfoPresentFlag(!!param->interlaceMode);
+        vui->setFieldSeqFlag(!!param->interlaceMode);
         vui->setHrdParametersPresentFlag(param->vui.bEnableVuiHrdParametersPresentFlag);
         vui->getHrdParameters()->setNalHrdParametersPresentFlag(param->vui.bEnableNalHrdParametersPresentFlag);
         vui->getHrdParameters()->setSubPicHrdParamsPresentFlag(param->vui.bEnableSubPicHrdParamsPresentFlag);
@@ -1411,6 +1411,10 @@
         x265_log(p, X265_LOG_WARNING, "!! HEVC Range Extension specifications are not finalized !!\n");
         x265_log(p, X265_LOG_WARNING, "!! This output bitstream may not be compliant with the final spec !!\n");
     }
+    if (p->interlaceMode)
+    {
+        x265_log(p, X265_LOG_WARNING, "Support for interlaced video is experimental\n");
+    }
 
     m_bframeDelay = p->bframes ? (p->bBPyramid ? 2 : 1) : 0;
 
@@ -1482,13 +1486,10 @@
     m_maxNumOffsetsPerPic = 2048;
     m_log2ParallelMergeLevelMinus2 = 0;
 
-    m_progressiveSourceFlag = true;
-    m_interlacedSourceFlag = false;
     m_nonPackedConstraintFlag = false;
     m_frameOnlyConstraintFlag = false;
     m_recoveryPointSEIEnabled = 0;
     m_bufferingPeriodSEIEnabled = 0;
-    m_pictureTimingSEIEnabled = 0;
     m_displayOrientationSEIAngle = 0;
     m_gradualDecodingRefreshInfoEnabled = 0;
     m_decodingUnitInfoSEIEnabled = 0;
diff -r 221d8aee9aa1 -r 0f771f867e9c source/encoder/encoder.h
--- a/source/encoder/encoder.h	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/encoder/encoder.h	Wed Mar 19 22:21:00 2014 -0500
@@ -116,8 +116,6 @@
     Level::Tier        m_levelTier;
     Level::Name        m_level;
 
-    bool               m_progressiveSourceFlag;
-    bool               m_interlacedSourceFlag;
     bool               m_nonPackedConstraintFlag;
     bool               m_frameOnlyConstraintFlag;
 
@@ -157,7 +155,6 @@
     bool               m_loopFilterAcrossTilesEnabledFlag;
 
     int                m_bufferingPeriodSEIEnabled;
-    int                m_pictureTimingSEIEnabled;
     int                m_recoveryPointSEIEnabled;
     int                m_displayOrientationSEIAngle;
     int                m_gradualDecodingRefreshInfoEnabled;
diff -r 221d8aee9aa1 -r 0f771f867e9c source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/encoder/frameencoder.cpp	Wed Mar 19 22:21:00 2014 -0500
@@ -136,11 +136,11 @@
     top->initPPS(&m_pps);
 
     m_sps.setNumLongTermRefPicSPS(0);
-    if (m_cfg->m_pictureTimingSEIEnabled || m_cfg->m_decodingUnitInfoSEIEnabled)
+    if (m_cfg->m_decodingUnitInfoSEIEnabled)
     {
         m_sps.setHrdParameters(m_cfg->param->fpsNum, m_cfg->param->fpsDenom, 0, m_cfg->param->rc.bitrate, m_cfg->param->bframes > 0);
     }
-    if (m_cfg->m_bufferingPeriodSEIEnabled || m_cfg->m_pictureTimingSEIEnabled || m_cfg->m_decodingUnitInfoSEIEnabled)
+    if (m_cfg->m_bufferingPeriodSEIEnabled || m_cfg->m_decodingUnitInfoSEIEnabled)
     {
         m_sps.getVuiParameters()->setHrdParametersPresentFlag(true);
     }
@@ -500,6 +500,26 @@
         }
     }
 
+    if (!!m_cfg->param->interlaceMode)
+    {
+        OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI);
+
+        SEIPictureTiming sei;
+        sei.m_picStruct = (slice->getPOC() & 1) && m_cfg->param->interlaceMode == 1 ? 1 /* top */ : 2 /* bot */;
+        sei.m_sourceScanType = 1;
+        sei.m_duplicateFlag = 0;
+
+        entropyCoder->setBitstream(&nalu.m_bitstream);
+        m_seiWriter.writeSEImessage(nalu.m_bitstream, sei, &m_sps);
+        writeRBSPTrailingBits(nalu.m_bitstream);
+        m_nalList[m_nalCount] = X265_MALLOC(NALUnitEBSP, 1);
+        if (m_nalList[m_nalCount])
+        {
+            m_nalList[m_nalCount]->init(nalu);
+            m_nalCount++;
+        }
+    }
+
     /* use the main bitstream buffer for storing the marshaled picture */
     if (m_sps.getUseSAO())
     {
diff -r 221d8aee9aa1 -r 0f771f867e9c source/x265.cpp
--- a/source/x265.cpp	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/x265.cpp	Wed Mar 19 22:21:00 2014 -0500
@@ -76,6 +76,8 @@
     { "input-depth",    required_argument, NULL, 0 },
     { "input-res",      required_argument, NULL, 0 },
     { "input-csp",      required_argument, NULL, 0 },
+    { "interlace",      required_argument, NULL, 0 },
+    { "no-interlace",         no_argument, NULL, 0 },
     { "fps",            required_argument, NULL, 0 },
     { "seek",           required_argument, NULL, 0 },
     { "frame-skip",     required_argument, NULL, 0 },
@@ -388,9 +390,6 @@
     H0("   --colormatrix <string>        Specify color matrix setting from undef, bt709, fcc, bt470bg, smpte170m,\n");
     H0("                                 smpte240m, GBR, YCgCo, bt2020nc, bt2020c. Default undef\n");
     H0("   --chromaloc <integer>         Specify chroma sample location (0 to 5). Default of %d\n", param->vui.chromaSampleLocTypeTopField);
-    H0("   --[no-]fieldseq               Specify that pictures are fields and an SEI timing message\n");
-    H0("                                 will be added to every access unit. Default %s\n", OPT(param->vui.bEnableFieldSeqFlag));
-    H0("   --[no-]framefieldinfo         Specify that a pic-struct will be added to the SEI timing message. Default %s\n", OPT(param->vui.bEnableFrameFieldInfoPresentFlag));
     H0("   --[no-]timinginfo             Add timing information to the VUI. Defaut %s\n", OPT(param->vui.bEnableVuiTimingInfoPresentFlag));
     H0("   --[no-]hrd                    Signal HRD information. Default %s\n", OPT(param->vui.bEnableVuiHrdParametersPresentFlag));
     H0("   --nal-hrd <string>            Signal NAL HRD information (requires vbv-buffer size) Choose from none, vbr or cbr.Default none\n");
diff -r 221d8aee9aa1 -r 0f771f867e9c source/x265.h
--- a/source/x265.h	Wed Mar 19 18:26:14 2014 -0500
+++ b/source/x265.h	Wed Mar 19 22:21:00 2014 -0500
@@ -293,6 +293,7 @@
 static const char * const x265_sar_names[] = { "undef", "1:1", "12:11", "10:11", "16:11", "40:33", "24:11", "20:11",
                                                "32:11", "80:33", "18:11", "15:11", "64:33", "160:99", "4:3", "3:2", "2:1", 0 };
 static const char * const x265_nal_hrd_names[] = { "none", "vbr", "cbr", 0 };
+static const char * const x265_interlace_names[] = { "prog", "tff", "bff", 0 };
 
 /* x265 input parameters
  *
@@ -382,6 +383,12 @@
      * minimum requirement. All valid HEVC heights are supported */
     int       sourceHeight;
 
+    /* Interlace type of source pictures. 0 - progressive pictures (default).
+     * 1 - top field first, 2 - bottom field first. HEVC encodes interlaced
+     * content as fields, they must be provided to the encoder in the correct
+     * temporal order. EXPERIMENTAL */
+    int       interlaceMode;
+
     /*== Coding Unit (CU) definitions ==*/
 
     /* Maxiumum CU width and height in pixels.  The size must be 64, 32, or 16.
@@ -769,16 +776,6 @@
          * the bottom field. The default is 0 */
         int chromaSampleLocTypeBottomField;
 
-        /* Field seq flag specifies that the pictures are fields and each one
-         * has a timing SEI message. The default is false */
-        int bEnableFieldSeqFlag;
-
-        /* Frame field info present flag indicates that each picture has a
-         * timing SEI message wich includes a pic_struct, source_scan_type and
-         * duplicate_flag elements. If not set then the pic_struct element is
-         * not included. The default is false */
-        int bEnableFrameFieldInfoPresentFlag;
-
         /* Default display window flag adds def_disp_win_left_offset,
          * def_disp_win_right_offset, def_disp_win_top_offset and
          * def_disp_win_bottom_offset to the VUI. The default is false */


More information about the x265-devel mailing list