[x265] [PATCH 1 of 2] encoder: Add support for Temporal Layering of the encoded bitstream

Steve Borho steve at borho.org
Tue Feb 3 18:07:29 CET 2015


On 02/03, aarthi at multicorewareinc.com wrote:
> # HG changeset patch
> # User Aarthi Thirumalai
> # Date 1422960681 -19800
> #      Tue Feb 03 16:21:21 2015 +0530
> # Node ID 830d29c97117c609585b7c18cc75f120a89ce79e
> # Parent  4583eda4cf55e9a7f5c11d1ea660367f3822af53
> encoder: Add support for Temporal Layering of the encoded bitstream.
> 
> Implements Temporal Sub Layers while encoding, signals NAL units of coded slices
> with their temporalId. Output bitstreams can be extracted either at the base temporal layer
> (layer 0) with roughly half the frame rate or at a higher temporal layer (layer 1)
> that decodes all the frames in the sequence.

queued, with some tweaks

> diff -r 4583eda4cf55 -r 830d29c97117 source/common/param.cpp
> --- a/source/common/param.cpp	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/common/param.cpp	Tue Feb 03 16:21:21 2015 +0530
> @@ -181,6 +181,7 @@
>      param->bIntraInBFrames = 0;
>      param->bLossless = 0;
>      param->bCULossless = 0;
> +    param->bEnableTemporalSubLayers = 0;
>  
>      /* Rate control options */
>      param->rc.vbvMaxBitrate = 0;
> diff -r 4583eda4cf55 -r 830d29c97117 source/common/slice.h
> --- a/source/common/slice.h	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/common/slice.h	Tue Feb 03 16:21:21 2015 +0530
> @@ -149,6 +149,7 @@
>  
>  struct VPS
>  {
> +    uint32_t         maxTempSubLayers;
>      uint32_t         numReorderPics;
>      uint32_t         maxDecPicBuffering;
>      HRDInfo          hrdParameters;
> @@ -228,6 +229,7 @@
>      bool     bUseAMP; // use param
>      uint32_t maxAMPDepth;
>  
> +    uint32_t maxTempSubLayers; // max number of Temporal Sub layers
>      uint32_t maxDecPicBuffering; // these are dups of VPS values
>      int      numReorderPics;
>      int      maxLatencyIncrease;
> diff -r 4583eda4cf55 -r 830d29c97117 source/encoder/encoder.cpp
> --- a/source/encoder/encoder.cpp	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/encoder/encoder.cpp	Tue Feb 03 16:21:21 2015 +0530
> @@ -669,6 +669,14 @@
>              /* determine references, setup RPS, etc */
>              m_dpb->prepareEncode(frameEnc);
>  
> +            /* If temporal Layers are enabled, set tempLayer and NAL Unit Type.
> +             * For now, there are a max of 2 layers, with the non Referenced B frames
> +             * forming the temporal sublayer and other referenced frames are on the base layer */

this comment is new and stale at the same time :)

> +            if (!frameEnc->m_encData->m_bHasReferences && m_param->bEnableTemporalSubLayers)
> +            {
> +                frameEnc->m_encData->m_slice->m_nalUnitType = NAL_UNIT_CODED_SLICE_TSA_N;
> +            }
> +

I've moved this into prepareEncode(), where NAL types are generally
decided.

