[x265] [PATCH] Reorder miniGOP based on temporal layer hierarchy and add support for more B frame layers

Kirithika Kalirathnam kirithika at multicorewareinc.com
Mon Dec 26 11:36:29 UTC 2022


>From 726b72802553ebcab1cc4758f3181f25a4f9105d Mon Sep 17 00:00:00 2001
From: Kirithika <kirithika at multicorewareinc.com>
Date: Fri, 16 Dec 2022 19:05:38 +0530
Subject: [PATCH] Reorder miniGOP based on temporal layer hierarchy and add
 support for more B frame layers

---
 source/common/frame.h        |   2 +
 source/encoder/encoder.cpp   |   8 +
 source/encoder/slicetype.cpp | 570 +++++++++++++++++++++++++++++------
 source/encoder/slicetype.h   |   5 +
 4 files changed, 491 insertions(+), 94 deletions(-)

diff --git a/source/common/frame.h b/source/common/frame.h
index 1ef0547bd..c916f7714 100644
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -90,6 +90,7 @@ public:

     int                    m_poc;
     int                    m_encodeOrder;
+    int                    m_gopOffset;
     int64_t                m_pts;                // user provided
presentation time stamp
     int64_t                m_reorderedPts;
     int64_t                m_dts;
@@ -161,6 +162,7 @@ public:

     /*Frame's temporal layer info*/
     uint8_t                m_tempLayer;
+    int8_t                 m_gopId;
     Frame();

     bool create(x265_param *param, float* quantOffsets);
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 91c0ae24f..51068a875 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -2307,6 +2307,14 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture* pic_out)
                 analysis->numPartitions  = m_param->num4x4Partitions;
                 x265_alloc_analysis_data(m_param, analysis);
             }
+            if (m_param->bEnableTemporalSubLayers > 2)
+            {
+                //Re-assign temporalid if the current frame is at the end
of encode or when I slice is encountered
+                if ((frameEnc->m_poc == (m_param->totalFrames - 1)) ||
(frameEnc->m_lowres.sliceType == X265_TYPE_I) ||
(frameEnc->m_lowres.sliceType == X265_TYPE_IDR))
+                {
+                    frameEnc->m_tempLayer = (int8_t)0;
+                }
+            }
             /* determine references, setup RPS, etc */
             m_dpb->prepareEncode(frameEnc);

diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
index 78977bed8..ca5c5ae4a 100644
--- a/source/encoder/slicetype.cpp
+++ b/source/encoder/slicetype.cpp
@@ -1082,6 +1082,24 @@ Lookahead::Lookahead(x265_param *param, ThreadPool*
pool)
     m_resetRunningAvg = true;

     m_segmentCountThreshold =
(uint32_t)(((float)((NUMBER_OF_SEGMENTS_IN_WIDTH *
NUMBER_OF_SEGMENTS_IN_HEIGHT) * 50) / 100) + 0.5);
+
+    if (m_param->bEnableTemporalSubLayers > 2)
+    {
+        switch (m_param->bEnableTemporalSubLayers)
+        {
+        case 3:
+            m_gopId = 0;
+            break;
+        case 4:
+            m_gopId = 1;
+            break;
+        case 5:
+            m_gopId = 2;
+            break;
+        default:
+            break;
+        }
+    }
 }

 #if DETAILED_CU_STATS
@@ -1793,6 +1811,53 @@ void PreLookaheadGroup::processTasks(int
workerThreadID)
     m_lock.release();
 }

+
+void Lookahead::placeBref(Frame** frames, int start, int end, int num, int
*brefs)
+{
+    int avg = (start + end) / 2;
+    if (m_param->bEnableTemporalSubLayers < 2)
+    {
+        (*frames[avg]).m_lowres.sliceType = X265_TYPE_BREF;
+        (*brefs)++;
+        return;
+    }
+    else
+    {
+        if (num <= 2)
+            return;
+        else
+        {
+            (*frames[avg]).m_lowres.sliceType = X265_TYPE_BREF;
+            (*brefs)++;
+            placeBref(frames, start, avg, avg - start, brefs);
+            placeBref(frames, avg + 1, end, end - avg, brefs);
+            return;
+        }
+    }
+}
+
+
+void Lookahead::compCostBref(Lowres **frames, int start, int end, int num)
+{
+    CostEstimateGroup estGroup(*this, frames);
+    int avg = (start + end) / 2;
+    if (num <= 2)
+    {
+        for (int i = start; i < end; i++)
+        {
+            estGroup.singleCost(start, end + 1, i + 1);
+        }
+        return;
+    }
+    else
+    {
+        estGroup.singleCost(start, end + 1, avg + 1);
+        compCostBref(frames, start, avg, avg - start);
+        compCostBref(frames, avg + 1, end, end - avg);
+        return;
+    }
+}
+
 /* called by API thread or worker thread with inputQueueLock acquired */
 void Lookahead::slicetypeDecide()
 {
@@ -2038,137 +2103,454 @@ void Lookahead::slicetypeDecide()
                 break;
         }
     }
