<div dir="ltr">From 726b72802553ebcab1cc4758f3181f25a4f9105d Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com">kirithika@multicorewareinc.com</a>><br>Date: Fri, 16 Dec 2022 19:05:38 +0530<br>Subject: [PATCH] Reorder miniGOP based on temporal layer hierarchy and add<br> support for more B frame layers<br><br>---<br> source/common/frame.h        |   2 +<br> source/encoder/encoder.cpp   |   8 +<br> source/encoder/slicetype.cpp | 570 +++++++++++++++++++++++++++++------<br> source/encoder/slicetype.h   |   5 +<br> 4 files changed, 491 insertions(+), 94 deletions(-)<br><br>diff --git a/source/common/frame.h b/source/common/frame.h<br>index 1ef0547bd..c916f7714 100644<br>--- a/source/common/frame.h<br>+++ b/source/common/frame.h<br>@@ -90,6 +90,7 @@ public:<br> <br>     int                    m_poc;<br>     int                    m_encodeOrder;<br>+    int                    m_gopOffset;<br>     int64_t                m_pts;                // user provided presentation time stamp<br>     int64_t                m_reorderedPts;<br>     int64_t                m_dts;<br>@@ -161,6 +162,7 @@ public:<br> <br>     /*Frame's temporal layer info*/<br>     uint8_t                m_tempLayer;<br>+    int8_t                 m_gopId;<br>     Frame();<br> <br>     bool create(x265_param *param, float* quantOffsets);<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 91c0ae24f..51068a875 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -2307,6 +2307,14 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 analysis->numPartitions  = m_param->num4x4Partitions;<br>                 x265_alloc_analysis_data(m_param, analysis);<br>             }<br>+            if (m_param->bEnableTemporalSubLayers > 2)<br>+            {<br>+                //Re-assign temporalid if the current frame is at the end of encode or when I slice is encountered<br>+                if ((frameEnc->m_poc == (m_param->totalFrames - 1)) || (frameEnc->m_lowres.sliceType == X265_TYPE_I) || (frameEnc->m_lowres.sliceType == X265_TYPE_IDR))<br>+                {<br>+                    frameEnc->m_tempLayer = (int8_t)0;<br>+                }<br>+            }<br>             /* determine references, setup RPS, etc */<br>             m_dpb->prepareEncode(frameEnc);<br> <br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index 78977bed8..ca5c5ae4a 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -1082,6 +1082,24 @@ Lookahead::Lookahead(x265_param *param, ThreadPool* pool)<br>     m_resetRunningAvg = true;<br> <br>     m_segmentCountThreshold = (uint32_t)(((float)((NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT) * 50) / 100) + 0.5);<br>+<br>+    if (m_param->bEnableTemporalSubLayers > 2)<br>+    {<br>+        switch (m_param->bEnableTemporalSubLayers)<br>+        {<br>+        case 3:<br>+            m_gopId = 0;<br>+            break;<br>+        case 4:<br>+            m_gopId = 1;<br>+            break;<br>+        case 5:<br>+            m_gopId = 2;<br>+            break;<br>+        default:<br>+            break;<br>+        }<br>+    }<br> }<br> <br> #if DETAILED_CU_STATS<br>@@ -1793,6 +1811,53 @@ void PreLookaheadGroup::processTasks(int workerThreadID)<br>     m_lock.release();<br> }<br> <br>+<br>+void Lookahead::placeBref(Frame** frames, int start, int end, int num, int *brefs)<br>+{<br>+    int avg = (start + end) / 2;<br>+    if (m_param->bEnableTemporalSubLayers < 2)<br>+    {<br>+        (*frames[avg]).m_lowres.sliceType = X265_TYPE_BREF;<br>+        (*brefs)++;<br>+        return;<br>+    }<br>+    else<br>+    {<br>+        if (num <= 2)<br>+            return;<br>+        else<br>+        {<br>+            (*frames[avg]).m_lowres.sliceType = X265_TYPE_BREF;<br>+            (*brefs)++;<br>+            placeBref(frames, start, avg, avg - start, brefs);<br>+            placeBref(frames, avg + 1, end, end - avg, brefs);<br>+            return;<br>+        }<br>+    }<br>+}<br>+<br>+<br>+void Lookahead::compCostBref(Lowres **frames, int start, int end, int num)<br>+{<br>+    CostEstimateGroup estGroup(*this, frames);<br>+    int avg = (start + end) / 2;<br>+    if (num <= 2)<br>+    {<br>+        for (int i = start; i < end; i++)<br>+        {<br>+            estGroup.singleCost(start, end + 1, i + 1);<br>+        }<br>+        return;<br>+    }<br>+    else<br>+    {<br>+        estGroup.singleCost(start, end + 1, avg + 1);<br>+        compCostBref(frames, start, avg, avg - start);<br>+        compCostBref(frames, avg + 1, end, end - avg);<br>+        return;<br>+    }<br>+}<br>+<br> /* called by API thread or worker thread with inputQueueLock acquired */<br> void Lookahead::slicetypeDecide()<br> {<br>@@ -2038,137 +2103,454 @@ void Lookahead::slicetypeDecide()<br>                 break;<br>         }<br>     }<br>-    if (bframes)<br>-        list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;<br>-    list[bframes]->m_lowres.leadingBframes = bframes;<br>-    m_lastNonB = &list[bframes]->m_lowres;<br> <br>-    /* insert a bref into the sequence */<br>-    if (m_param->bBPyramid && bframes > 1 && !brefs)<br>-    {<br>-        list[bframes / 2]->m_lowres.sliceType = X265_TYPE_BREF;<br>-        brefs++;<br>-    }<br>-    /* calculate the frame costs ahead of time for estimateFrameCost while we still have lowres */<br>-    if (m_param->rc.rateControlMode != X265_RC_CQP)<br>+    if (m_param->bEnableTemporalSubLayers > 2)<br>     {<br>-        int p0, p1, b;<br>-        /* For zero latency tuning, calculate frame cost to be used later in RC */<br>-        if (!maxSearch)<br>+        //Split the partial mini GOP into sub mini GOPs when temporal sub layers are enabled<br>+        if (bframes < m_param->bframes)<br>         {<br>-            for (int i = 0; i <= bframes; i++)<br>-               frames[i + 1] = &list[i]->m_lowres;<br>-        }<br>+            int leftOver = bframes + 1;<br>+            int8_t gopId = m_gopId - 1;<br>+            int gopLen = x265_gop_ra_length[gopId];<br>+            int listReset = 0;<br> <br>-        /* estimate new non-B cost */<br>-        p1 = b = bframes + 1;<br>-        p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b : 0;<br>+            m_outputLock.acquire();<br> <br>-        CostEstimateGroup estGroup(*this, frames);<br>+            while ((gopId >= 0) && (leftOver > 3))<br>+            {<br>+                if (leftOver < gopLen)<br>+                {<br>+                    gopId = gopId - 1;<br>+                    gopLen = x265_gop_ra_length[gopId];<br>+                    continue;<br>+                }<br>+                else<br>+                {<br>+                    int newbFrames = listReset + gopLen - 1;<br>+                    //Re-assign GOP<br>+                    list[newbFrames]->m_lowres.sliceType = IS_X265_TYPE_I(list[newbFrames]->m_lowres.sliceType) ? list[newbFrames]->m_lowres.sliceType : X265_TYPE_P;<br>+                    if (newbFrames)<br>+                        list[newbFrames - 1]->m_lowres.bLastMiniGopBFrame = true;<br>+                    list[newbFrames]->m_lowres.leadingBframes = newbFrames;<br>+                    m_lastNonB = &list[newbFrames]->m_lowres;<br>+<br>+                    /* insert a bref into the sequence */<br>+                    if (m_param->bBPyramid && newbFrames)<br>+                    {<br>+                        placeBref(list, listReset, newbFrames, newbFrames + 1, &brefs);<br>+                    }<br>+                    if (m_param->rc.rateControlMode != X265_RC_CQP)<br>+                    {<br>+                        int p0, p1, b;<br>+                        /* For zero latency tuning, calculate frame cost to be used later in RC */<br>+                        if (!maxSearch)<br>+                        {<br>+                            for (int i = listReset; i <= newbFrames; i++)<br>+                                frames[i + 1] = &list[listReset + i]->m_lowres;<br>+                        }<br> <br>-        estGroup.singleCost(p0, p1, b);<br>+                        /* estimate new non-B cost */<br>+                        p1 = b = newbFrames + 1;<br>+                        p0 = (IS_X265_TYPE_I(frames[newbFrames + 1]->sliceType)) ? b : listReset;<br> <br>-        if (bframes)<br>-        {<br>-            p0 = 0; // last nonb<br>-            bool isp0available = frames[bframes + 1]->sliceType == X265_TYPE_IDR ? false : true;<br>+                        CostEstimateGroup estGroup(*this, frames);<br>+<br>+                        estGroup.singleCost(p0, p1, b);<br>+<br>+                        if (newbFrames)<br>+                            compCostBref(frames, listReset, newbFrames, newbFrames + 1);<br>+                    }<br>+<br>+                    m_inputLock.acquire();<br>+                    /* dequeue all frames from inputQueue that are about to be enqueued<br>+                     * in the output queue. The order is important because Frame can<br>+                     * only be in one list at a time */<br>+                    int64_t pts[X265_BFRAME_MAX + 1];<br>+                    for (int i = 0; i < gopLen; i++)<br>+                    {<br>+                        Frame *curFrame;<br>+                        curFrame = m_inputQueue.popFront();<br>+                        pts[i] = curFrame->m_pts;<br>+                        maxSearch--;<br>+                    }<br>+                    m_inputLock.release();<br>+<br>+                    int idx = 0;<br>+                    /* add non-B to output queue */<br>+                    list[newbFrames]->m_reorderedPts = pts[idx++];<br>+                    list[newbFrames]->m_gopOffset = 0;<br>+                    list[newbFrames]->m_gopId = gopId;<br>+                    list[newbFrames]->m_tempLayer = x265_gop_ra[gopId][0].layer;<br>+                    m_outputQueue.pushBack(*list[newbFrames]);<br>+<br>+                    /* add B frames to output queue */<br>+                    int i = 1, j = 1;<br>+                    while (i < gopLen)<br>+                    {<br>+                        int offset = listReset + (x265_gop_ra[gopId][j].poc_offset - 1);<br>+                        if (!list[offset] || offset == newbFrames)<br>+                            continue;<br>+<br>+                        // Assign gop offset and temporal layer of frames<br>+                        list[offset]->m_gopOffset = j;<br>+                        list[bframes]->m_gopId = gopId;<br>+                        list[offset]->m_tempLayer = x265_gop_ra[gopId][j++].layer;<br>+<br>+                        list[offset]->m_reorderedPts = pts[idx++];<br>+                        m_outputQueue.pushBack(*list[offset]);<br>+                        i++;<br>+                    }<br>+<br>+                    listReset += gopLen;<br>+                    leftOver = leftOver - gopLen;<br>+                    gopId -= 1;<br>+                    gopLen = (gopId >= 0) ? x265_gop_ra_length[gopId] : 0;<br>+                }<br>+            }<br> <br>-            for (b = 1; b <= bframes; b++)<br>+            if (leftOver > 0 && leftOver < 4)<br>             {<br>-                if (!isp0available)<br>-                    p0 = b;<br>+                int64_t pts[X265_BFRAME_MAX + 1];<br>+                int idx = 0;<br> <br>-                if (frames[b]->sliceType == X265_TYPE_B)<br>-                    for (p1 = b; frames[p1]->sliceType == X265_TYPE_B; p1++)<br>-                        ; // find new nonb or bref<br>-                else<br>-                    p1 = bframes + 1;<br>+                int newbFrames = listReset + leftOver - 1;<br>+                list[newbFrames]->m_lowres.sliceType = IS_X265_TYPE_I(list[newbFrames]->m_lowres.sliceType) ? list[newbFrames]->m_lowres.sliceType : X265_TYPE_P;<br>+                if (newbFrames)<br>+                        list[newbFrames - 1]->m_lowres.bLastMiniGopBFrame = true;<br>+                list[newbFrames]->m_lowres.leadingBframes = newbFrames;<br>+                m_lastNonB = &list[newbFrames]->m_lowres;<br> <br>-                estGroup.singleCost(p0, p1, b);<br>+                /* insert a bref into the sequence */<br>+                if (m_param->bBPyramid && (newbFrames- listReset) > 1)<br>+                    placeBref(list, listReset, newbFrames, newbFrames + 1, &brefs);<br>+<br>+                if (m_param->rc.rateControlMode != X265_RC_CQP)<br>+                {<br>+                    int p0, p1, b;<br>+                    /* For zero latency tuning, calculate frame cost to be used later in RC */<br>+                    if (!maxSearch)<br>+                    {<br>+                        for (int i = listReset; i <= newbFrames; i++)<br>+                            frames[i + 1] = &list[listReset + i]->m_lowres;<br>+                    }<br>+<br>+                        /* estimate new non-B cost */<br>+                    p1 = b = newbFrames + 1;<br>+                    p0 = (IS_X265_TYPE_I(frames[newbFrames + 1]->sliceType)) ? b : listReset;<br>+<br>+                    CostEstimateGroup estGroup(*this, frames);<br>+<br>+                    estGroup.singleCost(p0, p1, b);<br> <br>-                if (frames[b]->sliceType == X265_TYPE_BREF)<br>+                    if (newbFrames)<br>+                        compCostBref(frames, listReset, newbFrames, newbFrames + 1);<br>+                }<br>+<br>+                m_inputLock.acquire();<br>+                /* dequeue all frames from inputQueue that are about to be enqueued<br>+                 * in the output queue. The order is important because Frame can<br>+                 * only be in one list at a time */<br>+                for (int i = 0; i < leftOver; i++)<br>+                {<br>+                    Frame *curFrame;<br>+                    curFrame = m_inputQueue.popFront();<br>+                    pts[i] = curFrame->m_pts;<br>+                    maxSearch--;<br>+                }<br>+                m_inputLock.release();<br>+<br>+                m_lastNonB = &list[newbFrames]->m_lowres;<br>+                list[newbFrames]->m_reorderedPts = pts[idx++];<br>+                list[newbFrames]->m_gopOffset = 0;<br>+                list[newbFrames]->m_gopId = -1;<br>+                list[newbFrames]->m_tempLayer = 0;<br>+                m_outputQueue.pushBack(*list[newbFrames]);<br>+                if (brefs)<br>                 {<br>-                    p0 = b;<br>-                    isp0available = true;<br>+                    for (int i = listReset; i < newbFrames; i++)<br>+                    {<br>+                        if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)<br>+                        {<br>+                            list[i]->m_reorderedPts = pts[idx++];<br>+                            list[i]->m_gopOffset = 0;<br>+                            list[i]->m_gopId = -1;<br>+                            list[i]->m_tempLayer = 0;<br>+                            m_outputQueue.pushBack(*list[i]);<br>+                        }<br>+                    }<br>+                }<br>+<br>+                /* add B frames to output queue */<br>+                for (int i = listReset; i < newbFrames; i++)<br>+                {<br>+                    /* push all the B frames into output queue except B-ref, which already pushed into output queue */<br>+                    if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)<br>+                    {<br>+                        list[i]->m_reorderedPts = pts[idx++];<br>+                        list[i]->m_gopOffset = 0;<br>+                        list[i]->m_gopId = -1;<br>+                        list[i]->m_tempLayer = 1;<br>+                        m_outputQueue.pushBack(*list[i]);<br>+                    }<br>                 }<br>             }<br>         }<br>-    }<br>+        else<br>+        // Fill the complete mini GOP when temporal sub layers are enabled<br>+        {<br> <br>-    m_inputLock.acquire();<br>-    /* dequeue all frames from inputQueue that are about to be enqueued<br>-     * in the output queue. The order is important because Frame can<br>-     * only be in one list at a time */<br>-    int64_t pts[X265_BFRAME_MAX + 1];<br>-    for (int i = 0; i <= bframes; i++)<br>-    {<br>-        Frame *curFrame;<br>-        curFrame = m_inputQueue.popFront();<br>-        pts[i] = curFrame->m_pts;<br>-        maxSearch--;<br>-    }<br>-    m_inputLock.release();<br>+            list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;<br>+            list[bframes]->m_lowres.leadingBframes = bframes;<br>+            m_lastNonB = &list[bframes]->m_lowres;<br> <br>-    m_outputLock.acquire();<br>-    /* add non-B to output queue */<br>-    int idx = 0;<br>-    list[bframes]->m_reorderedPts = pts[idx++];<br>-    m_outputQueue.pushBack(*list[bframes]);<br>-    /* Add B-ref frame next to P frame in output queue, the B-ref encode before non B-ref frame */<br>-    if (brefs)<br>-    {<br>-        for (int i = 0; i < bframes; i++)<br>+            /* insert a bref into the sequence */<br>+            if (m_param->bBPyramid && !brefs)<br>+            {<br>+                placeBref(list, 0, bframes, bframes + 1, &brefs);<br>+            }<br>+<br>+            /* calculate the frame costs ahead of time for estimateFrameCost while we still have lowres */<br>+            if (m_param->rc.rateControlMode != X265_RC_CQP)<br>+            {<br>+                int p0, p1, b;<br>+                /* For zero latency tuning, calculate frame cost to be used later in RC */<br>+                if (!maxSearch)<br>+                {<br>+                    for (int i = 0; i <= bframes; i++)<br>+                        frames[i + 1] = &list[i]->m_lowres;<br>+                }<br>+<br>+                /* estimate new non-B cost */<br>+                p1 = b = bframes + 1;<br>+                p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b : 0;<br>+<br>+                CostEstimateGroup estGroup(*this, frames);<br>+                estGroup.singleCost(p0, p1, b);<br>+<br>+                compCostBref(frames, 0, bframes, bframes + 1);<br>+            }<br>+<br>+            m_inputLock.acquire();<br>+            /* dequeue all frames from inputQueue that are about to be enqueued<br>+            * in the output queue. The order is important because Frame can<br>+            * only be in one list at a time */<br>+            int64_t pts[X265_BFRAME_MAX + 1];<br>+            for (int i = 0; i <= bframes; i++)<br>+            {<br>+                Frame *curFrame;<br>+                curFrame = m_inputQueue.popFront();<br>+                pts[i] = curFrame->m_pts;<br>+                maxSearch--;<br>+            }<br>+            m_inputLock.release();<br>+<br>+            m_outputLock.acquire();<br>+<br>+            int idx = 0;<br>+            /* add non-B to output queue */<br>+            list[bframes]->m_reorderedPts = pts[idx++];<br>+            list[bframes]->m_gopOffset = 0;<br>+            list[bframes]->m_gopId = m_gopId;<br>+            list[bframes]->m_tempLayer = x265_gop_ra[m_gopId][0].layer;<br>+            m_outputQueue.pushBack(*list[bframes]);<br>+<br>+            int i = 1, j = 1;<br>+            while (i <= bframes)<br>+            {<br>+                int offset = x265_gop_ra[m_gopId][j].poc_offset - 1;<br>+                if (!list[offset] || offset == bframes)<br>+                    continue;<br>+<br>+                // Assign gop offset and temporal layer of frames<br>+                list[offset]->m_gopOffset = j;<br>+                list[offset]->m_gopId = m_gopId;<br>+                list[offset]->m_tempLayer = x265_gop_ra[m_gopId][j++].layer;<br>+<br>+                /* add B frames to output queue */<br>+                list[offset]->m_reorderedPts = pts[idx++];<br>+                m_outputQueue.pushBack(*list[offset]);<br>+                i++;<br>+            }<br>+        }<br>+<br>+        bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));<br>+        if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))<br>         {<br>-            if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)<br>+            m_inputLock.acquire();<br>+            Frame *curFrame = m_inputQueue.first();<br>+            frames[0] = m_lastNonB;<br>+            int j;<br>+            for (j = 0; j < maxSearch; j++)<br>             {<br>-                list[i]->m_reorderedPts = pts[idx++];<br>-                m_outputQueue.pushBack(*list[i]);<br>+                frames[j + 1] = &curFrame->m_lowres;<br>+                curFrame = curFrame->m_next;<br>+            }<br>+            m_inputLock.release();<br>+<br>+            frames[j + 1] = NULL;<br>+            if (!m_param->rc.bStatRead)<br>+                slicetypeAnalyse(frames, true);<br>+            bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>+            if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass)<br>+            {<br>+                int numFrames;<br>+                for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>+                {<br>+                    Lowres *fenc = frames[numFrames + 1];<br>+                    if (!fenc)<br>+                        break;<br>+                }<br>+                vbvLookahead(frames, numFrames, true);<br>             }<br>         }<br>-    }<br> <br>-    /* add B frames to output queue */<br>-    for (int i = 0; i < bframes; i++)<br>+<br>+        m_outputLock.release();<br>+    }<br>+    else<br>     {<br>-        /* push all the B frames into output queue except B-ref, which already pushed into output queue */<br>-        if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)<br>+<br>+        if (bframes)<br>+            list[bframes - 1]->m_lowres.bLastMiniGopBFrame = true;<br>+        list[bframes]->m_lowres.leadingBframes = bframes;<br>+        m_lastNonB = &list[bframes]->m_lowres;<br>+<br>+        /* insert a bref into the sequence */<br>+        if (m_param->bBPyramid && bframes > 1 && !brefs)<br>         {<br>-            list[i]->m_reorderedPts = pts[idx++];<br>-            m_outputQueue.pushBack(*list[i]);<br>+            placeBref(list, 0, bframes, bframes + 1, &brefs);<br>+        }<br>+        /* calculate the frame costs ahead of time for estimateFrameCost while we still have lowres */<br>+        if (m_param->rc.rateControlMode != X265_RC_CQP)<br>+        {<br>+            int p0, p1, b;<br>+            /* For zero latency tuning, calculate frame cost to be used later in RC */<br>+            if (!maxSearch)<br>+            {<br>+                for (int i = 0; i <= bframes; i++)<br>+                    frames[i + 1] = &list[i]->m_lowres;<br>+            }<br>+<br>+            /* estimate new non-B cost */<br>+            p1 = b = bframes + 1;<br>+            p0 = (IS_X265_TYPE_I(frames[bframes + 1]->sliceType)) ? b : 0;<br>+<br>+            CostEstimateGroup estGroup(*this, frames);<br>+            estGroup.singleCost(p0, p1, b);<br>+<br>+            if (m_param->bEnableTemporalSubLayers > 1 && bframes)<br>+            {<br>+                compCostBref(frames, 0, bframes, bframes + 1);<br>+            }<br>+            else<br>+            {<br>+                if (bframes)<br>+                {<br>+                    p0 = 0; // last nonb<br>+                    bool isp0available = frames[bframes + 1]->sliceType == X265_TYPE_IDR ? false : true;<br>+<br>+                    for (b = 1; b <= bframes; b++)<br>+                    {<br>+                        if (!isp0available)<br>+                            p0 = b;<br>+<br>+                        if (frames[b]->sliceType == X265_TYPE_B)<br>+                            for (p1 = b; frames[p1]->sliceType == X265_TYPE_B; p1++)<br>+                                ; // find new nonb or bref<br>+                        else<br>+                            p1 = bframes + 1;<br>+<br>+                        estGroup.singleCost(p0, p1, b);<br>+<br>+                        if (frames[b]->sliceType == X265_TYPE_BREF)<br>+                        {<br>+                            p0 = b;<br>+                            isp0available = true;<br>+                        }<br>+                    }<br>+                }<br>+            }<br>         }<br>-    }<br> <br>-    bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));<br>-    if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))<br>-    {<br>         m_inputLock.acquire();<br>-        Frame *curFrame = m_inputQueue.first();<br>-        frames[0] = m_lastNonB;<br>-        int j;<br>-        for (j = 0; j < maxSearch; j++)<br>+        /* dequeue all frames from inputQueue that are about to be enqueued<br>+         * in the output queue. The order is important because Frame can<br>+         * only be in one list at a time */<br>+        int64_t pts[X265_BFRAME_MAX + 1];<br>+        for (int i = 0; i <= bframes; i++)<br>         {<br>-            frames[j + 1] = &curFrame->m_lowres;<br>-            curFrame = curFrame->m_next;<br>+            Frame *curFrame;<br>+            curFrame = m_inputQueue.popFront();<br>+            pts[i] = curFrame->m_pts;<br>+            maxSearch--;<br>         }<br>         m_inputLock.release();<br> <br>-        frames[j + 1] = NULL;<br>-        if (!m_param->rc.bStatRead)<br>-            slicetypeAnalyse(frames, true);<br>-        bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>-        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass)<br>+        m_outputLock.acquire();<br>+<br>+        /* add non-B to output queue */<br>+        int idx = 0;<br>+        list[bframes]->m_reorderedPts = pts[idx++];<br>+        m_outputQueue.pushBack(*list[bframes]);<br>+<br>+        /* Add B-ref frame next to P frame in output queue, the B-ref encode before non B-ref frame */<br>+        if (brefs)<br>         {<br>-            int numFrames;<br>-            for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>+            for (int i = 0; i < bframes; i++)<br>             {<br>-                Lowres *fenc = frames[numFrames + 1];<br>-                if (!fenc)<br>-                    break;<br>+                if (list[i]->m_lowres.sliceType == X265_TYPE_BREF)<br>+                {<br>+                    list[i]->m_reorderedPts = pts[idx++];<br>+                    m_outputQueue.pushBack(*list[i]);<br>+                }<br>+            }<br>+        }<br>+<br>+        /* add B frames to output queue */<br>+        for (int i = 0; i < bframes; i++)<br>+        {<br>+            /* push all the B frames into output queue except B-ref, which already pushed into output queue */<br>+            if (list[i]->m_lowres.sliceType != X265_TYPE_BREF)<br>+            {<br>+                list[i]->m_reorderedPts = pts[idx++];<br>+                m_outputQueue.pushBack(*list[i]);<br>+            }<br>+        }<br>+<br>+<br>+        bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));<br>+        if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))<br>+        {<br>+            m_inputLock.acquire();<br>+            Frame *curFrame = m_inputQueue.first();<br>+            frames[0] = m_lastNonB;<br>+            int j;<br>+            for (j = 0; j < maxSearch; j++)<br>+            {<br>+                frames[j + 1] = &curFrame->m_lowres;<br>+                curFrame = curFrame->m_next;<br>+            }<br>+            m_inputLock.release();<br>+<br>+            frames[j + 1] = NULL;<br>+            if (!m_param->rc.bStatRead)<br>+                slicetypeAnalyse(frames, true);<br>+            bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>+            if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass)<br>+            {<br>+                int numFrames;<br>+                for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>+                {<br>+                    Lowres *fenc = frames[numFrames + 1];<br>+                    if (!fenc)<br>+                        break;<br>+                }<br>+                vbvLookahead(frames, numFrames, true);<br>             }<br>-            vbvLookahead(frames, numFrames, true);<br>         }<br>+<br>+        m_outputLock.release();<br>     }<br>-    m_outputLock.release();<br> }<br> <br> void Lookahead::vbvLookahead(Lowres **frames, int numFrames, int keyframe)<br>diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h<br>index 05cef800b..f4184e4e2 100644<br>--- a/source/encoder/slicetype.h<br>+++ b/source/encoder/slicetype.h<br>@@ -200,6 +200,8 @@ public:<br>     bool          m_resetRunningAvg;<br>     uint32_t      m_segmentCountThreshold;<br> <br>+    int8_t                  m_gopId;<br>+<br>     Lookahead(x265_param *param, ThreadPool *pool);<br> #if DETAILED_CU_STATS<br>     int64_t       m_slicetypeDecideElapsedTime;<br>@@ -251,6 +253,9 @@ protected:<br> <br>     /* called by getEstimatedPictureCost() to finalize cuTree costs */<br>     int64_t frameCostRecalculate(Lowres **frames, int p0, int p1, int b);<br>+    /*Compute index for positioning B-Ref frames*/<br>+    void     placeBref(Frame** frames, int start, int end, int num, int *brefs);<br>+    void     compCostBref(Lowres **frame, int start, int end, int num);<br> };<br> <br> class PreLookaheadGroup : public BondedTaskGroup<br>-- <br>2.28.0.windows.1<br><br><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><i>Thanks,</i><div><i>Kirithika</i></div></div></div></div></div>