>              if (m_param->rc.rateControlMode != X265_RC_CQP)
>                  m_lookahead->getEstimatedPictureCost(frameEnc);
>  
> @@ -1413,6 +1421,7 @@
>      sps->bUseAMP = m_param->bEnableAMP;
>      sps->maxAMPDepth = m_param->bEnableAMP ? g_maxCUDepth : 0;
>  
> +    sps->maxTempSubLayers = m_param->bEnableTemporalSubLayers ? 2 : 1;
>      sps->maxDecPicBuffering = m_vps.maxDecPicBuffering;
>      sps->numReorderPics = m_vps.numReorderPics;
>      sps->maxLatencyIncrease = m_param->bframes;
> @@ -1622,6 +1631,19 @@
>          p->bDistributeMotionEstimation = p->bDistributeModeAnalysis = 0;
>      }
>  
> +    if (p->bEnableTemporalSubLayers)
> +    {
> +        if (p->bFrameAdaptive)
> +            x265_log(p, X265_LOG_WARNING, "Scalable Video Coding needs fixed GOP structure, requires --b-adapt 0\n");
> +        p->bFrameAdaptive = 0;
> +        if (p->scenecutThreshold)
> +            x265_log(p, X265_LOG_WARNING, "Scalable Video Coding needs fixed GOP structure, requires --no -scenecut\n");
> +        p->scenecutThreshold = 0;
> +        if (p->bframes != 3)
> +            x265_log(p, X265_LOG_WARNING, "Ideally 3 bframes are needed to generate a base temporal layer bitstream with half the fps, requires --bframes 3\n");
> +        p->bframes = 3;

I don't see a reason to force bframes=3 here

> +    }
> +
>      m_bframeDelay = p->bframes ? (p->bBPyramid ? 2 : 1) : 0;
>  
>      p->bFrameBias = X265_MIN(X265_MAX(-90, p->bFrameBias), 100);
> diff -r 4583eda4cf55 -r 830d29c97117 source/encoder/entropy.cpp
> --- a/source/encoder/entropy.cpp	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/encoder/entropy.cpp	Tue Feb 03 16:21:21 2015 +0530
> @@ -51,17 +51,22 @@
>      WRITE_CODE(0,       4, "vps_video_parameter_set_id");
>      WRITE_CODE(3,       2, "vps_reserved_three_2bits");
>      WRITE_CODE(0,       6, "vps_reserved_zero_6bits");
> -    WRITE_CODE(0,       3, "vps_max_sub_layers_minus1");
> -    WRITE_FLAG(1,          "vps_temporal_id_nesting_flag");
> +    WRITE_CODE(vps.maxTempSubLayers - 1,       3, "vps_max_sub_layers_minus1");
> +    // Temporal Id Nesting is disabled only when maxTemporalLayers > 1
> +    WRITE_FLAG(!(vps.maxTempSubLayers - 1),       "vps_temporal_id_nesting_flag");
>      WRITE_CODE(0xffff, 16, "vps_reserved_ffff_16bits");
>  
> -    codeProfileTier(vps.ptl);
> +    codeProfileTier(vps.ptl ,vps.maxTempSubLayers - 1);
>  
>      WRITE_FLAG(true, "vps_sub_layer_ordering_info_present_flag");
> -    WRITE_UVLC(vps.maxDecPicBuffering - 1, "vps_max_dec_pic_buffering_minus1[i]");
> -    WRITE_UVLC(vps.numReorderPics,         "vps_num_reorder_pics[i]");
>  
> -    WRITE_UVLC(0,    "vps_max_latency_increase_plus1[i]");
> +    for (uint32_t i = 0; i <= vps.maxTempSubLayers - 1; i++)
> +    {
> +        WRITE_UVLC(vps.maxDecPicBuffering - 1, "vps_max_dec_pic_buffering_minus1[i]");
> +        WRITE_UVLC(vps.numReorderPics,         "vps_num_reorder_pics[i]");
> +        WRITE_UVLC(0,    "vps_max_latency_increase_plus1[i]");
> +    }
> +
>      WRITE_CODE(0, 6, "vps_max_nuh_reserved_zero_layer_id");
>      WRITE_UVLC(0,    "vps_max_op_sets_minus1");
>      WRITE_FLAG(0,    "vps_timing_info_present_flag"); /* we signal timing info in SPS-VUI */
> @@ -71,10 +76,11 @@
>  void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl)
>  {
>      WRITE_CODE(0, 4, "sps_video_parameter_set_id");
> -    WRITE_CODE(0, 3, "sps_max_sub_layers_minus1");
> -    WRITE_FLAG(1,    "sps_temporal_id_nesting_flag");
> +    WRITE_CODE(sps.maxTempSubLayers - 1, 3, "sps_max_sub_layers_minus1");
> +    // Temporal Id Nesting is disabled only when maxTemporalLayers > 1
> +    WRITE_FLAG(!(sps.maxTempSubLayers - 1), "sps_temporal_id_nesting_flag");
>  
> -    codeProfileTier(ptl);
> +    codeProfileTier(ptl, sps.maxTempSubLayers - 1);
>  
>      WRITE_UVLC(0, "sps_seq_parameter_set_id");
>      WRITE_UVLC(sps.chromaFormatIdc, "chroma_format_idc");
> @@ -101,9 +107,12 @@
>      WRITE_UVLC(BITS_FOR_POC - 4, "log2_max_pic_order_cnt_lsb_minus4");
>      WRITE_FLAG(true,             "sps_sub_layer_ordering_info_present_flag");
>  
> -    WRITE_UVLC(sps.maxDecPicBuffering - 1, "sps_max_dec_pic_buffering_minus1[i]");
> -    WRITE_UVLC(sps.numReorderPics,         "sps_num_reorder_pics[i]");
> -    WRITE_UVLC(sps.maxLatencyIncrease + 1, "sps_max_latency_increase_plus1[i]");
> +    for (uint32_t i = 0; i <= sps.maxTempSubLayers - 1; i++)
> +    {
> +        WRITE_UVLC(sps.maxDecPicBuffering - 1, "sps_max_dec_pic_buffering_minus1[i]");
> +        WRITE_UVLC(sps.numReorderPics,         "sps_num_reorder_pics[i]");
> +        WRITE_UVLC(sps.maxLatencyIncrease + 1, "sps_max_latency_increase_plus1[i]");
> +    }
>  
>      WRITE_UVLC(sps.log2MinCodingBlockSize - 3,    "log2_min_coding_block_size_minus3");
>      WRITE_UVLC(sps.log2DiffMaxMinCodingBlockSize, "log2_diff_max_min_coding_block_size");
> @@ -184,7 +193,7 @@
>      WRITE_FLAG(0, "pps_extension_flag");
>  }
>  
> -void Entropy::codeProfileTier(const ProfileTierLevel& ptl)
> +void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayerMinus1)
>  {
>      WRITE_CODE(0, 2,                "XXX_profile_space[]");
>      WRITE_FLAG(ptl.tierFlag,        "XXX_tier_flag[]");
> @@ -222,6 +231,14 @@
>      }
>  
>      WRITE_CODE(ptl.levelIdc, 8, "general_level_idc");
> +
> +    if (maxTempSubLayerMinus1)
> +    {
> +         WRITE_FLAG(0, "sub_layer_profile_present_flag[i]");
> +         WRITE_FLAG(0, "sub_layer_level_present_flag[i]");
> +         for (int i = maxTempSubLayerMinus1; i < 8 ; i++)
> +             WRITE_CODE(0, 2, "reserved_zero_2bits");
> +    }
>  }
>  
>  void Entropy::codeVUI(const VUI& vui)
> @@ -331,24 +348,27 @@
>  
>  void Entropy::codeHrdParameters(const HRDInfo& hrd)
>  {
> -    WRITE_FLAG(1, "nal_hrd_parameters_present_flag");
> -    WRITE_FLAG(0, "vcl_hrd_parameters_present_flag");
> -    WRITE_FLAG(0, "sub_pic_hrd_params_present_flag");
> +    for(int i = 0; i <= 1; i++)

white-space fixed here

> +    {
> +        WRITE_FLAG(1, "nal_hrd_parameters_present_flag");
> +        WRITE_FLAG(0, "vcl_hrd_parameters_present_flag");
> +        WRITE_FLAG(0, "sub_pic_hrd_params_present_flag");
>  
> -    WRITE_CODE(hrd.bitRateScale, 4, "bit_rate_scale");
> -    WRITE_CODE(hrd.cpbSizeScale, 4, "cpb_size_scale");
> +        WRITE_CODE(hrd.bitRateScale, 4, "bit_rate_scale");
> +        WRITE_CODE(hrd.cpbSizeScale, 4, "cpb_size_scale");
>  
> -    WRITE_CODE(hrd.initialCpbRemovalDelayLength - 1, 5, "initial_cpb_removal_delay_length_minus1");
> -    WRITE_CODE(hrd.cpbRemovalDelayLength - 1,        5, "au_cpb_removal_delay_length_minus1");
> -    WRITE_CODE(hrd.dpbOutputDelayLength - 1,         5, "dpb_output_delay_length_minus1");
> +        WRITE_CODE(hrd.initialCpbRemovalDelayLength - 1, 5, "initial_cpb_removal_delay_length_minus1");
> +        WRITE_CODE(hrd.cpbRemovalDelayLength - 1,        5, "au_cpb_removal_delay_length_minus1");
> +        WRITE_CODE(hrd.dpbOutputDelayLength - 1,         5, "dpb_output_delay_length_minus1");
>  
> -    WRITE_FLAG(1, "fixed_pic_rate_general_flag");
> -    WRITE_UVLC(0, "elemental_duration_in_tc_minus1");
> -    WRITE_UVLC(0, "cpb_cnt_minus1");
> +        WRITE_FLAG(1, "fixed_pic_rate_general_flag");
> +        WRITE_UVLC(0, "elemental_duration_in_tc_minus1");
> +        WRITE_UVLC(0, "cpb_cnt_minus1");
>  
> -    WRITE_UVLC(hrd.bitRateValue - 1, "bit_rate_value_minus1");
> -    WRITE_UVLC(hrd.cpbSizeValue - 1, "cpb_size_value_minus1");
> -    WRITE_FLAG(hrd.cbrFlag, "cbr_flag");
> +        WRITE_UVLC(hrd.bitRateValue - 1, "bit_rate_value_minus1");
> +        WRITE_UVLC(hrd.cpbSizeValue - 1, "cpb_size_value_minus1");
> +        WRITE_FLAG(hrd.cbrFlag, "cbr_flag");
> +    }
>  }
>  
>  void Entropy::codeAUD(const Slice& slice)
> diff -r 4583eda4cf55 -r 830d29c97117 source/encoder/entropy.h
> --- a/source/encoder/entropy.h	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/encoder/entropy.h	Tue Feb 03 16:21:21 2015 +0530
> @@ -230,7 +230,7 @@
>      void writeEpExGolomb(uint32_t symbol, uint32_t count);
>      void writeCoefRemainExGolomb(uint32_t symbol, const uint32_t absGoRice);
>  
> -    void codeProfileTier(const ProfileTierLevel& ptl);
> +    void codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayerMinus1);
>      void codeScalingList(const ScalingList&);
>      void codeScalingList(const ScalingList& scalingList, uint32_t sizeId, uint32_t listId);
>  
> diff -r 4583eda4cf55 -r 830d29c97117 source/encoder/level.cpp
> --- a/source/encoder/level.cpp	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/encoder/level.cpp	Tue Feb 03 16:21:21 2015 +0530
> @@ -60,6 +60,7 @@
>  /* determine minimum decoder level required to decode the described video */
>  void determineLevel(const x265_param &param, VPS& vps)
>  {
> +    vps.maxTempSubLayers = param.bEnableTemporalSubLayers ? 2 : 1;
>      if (param.bLossless)
>          vps.ptl.profileIdc = Profile::NONE;
>      else if (param.internalCsp == X265_CSP_I420)
> diff -r 4583eda4cf55 -r 830d29c97117 source/encoder/nal.cpp
> --- a/source/encoder/nal.cpp	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/encoder/nal.cpp	Tue Feb 03 16:21:21 2015 +0530
> @@ -107,7 +107,7 @@
>       * nuh_reserved_zero_6bits  6-bits
>       * nuh_temporal_id_plus1    3-bits */
>      out[bytes++] = (uint8_t)nalUnitType << 1;
> -    out[bytes++] = 1;
> +    out[bytes++] = 1 + (nalUnitType == NAL_UNIT_CODED_SLICE_TSA_N);
>  
>      /* 7.4.1 ...
>       * Within the NAL unit, the following three-byte sequences shall not occur at
> diff -r 4583eda4cf55 -r 830d29c97117 source/x265.h
> --- a/source/x265.h	Mon Feb 02 17:03:40 2015 +0530
> +++ b/source/x265.h	Tue Feb 03 16:21:21 2015 +0530
> @@ -791,6 +791,12 @@
>       * CU. */
>      int       bCULossless;
>  
> +    /* Enable Temporal Sub Layers while encoding, signals NAL units of coded slices
> +     * with their temporalId. Output bitstreams can be extracted either at the base temporal layer
> +     * (layer 0) with roughly half the frame rate or at a higher temporal layer (layer 1)
> +     * that decodes all the frames in the sequence. */
> +    int       bEnableTemporalSubLayers;
> +
>      /*== Rate Control ==*/
>  
>      struct
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel

-- 
Steve Borho


More information about the x265-devel mailing list