-    if (bframes)
-        list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;
-    list[bframes]->m_lowres.leadingBframes = bframes;
-    m_lastNonB = &list[bframes]->m_lowres;

-    /* insert a bref into the sequence */
-    if (m_param->bBPyramid && bframes > 1 && !brefs)
-    {
-        list[bframes / 2]->m_lowres.sliceType = X265_TYPE_BREF;
-        brefs++;
-    }
-    /* calculate the frame costs ahead of time for estimateFrameCost while
we still have lowres */
-    if (m_param->rc.rateControlMode != X265_RC_CQP)
+    if (m_param->bEnableTemporalSubLayers > 2)
     {
-        int p0, p1, b;
-        /* For zero latency tuning, calculate frame cost to be used later
in RC */
-        if (!maxSearch)
+        //Split the partial mini GOP into sub mini GOPs when temporal sub
layers are enabled
+        if (bframes < m_param->bframes)
         {
-            for (int i = 0; i <= bframes; i++)
-               frames[i + 1] = &list[i]->m_lowres;
-        }
+            int leftOver = bframes + 1;
+            int8_t gopId = m_gopId - 1;
+            int gopLen = x265_gop_ra_length[gopId];
+            int listReset = 0;

-        /* estimate new non-B cost */
-        p1 = b = bframes + 1;
-        p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b : 0;
+            m_outputLock.acquire();

-        CostEstimateGroup estGroup(*this, frames);
+            while ((gopId >= 0) && (leftOver > 3))
+            {
+                if (leftOver < gopLen)
+                {
+                    gopId = gopId - 1;
+                    gopLen = x265_gop_ra_length[gopId];
+                    continue;
+                }
+                else
+                {
+                    int newbFrames = listReset + gopLen - 1;
+                    //Re-assign GOP
+                    list[newbFrames]->m_lowres.sliceType =
IS_X265_TYPE_I(list[newbFrames]->m_lowres.sliceType) ?
list[newbFrames]->m_lowres.sliceType : X265_TYPE_P;
+                    if (newbFrames)
+                        list[newbFrames - 1]->m_lowres.bLastMiniGopBFrame
= true;
+                    list[newbFrames]->m_lowres.leadingBframes = newbFrames;
+                    m_lastNonB = &list[newbFrames]->m_lowres;
+
+                    /* insert a bref into the sequence */
+                    if (m_param->bBPyramid && newbFrames)
+                    {
+                        placeBref(list, listReset, newbFrames, newbFrames
+ 1, &brefs);
+                    }
+                    if (m_param->rc.rateControlMode != X265_RC_CQP)
+                    {
+                        int p0, p1, b;
+                        /* For zero latency tuning, calculate frame cost
to be used later in RC */
+                        if (!maxSearch)
+                        {
+                            for (int i = listReset; i <= newbFrames; i++)
+                                frames[i + 1] = &list[listReset +
i]->m_lowres;
+                        }

-        estGroup.singleCost(p0, p1, b);
+                        /* estimate new non-B cost */
+                        p1 = b = newbFrames + 1;
+                        p0 = (IS_X265_TYPE_I(frames[newbFrames +
1]->sliceType)) ? b : listReset;

-        if (bframes)
-        {
-            p0 = 0; // last nonb
-            bool isp0available = frames[bframes + 1]->sliceType ==
X265_TYPE_IDR ? false : true;
+                        CostEstimateGroup estGroup(*this, frames);
+
+                        estGroup.singleCost(p0, p1, b);
+
+                        if (newbFrames)
+                            compCostBref(frames, listReset, newbFrames,
newbFrames + 1);
+                    }
+
+                    m_inputLock.acquire();
+                    /* dequeue all frames from inputQueue that are about
to be enqueued
+                     * in the output queue. The order is important because
Frame can
+                     * only be in one list at a time */
+                    int64_t pts[X265_BFRAME_MAX + 1];
+                    for (int i = 0; i < gopLen; i++)
+                    {
+                        Frame *curFrame;
+                        curFrame = m_inputQueue.popFront();
+                        pts[i] = curFrame->m_pts;
+                        maxSearch--;
+                    }
+                    m_inputLock.release();
+
+                    int idx = 0;
+                    /* add non-B to output queue */
+                    list[newbFrames]->m_reorderedPts = pts[idx++];
+                    list[newbFrames]->m_gopOffset = 0;
+                    list[newbFrames]->m_gopId = gopId;
+                    list[newbFrames]->m_tempLayer =
x265_gop_ra[gopId][0].layer;
+                    m_outputQueue.pushBack(*list[newbFrames]);
+
+                    /* add B frames to output queue */
+                    int i = 1, j = 1;
+                    while (i < gopLen)
+                    {
+                        int offset = listReset +
(x265_gop_ra[gopId][j].poc_offset - 1);
+                        if (!list[offset] || offset == newbFrames)
+                            continue;
+
+                        // Assign gop offset and temporal layer of frames
+                        list[offset]->m_gopOffset = j;
+                        list[bframes]->m_gopId = gopId;
+                        list[offset]->m_tempLayer =
x265_gop_ra[gopId][j++].layer;
+
+                        list[offset]->m_reorderedPts = pts[idx++];
+                        m_outputQueue.pushBack(*list[offset]);
+                        i++;
+                    }
+
+                    listReset += gopLen;
+                    leftOver = leftOver - gopLen;
+                    gopId -= 1;
+                    gopLen = (gopId >= 0) ? x265_gop_ra_length[gopId] : 0;
+                }
+            }

-            for (b = 1; b <= bframes; b++)
+            if (leftOver > 0 && leftOver < 4)
             {
-                if (!isp0available)
-                    p0 = b;
+                int64_t pts[X265_BFRAME_MAX + 1];
+                int idx = 0;

-                if (frames[b]->sliceType == X265_TYPE_B)
-                    for (p1 = b; frames[p1]->sliceType == X265_TYPE_B;
p1++)
-                        ; // find new nonb or bref
-                else
-                    p1 = bframes + 1;
+                int newbFrames = listReset + leftOver - 1;
+                list[newbFrames]->m_lowres.sliceType =
IS_X265_TYPE_I(list[newbFrames]->m_lowres.sliceType) ?
list[newbFrames]->m_lowres.sliceType : X265_TYPE_P;
+                if (newbFrames)
+                        list[newbFrames - 1]->m_lowres.bLastMiniGopBFrame
= true;
+                list[newbFrames]->m_lowres.leadingBframes = newbFrames;
+                m_lastNonB = &list[newbFrames]->m_lowres;

-                estGroup.singleCost(p0, p1, b);
+                /* insert a bref into the sequence */
+                if (m_param->bBPyramid && (newbFrames- listReset) > 1)
+                    placeBref(list, listReset, newbFrames, newbFrames + 1,
&brefs);
+
+                if (m_param->rc.rateControlMode != X265_RC_CQP)
+                {
+                    int p0, p1, b;
+                    /* For zero latency tuning, calculate frame cost to be
used later in RC */
+                    if (!maxSearch)
+                    {
+                        for (int i = listReset; i <= newbFrames; i++)
+                            frames[i + 1] = &list[listReset + i]->m_lowres;
+                    }
+
+                        /* estimate new non-B cost */
+                    p1 = b = newbFrames + 1;
+                    p0 = (IS_X265_TYPE_I(frames[newbFrames +
1]->sliceType)) ? b : listReset;
+
+                    CostEstimateGroup estGroup(*this, frames);
+
+                    estGroup.singleCost(p0, p1, b);

-                if (frames[b]->sliceType == X265_TYPE_BREF)
+                    if (newbFrames)
+                        compCostBref(frames, listReset, newbFrames,
newbFrames + 1);
+                }
+
+                m_inputLock.acquire();
+                /* dequeue all frames from inputQueue that are about to be
enqueued
+                 * in the output queue. The order is important because
Frame can
+                 * only be in one list at a time */
+                for (int i = 0; i < leftOver; i++)
+                {
+                    Frame *curFrame;
+                    curFrame = m_inputQueue.popFront();
+                    pts[i] = curFrame->m_pts;
+                    maxSearch--;
+                }
+                m_inputLock.release();
+
+                m_lastNonB = &list[newbFrames]->m_lowres;
+                list[newbFrames]->m_reorderedPts = pts[idx++];
+                list[newbFrames]->m_gopOffset = 0;
+                list[newbFrames]->m_gopId = -1;
+                list[newbFrames]->m_tempLayer = 0;
+                m_outputQueue.pushBack(*list[newbFrames]);
+                if (brefs)
                 {
-                    p0 = b;
-                    isp0available = true;
+                    for (int i = listReset; i < newbFrames; i++)
+                    {
+                        if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)
+                        {
+                            list[i]->m_reorderedPts = pts[idx++];
+                            list[i]->m_gopOffset = 0;
+                            list[i]->m_gopId = -1;
+                            list[i]->m_tempLayer = 0;
+                            m_outputQueue.pushBack(*list[i]);
+                        }
+                    }
+                }
+
+                /* add B frames to output queue */
+                for (int i = listReset; i < newbFrames; i++)
+                {
+                    /* push all the B frames into output queue except
B-ref, which already pushed into output queue */
+                    if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)
+                    {
+                        list[i]->m_reorderedPts = pts[idx++];
+                        list[i]->m_gopOffset = 0;
+                        list[i]->m_gopId = -1;
+                        list[i]->m_tempLayer = 1;
+                        m_outputQueue.pushBack(*list[i]);
+                    }
                 }
             }
         }
-    }
+        else
+        // Fill the complete mini GOP when temporal sub layers are enabled
+        {

-    m_inputLock.acquire();
-    /* dequeue all frames from inputQueue that are about to be enqueued
-     * in the output queue. The order is important because Frame can
-     * only be in one list at a time */
-    int64_t pts[X265_BFRAME_MAX + 1];
-    for (int i = 0; i <= bframes; i++)
-    {
-        Frame *curFrame;
-        curFrame = m_inputQueue.popFront();
-        pts[i] = curFrame->m_pts;
-        maxSearch--;
-    }
-    m_inputLock.release();
+            list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;
+            list[bframes]->m_lowres.leadingBframes = bframes;
+            m_lastNonB = &list[bframes]->m_lowres;

-    m_outputLock.acquire();
-    /* add non-B to output queue */
-    int idx = 0;
-    list[bframes]->m_reorderedPts = pts[idx++];
-    m_outputQueue.pushBack(*list[bframes]);
-    /* Add B-ref frame next to P frame in output queue, the B-ref encode
before non B-ref frame */
-    if (brefs)
-    {
-        for (int i = 0; i < bframes; i++)
+            /* insert a bref into the sequence */
+            if (m_param->bBPyramid && !brefs)
+            {
+                placeBref(list, 0, bframes, bframes + 1, &brefs);
+            }
+
+            /* calculate the frame costs ahead of time for
estimateFrameCost while we still have lowres */
+            if (m_param->rc.rateControlMode != X265_RC_CQP)
+            {
+                int p0, p1, b;
+                /* For zero latency tuning, calculate frame cost to be
used later in RC */
+                if (!maxSearch)
+                {
+                    for (int i = 0; i <= bframes; i++)
+                        frames[i + 1] = &list[i]->m_lowres;
+                }
+
+                /* estimate new non-B cost */
+                p1 = b = bframes + 1;
+                p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b
: 0;
+
+                CostEstimateGroup estGroup(*this, frames);
+                estGroup.singleCost(p0, p1, b);
+
+                compCostBref(frames, 0, bframes, bframes + 1);
+            }
+
+            m_inputLock.acquire();
+            /* dequeue all frames from inputQueue that are about to be
enqueued
+            * in the output queue. The order is important because Frame can
+            * only be in one list at a time */
+            int64_t pts[X265_BFRAME_MAX + 1];
+            for (int i = 0; i <= bframes; i++)
+            {
+                Frame *curFrame;
+                curFrame = m_inputQueue.popFront();
+                pts[i] = curFrame->m_pts;
+                maxSearch--;
+            }
+            m_inputLock.release();
+
+            m_outputLock.acquire();
+
+            int idx = 0;
+            /* add non-B to output queue */
+            list[bframes]->m_reorderedPts = pts[idx++];
+            list[bframes]->m_gopOffset = 0;
+            list[bframes]->m_gopId = m_gopId;
+            list[bframes]->m_tempLayer = x265_gop_ra[m_gopId][0].layer;
+            m_outputQueue.pushBack(*list[bframes]);
+
+            int i = 1, j = 1;
+            while (i <= bframes)
+            {
+                int offset = x265_gop_ra[m_gopId][j].poc_offset - 1;
+                if (!list[offset] || offset == bframes)
+                    continue;
+
+                // Assign gop offset and temporal layer of frames
+                list[offset]->m_gopOffset = j;
+                list[offset]->m_gopId = m_gopId;
+                list[offset]->m_tempLayer =
x265_gop_ra[m_gopId][j++].layer;
+
+                /* add B frames to output queue */
+                list[offset]->m_reorderedPts = pts[idx++];
+                m_outputQueue.pushBack(*list[offset]);
+                i++;
+            }
+        }
+
+        bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
(m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
+        if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
         {
-            if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)
+            m_inputLock.acquire();
+            Frame *curFrame = m_inputQueue.first();
+            frames[0] = m_lastNonB;
+            int j;
+            for (j = 0; j < maxSearch; j++)
             {
-                list[i]->m_reorderedPts = pts[idx++];
-                m_outputQueue.pushBack(*list[i]);
+                frames[j + 1] = &curFrame->m_lowres;
+                curFrame = curFrame->m_next;
+            }
+            m_inputLock.release();
+
+            frames[j + 1] = NULL;
+            if (!m_param->rc.bStatRead)
+                slicetypeAnalyse(frames, true);
+            bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
m_param->rc.vbvMaxBitrate > 0;
+            if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
|| m_param->bliveVBV2pass)
+            {
+                int numFrames;
+                for (numFrames = 0; numFrames < maxSearch; numFrames++)
+                {
+                    Lowres *fenc = frames[numFrames + 1];
+                    if (!fenc)
+                        break;
+                }
+                vbvLookahead(frames, numFrames, true);
             }
         }
-    }

-    /* add B frames to output queue */
-    for (int i = 0; i < bframes; i++)
+
+        m_outputLock.release();
+    }
+    else
     {
-        /* push all the B frames into output queue except B-ref, which
already pushed into output queue */
-        if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)
+
+        if (bframes)
+            list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;
+        list[bframes]->m_lowres.leadingBframes = bframes;
+        m_lastNonB = &list[bframes]->m_lowres;
+
+        /* insert a bref into the sequence */
+        if (m_param->bBPyramid && bframes > 1 && !brefs)
         {
-            list[i]->m_reorderedPts = pts[idx++];
-            m_outputQueue.pushBack(*list[i]);
+            placeBref(list, 0, bframes, bframes + 1, &brefs);
+        }
+        /* calculate the frame costs ahead of time for estimateFrameCost
while we still have lowres */
+        if (m_param->rc.rateControlMode != X265_RC_CQP)
+        {
+            int p0, p1, b;
+            /* For zero latency tuning, calculate frame cost to be used
later in RC */
+            if (!maxSearch)
+            {
+                for (int i = 0; i <= bframes; i++)
+                    frames[i + 1] = &list[i]->m_lowres;
+            }
+
+            /* estimate new non-B cost */
+            p1 = b = bframes + 1;
+            p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b : 0;
+
+            CostEstimateGroup estGroup(*this, frames);
+            estGroup.singleCost(p0, p1, b);
+
+            if (m_param->bEnableTemporalSubLayers > 1 && bframes)
+            {
+                compCostBref(frames, 0, bframes, bframes + 1);
+            }
+            else
+            {
+                if (bframes)
+                {
+                    p0 = 0; // last nonb
+                    bool isp0available = frames[bframes + 1]->sliceType ==
X265_TYPE_IDR ? false : true;
+
+                    for (b = 1; b <= bframes; b++)
+                    {
+                        if (!isp0available)
+                            p0 = b;
+
+                        if (frames[b]->sliceType == X265_TYPE_B)
+                            for (p1 = b; frames[p1]->sliceType ==
X265_TYPE_B; p1++)
+                                ; // find new nonb or bref
+                        else
+                            p1 = bframes + 1;
+
+                        estGroup.singleCost(p0, p1, b);
+
+                        if (frames[b]->sliceType == X265_TYPE_BREF)
+                        {
+                            p0 = b;
+                            isp0available = true;
+                        }
+                    }
+                }
+            }
         }
-    }

-    bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
(m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
-    if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
-    {
         m_inputLock.acquire();
-        Frame *curFrame = m_inputQueue.first();
-        frames[0] = m_lastNonB;
-        int j;
-        for (j = 0; j < maxSearch; j++)
+        /* dequeue all frames from inputQueue that are about to be enqueued
+         * in the output queue. The order is important because Frame can
+         * only be in one list at a time */
+        int64_t pts[X265_BFRAME_MAX + 1];
+        for (int i = 0; i <= bframes; i++)
         {
-            frames[j + 1] = &curFrame->m_lowres;
-            curFrame = curFrame->m_next;
+            Frame *curFrame;
+            curFrame = m_inputQueue.popFront();
+            pts[i] = curFrame->m_pts;
+            maxSearch--;
         }
         m_inputLock.release();

-        frames[j + 1] = NULL;
-        if (!m_param->rc.bStatRead)
-            slicetypeAnalyse(frames, true);
-        bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
m_param->rc.vbvMaxBitrate > 0;
-        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) ||
m_param->bliveVBV2pass)
+        m_outputLock.acquire();
+
+        /* add non-B to output queue */
+        int idx = 0;
+        list[bframes]->m_reorderedPts = pts[idx++];
+        m_outputQueue.pushBack(*list[bframes]);
+
+        /* Add B-ref frame next to P frame in output queue, the B-ref
encode before non B-ref frame */
+        if (brefs)
         {
-            int numFrames;
-            for (numFrames = 0; numFrames < maxSearch; numFrames++)
+            for (int i = 0; i < bframes; i++)
             {
-                Lowres *fenc = frames[numFrames + 1];
-                if (!fenc)
-                    break;
+                if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)
+                {
+                    list[i]->m_reorderedPts = pts[idx++];
+                    m_outputQueue.pushBack(*list[i]);
+                }
+            }
+        }
+
+        /* add B frames to output queue */
+        for (int i = 0; i < bframes; i++)
+        {
+            /* push all the B frames into output queue except B-ref, which
already pushed into output queue */
+            if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)
+            {
+                list[i]->m_reorderedPts = pts[idx++];
+                m_outputQueue.pushBack(*list[i]);
+            }
+        }
+
+
+        bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
(m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
+        if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
+        {
+            m_inputLock.acquire();
+            Frame *curFrame = m_inputQueue.first();
+            frames[0] = m_lastNonB;
+            int j;
+            for (j = 0; j < maxSearch; j++)
+            {
+                frames[j + 1] = &curFrame->m_lowres;
+                curFrame = curFrame->m_next;
+            }
+            m_inputLock.release();
+
+            frames[j + 1] = NULL;
+            if (!m_param->rc.bStatRead)
+                slicetypeAnalyse(frames, true);
+            bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
m_param->rc.vbvMaxBitrate > 0;
+            if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
|| m_param->bliveVBV2pass)
+            {
+                int numFrames;
+                for (numFrames = 0; numFrames < maxSearch; numFrames++)
+                {
+                    Lowres *fenc = frames[numFrames + 1];
+                    if (!fenc)
+                        break;
+                }
+                vbvLookahead(frames, numFrames, true);
             }
-            vbvLookahead(frames, numFrames, true);
         }
+
+        m_outputLock.release();
     }
-    m_outputLock.release();
 }

 void Lookahead::vbvLookahead(Lowres **frames, int numFrames, int keyframe)
diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h
index 05cef800b..f4184e4e2 100644
--- a/source/encoder/slicetype.h
+++ b/source/encoder/slicetype.h
@@ -200,6 +200,8 @@ public:
     bool          m_resetRunningAvg;
     uint32_t      m_segmentCountThreshold;

+    int8_t                  m_gopId;
+
     Lookahead(x265_param *param, ThreadPool *pool);
 #if DETAILED_CU_STATS
     int64_t       m_slicetypeDecideElapsedTime;
@@ -251,6 +253,9 @@ protected:

     /* called by getEstimatedPictureCost() to finalize cuTree costs */
     int64_t frameCostRecalculate(Lowres **frames, int p0, int p1, int b);
+    /*Compute index for positioning B-Ref frames*/
+    void     placeBref(Frame** frames, int start, int end, int num, int
*brefs);
+    void     compCostBref(Lowres **frame, int start, int end, int num);
 };

 class PreLookaheadGroup : public BondedTaskGroup
-- 
2.28.0.windows.1

*Thanks,*
*Kirithika*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221226/626ae7a2/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch-4.diff
Type: application/octet-stream
Size: 27560 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221226/626ae7a2/attachment-0001.obj>


More information about the x265-devel mailing list