[x265] [PATCH] Enable sharing cutree data among encoders

Dakshinya T R S dakshinya at multicorewareinc.com
Wed Oct 6 06:40:17 UTC 2021


>From 69d41f124d14347ec71cc61f3290d3eae7369631 Mon Sep 17 00:00:00 2001
From: lwWang <liwei at multicorewareinc.com>
Date: Wed, 8 Sep 2021 13:38:37 +0800
Subject: [PATCH] Enable sharing cutree data among encoders

---
 source/common/CMakeLists.txt   |   3 +-
 source/common/ringmem.cpp      | 357 +++++++++++++++++++
 source/common/ringmem.h        |  85 +++++
 source/common/threading.h      | 137 ++++++++
 source/encoder/encoder.cpp     |   4 +-
 source/encoder/encoder.h       |   2 +-
 source/encoder/ratecontrol.cpp | 603 +++++++++++++++++++++------------
 source/encoder/ratecontrol.h   |  20 +-
 8 files changed, 987 insertions(+), 224 deletions(-)
 create mode 100644 source/common/ringmem.cpp
 create mode 100644 source/common/ringmem.h

diff --git a/source/common/CMakeLists.txt b/source/common/CMakeLists.txt
index 12b643ad5..8752c6199 100644
--- a/source/common/CMakeLists.txt
+++ b/source/common/CMakeLists.txt
@@ -169,4 +169,5 @@ add_library(common OBJECT
     scalinglist.cpp scalinglist.h
     quant.cpp quant.h contexts.h
     deblock.cpp deblock.h
-    scaler.cpp scaler.h)
+    scaler.cpp scaler.h
+    ringmem.cpp ringmem.h)
diff --git a/source/common/ringmem.cpp b/source/common/ringmem.cpp
new file mode 100644
index 000000000..a4f191c90
--- /dev/null
+++ b/source/common/ringmem.cpp
@@ -0,0 +1,357 @@
+/*****************************************************************************
+ * Copyright (C) 2013-2017 MulticoreWare, Inc
+ *
+ * Authors: liwei <liwei at multicorewareinc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111,
USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at license @ x265.com
+
*****************************************************************************/
+
+#include "ringmem.h"
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif ////< _WIN32
+
+#ifdef _WIN32
+#define X265_SHARED_MEM_NAME                    "Local\\_x265_shr_mem_"
+#define X265_SEMAPHORE_RINGMEM_WRITER_NAME    "_x265_semW_"
+#define X265_SEMAPHORE_RINGMEM_READER_NAME    "_x265_semR_"
+#else /* POSIX / pthreads */
+#define X265_SHARED_MEM_NAME                    "/tmp/_x265_shr_mem_"
+#define X265_SEMAPHORE_RINGMEM_WRITER_NAME    "/tmp/_x265_semW_"
+#define X265_SEMAPHORE_RINGMEM_READER_NAME    "/tmp/_x265_semR_"
+#endif
+
+#define RINGMEM_ALLIGNMENT                       64
+
+namespace X265_NS {
+    RingMem::RingMem()
+        : m_initialized(false)
+        , m_protectRW(false)
+        , m_itemSize(0)
+        , m_itemCnt(0)
+        , m_dataPool(NULL)
+        , m_shrMem(NULL)
+#ifdef _WIN32
+        , m_handle(NULL)
+#else //_WIN32
+        , m_filepath(NULL)
+#endif //_WIN32
+        , m_writeSem(NULL)
+        , m_readSem(NULL)
+    {
+    }
+
+
+    RingMem::~RingMem()
+    {
+    }
+
+    bool RingMem::skipRead(int32_t cnt) {
+        if (!m_initialized)
+        {
+            return false;
+        }
+
+        if (m_protectRW)
+        {
+            for (int i = 0; i < cnt; i++)
+            {
+                m_readSem->take();
+            }
+        }
+
+        ATOMIC_ADD(&m_shrMem->m_read, cnt);
+
+        if (m_protectRW)
+        {
+            m_writeSem->give(cnt);
+        }
+
+        return true;
+    }
+
+    bool RingMem::skipWrite(int32_t cnt) {
+        if (!m_initialized)
+        {
+            return false;
+        }
+
+        if (m_protectRW)
+        {
+            for (int i = 0; i < cnt; i++)
+            {
+                m_writeSem->take();
+            }
+        }
+
+        ATOMIC_ADD(&m_shrMem->m_write, cnt);
+
+        if (m_protectRW)
+        {
+            m_readSem->give(cnt);
+        }
+
+        return true;
+    }
+
+    ///< initialize
+    bool RingMem::init(int32_t itemSize, int32_t itemCnt, const char
*name, bool protectRW)
+    {
+        ///< check parameters
+        if (itemSize <= 0 || itemCnt <= 0 || NULL == name)
+        {
+            ///< invalid parameters
+            return false;
+        }
+
+        if (!m_initialized)
+        {
+            ///< formating names
+            char nameBuf[MAX_SHR_NAME_LEN] = { 0 };
+
+            ///< shared memory name
+            snprintf(nameBuf, sizeof(nameBuf) - 1, "%s%s",
X265_SHARED_MEM_NAME, name);
+
+            ///< create or open shared memory
+            bool newCreated = false;
+
+            ///< calculate the size of the shared memory
+            int32_t shrMemSize = (itemSize * itemCnt + sizeof(ShrMemCtrl)
+ RINGMEM_ALLIGNMENT - 1) & ~(RINGMEM_ALLIGNMENT - 1);
+
+#ifdef _WIN32
+            HANDLE h = OpenFileMappingA(FILE_MAP_WRITE | FILE_MAP_READ,
FALSE, nameBuf);
+            if (!h)
+            {
+                h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, shrMemSize, nameBuf);
+
+                if (!h)
+                {
+                    return false;
+                }
+
+                newCreated = true;
+            }
+
+            void *pool = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+
+            ///< should not close the handle here, otherwise the
OpenFileMapping would fail
+            //CloseHandle(h);
+            m_handle = h;
+
+            if (!pool)
+            {
+                return false;
+            }
+
+#else /* POSIX / pthreads */
+            mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
| S_IWOTH;
+            int flag = O_RDWR;
+            int shrfd = -1;
+            if ((shrfd = open(nameBuf, flag, mode)) < 0)
+            {
+                flag |= O_CREAT;
+
+                shrfd = open(nameBuf, flag, mode);
+                if (shrfd < 0)
+                {
+                    return false;
+                }
+                newCreated = true;
+
+                lseek(shrfd, shrMemSize - 1, SEEK_SET);
+
+                if (-1 == write(shrfd, "\0", 1))
+                {
+                    close(shrfd);
+                    return false;
+                }
+
+                if (lseek(shrfd, 0, SEEK_END) < shrMemSize)
+                {
+                    close(shrfd);
+                    return false;
+                }
+            }
+
+            void *pool = mmap(0,
+                shrMemSize,
+                PROT_READ | PROT_WRITE,
+                MAP_SHARED,
+                shrfd,
+                0);
+
+            close(shrfd);
+            if (pool == MAP_FAILED)
+            {
+                return false;
+            }
+
+            m_filepath = strdup(nameBuf);
+#endif ///< _WIN32
+
+            if (newCreated)
+            {
+                memset(pool, 0, shrMemSize);
+            }
+
+            m_shrMem = reinterpret_cast<ShrMemCtrl *>(pool);
+            m_dataPool = reinterpret_cast<uint8_t *>(pool) +
sizeof(ShrMemCtrl);
+            m_itemSize = itemSize;
+            m_itemCnt = itemCnt;
+            m_initialized = true;
+
+            if (protectRW)
+            {
+                m_protectRW = true;
+                m_writeSem = new NamedSemaphore();
+                if (!m_writeSem)
+                {
+                    release();
+                    return false;
+                }
+
+                ///< shared memory name
+                snprintf(nameBuf, sizeof(nameBuf - 1), "%s%s",
X265_SEMAPHORE_RINGMEM_WRITER_NAME, name);
+                if (!m_writeSem->create(nameBuf, m_itemCnt, m_itemCnt))
+                {
+                    release();
+                    return false;
+                }
+
+                m_readSem = new NamedSemaphore();
+                if (!m_readSem)
+                {
+                    release();
+                    return false;
+                }
+
+                ///< shared memory name
+                snprintf(nameBuf, sizeof(nameBuf - 1), "%s%s",
X265_SEMAPHORE_RINGMEM_READER_NAME, name);
+                if (!m_readSem->create(nameBuf, 0, m_itemCnt))
+                {
+                    release();
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+    ///< finalize
+    void RingMem::release()
+    {
+        if (m_initialized)
+        {
+            m_initialized = false;
+
+            if (m_shrMem)
+            {
+#ifdef _WIN32
+                UnmapViewOfFile(m_shrMem);
+                CloseHandle(m_handle);
+                m_handle = NULL;
+#else /* POSIX / pthreads */
+                int32_t shrMemSize = (m_itemSize * m_itemCnt +
sizeof(ShrMemCtrl) + RINGMEM_ALLIGNMENT - 1) & (~RINGMEM_ALLIGNMENT - 1);
+                munmap(m_shrMem, shrMemSize);
+                unlink(m_filepath);
+                free(m_filepath);
+                m_filepath = NULL;
+#endif ///< _WIN32
+                m_shrMem = NULL;
+                m_dataPool = NULL;
+                m_itemSize = 0;
+                m_itemCnt = 0;
+            }
+
+            if (m_protectRW)
+            {
+                m_protectRW = false;
+                if (m_writeSem)
+                {
+                    m_writeSem->release();
+
+                    delete m_writeSem;
+                    m_writeSem = NULL;
+                }
+
+                if (m_readSem)
+                {
+                    m_readSem->release();
+
+                    delete m_readSem;
+                    m_readSem = NULL;
+                }
+            }
+
+        }
+    }
+
+    ///< data read
+    bool RingMem::readNext(void* dst, fnRWSharedData callback)
+    {
+        if (!m_initialized || !callback || !dst)
+        {
+            return false;
+        }
+
+        if (m_protectRW)
+        {
+            if (!m_readSem->take())
+            {
+                return false;
+            }
+        }
+
+        int32_t index = ATOMIC_ADD(&m_shrMem->m_read, 1) % m_itemCnt;
+        (*callback)(dst, reinterpret_cast<uint8_t *>(m_dataPool) + index *
m_itemSize, m_itemSize);
+
+        if (m_protectRW)
+        {
+            m_writeSem->give(1);
+        }
+
+        return true;
+    }
+    ///< data write
+    bool RingMem::writeData(void *data, fnRWSharedData callback)
+    {
+        if (!m_initialized || !data || !callback)
+        {
+            return false;
+        }
+
+        if (m_protectRW)
+        {
+            if (!m_writeSem->take())
+            {
+                return false;
+            }
+        }
+
+        int32_t index = ATOMIC_ADD(&m_shrMem->m_write, 1) % m_itemCnt;
+        (*callback)(reinterpret_cast<uint8_t *>(m_dataPool) + index *
m_itemSize, data, m_itemSize);
+
+        if (m_protectRW)
+        {
+            m_readSem->give(1);
+        }
+
+        return true;
+    }
+}
diff --git a/source/common/ringmem.h b/source/common/ringmem.h
new file mode 100644
index 000000000..76f54bb19
--- /dev/null
+++ b/source/common/ringmem.h
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * Copyright (C) 2013-2017 MulticoreWare, Inc
+ *
+ * Authors: liwei <liwei at multicorewareinc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111,
USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at license @ x265.com
+
*****************************************************************************/
+
+#ifndef X265_RINGMEM_H
+#define X265_RINGMEM_H
+
+#include "common.h"
+#include "threading.h"
+
+namespace X265_NS {
+
+#define MAX_SHR_NAME_LEN                         256
+
+    class RingMem {
+    public:
+        RingMem();
+        ~RingMem();
+
+        bool skipRead(int32_t cnt);
+
+        bool skipWrite(int32_t cnt);
+
+        ///< initialize
+        ///< protectRW: if use the semaphore the protect the write and
read operation.
+        bool init(int32_t itemSize, int32_t itemCnt, const char *name,
bool protectRW = false);
+        ///< finalize
+        void release();
+
+        typedef void(*fnRWSharedData)(void *dst, void *src, int32_t size);
+
+        ///< data read
+        bool readNext(void* dst, fnRWSharedData callback);
+        ///< data write
+        bool writeData(void *data, fnRWSharedData callback);
+
+    private:
+        bool    m_initialized;
+        bool    m_protectRW;
+
+        int32_t m_itemSize;
+        int32_t m_itemCnt;
+        ///< data pool
+        void   *m_dataPool;
+        typedef struct {
+            ///< index to write
+            int32_t m_write;
+            ///< index to read
+            int32_t m_read;
+
+        }ShrMemCtrl;
+
+        ShrMemCtrl *m_shrMem;
+#ifdef _WIN32
+        void       *m_handle;
+#else // _WIN32
+        char       *m_filepath;
+#endif // _WIN32
+
+        ///< Semaphores
+        NamedSemaphore *m_writeSem;
+        NamedSemaphore *m_readSem;
+    };
+};
+
+#endif // ifndef X265_RINGMEM_H
diff --git a/source/common/threading.h b/source/common/threading.h
index 53a63beaf..dcf6081e3 100644
--- a/source/common/threading.h
+++ b/source/common/threading.h
@@ -3,6 +3,7 @@
  *
  * Authors: Steve Borho <steve at borho.org>
  *          Min Chen <chenm003 at 163.com>
+            liwei <liwei at multicorewareinc.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -253,6 +254,47 @@ protected:
     int                m_val;
 };

+class NamedSemaphore
+{
+public:
+    NamedSemaphore() : m_sem(NULL)
+    {
+    }
+
+    ~NamedSemaphore()
+    {
+    }
+
+    bool create(const char* name, const int initcnt, const int maxcnt)
+    {
+        if(!m_sem)
+        {
+            m_sem = CreateSemaphoreA(NULL, initcnt, maxcnt, name);
+        }
+        return m_sem != NULL;
+    }
+
+    bool give(const int32_t cnt)
+    {
+        return ReleaseSemaphore(m_sem, (LONG)cnt, NULL) != FALSE;
+    }
+
+    bool take(const uint32_t time_out = INFINITE)
+    {
+        int32_t rt = WaitForSingleObject(m_sem, time_out);
+        return rt != WAIT_TIMEOUT && rt != WAIT_FAILED;
+    }
+
+    void release()
+    {
+        CloseHandle(m_sem);
+        m_sem = NULL;
+    }
+
+private:
+    HANDLE m_sem;
+};
+
 #else /* POSIX / pthreads */

 typedef pthread_t ThreadHandle;
@@ -459,6 +501,101 @@ protected:
     int             m_val;
 };

+#define TIMEOUT_INFINITE 0xFFFFFFFF
+
+class NamedSemaphore
+{
+public:
+    NamedSemaphore()
+        : m_sem(NULL)
+        , m_name(NULL)
+    {
+    }
+
+    ~NamedSemaphore()
+    {
+    }
+
+    bool create(const char* name, const int initcnt, const int maxcnt)
+    {
+        bool ret = false;
+
+        if (initcnt >= maxcnt)
+        {
+            return false;
+        }
+
+        m_sem = sem_open(name, O_CREAT | O_EXCL, 0666, initcnt);
+        if (m_sem != SEM_FAILED)
+        {
+            m_name = strdup(name);
+            ret = true;
+        }
+        else
+        {
+            if (EEXIST == errno)
+            {
+                m_sem = sem_open(name, 0);
+                if (m_sem != SEM_FAILED)
+                {
+                    m_name = strdup(name);
+                    ret = true;
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    bool give(const int32_t cnt)
+    {
+        int ret = 0;
+        int32_t curCnt = cnt;
+        while (curCnt-- && !ret) {
+            ret = sem_post(m_sem);
+        }
+
+        return 0 == ret;
+    }
+
+    bool take(const uint32_t time_out = TIMEOUT_INFINITE)
+    {
+        if (TIMEOUT_INFINITE == time_out) {
+            return 0 == sem_wait(m_sem);
+        }
+        else
+        {
+            if (0 == time_out)
+            {
+                return 0 == sem_trywait(m_sem);
+            }
+            else
+            {
+                struct timespec ts;
+                ts.tv_sec = time_out / 1000L;
+                ts.tv_nsec = (time_out * 1000000L) - ts.tv_sec * 1000 *
1000 * 1000;
+                return 0 == sem_timedwait(m_sem, &ts);
+            }
+        }
+    }
+
+    void release()
+    {
+        if (m_sem)
+        {
+            sem_close(m_sem);
+            sem_unlink(m_name);
+            m_sem = NULL;
+            free(m_name);
+            m_name = NULL;
+        }
+    }
+
+private:
+    sem_t *m_sem;
+    char  *m_name;
+};
+
 #endif // ifdef _WIN32

 class ScopedLock
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index cc014a740..19551b1f2 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -187,7 +187,7 @@ inline char *strcatFilename(const char *input, const
char *suffix)
     return output;
 }

-void Encoder::create()
+void Encoder::create(char *dataShr)
 {
     if (!primitives.pu[0].sad)
     {
@@ -389,7 +389,7 @@ void Encoder::create()
             lookAheadThreadPool[i].start();
     m_lookahead->m_numPools = pools;
     m_dpb = new DPB(m_param);
-    m_rateControl = new RateControl(*m_param, this);
+    m_rateControl = new RateControl(*m_param, this, dataShr);
     if (!m_param->bResetZoneConfig)
     {
         zoneReadCount = new ThreadSafeInteger[m_param->rc.zonefileCount];
diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
index 2ee5bdaee..4b8478f16 100644
--- a/source/encoder/encoder.h
+++ b/source/encoder/encoder.h
@@ -305,7 +305,7 @@ public:
 #endif
     };

-    void create();
+    void create(char *dataShr = NULL);
     void stopJobs();
     void destroy();

diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 71f08a73e..e2f514172 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -41,6 +41,10 @@
 #define BR_SHIFT  6
 #define CPB_SHIFT 4

+#define SHARED_DATA_ALIGNMENT      4 ///< 4btye, 32bit
+#define CUTREE_SHARED_MEM_NAME     "cutree"
+#define GOP_CNT_CU_TREE            3
+
 using namespace X265_NS;

 /* Amortize the partial cost of I frames over the next N frames */
@@ -104,6 +108,37 @@ inline char *strcatFilename(const char *input, const
char *suffix)
     return output;
 }

+typedef struct CUTreeSharedDataItem
+{
+    uint8_t  *type;
+    uint16_t *stats;
+}CUTreeSharedDataItem;
+
+void ReadSharedCUTreeData(void *dst, void *src, int32_t size)
+{
+    CUTreeSharedDataItem *statsDst = reinterpret_cast<CUTreeSharedDataItem
*>(dst);
+    uint8_t *typeSrc = reinterpret_cast<uint8_t *>(src);
+    *statsDst->type = *typeSrc;
+
+    ///< for memory alignment, the type will take 32bit in the shared
memory
+    int32_t offset = (sizeof(*statsDst->type) + SHARED_DATA_ALIGNMENT - 1)
& ~(SHARED_DATA_ALIGNMENT - 1);
+    uint16_t *statsSrc = reinterpret_cast<uint16_t *>(typeSrc + offset);
+    memcpy(statsDst->stats, statsSrc, size - offset);
+}
+
+void WriteSharedCUTreeData(void *dst, void *src, int32_t size)
+{
+    CUTreeSharedDataItem *statsSrc = reinterpret_cast<CUTreeSharedDataItem
*>(src);
+    uint8_t *typeDst = reinterpret_cast<uint8_t *>(dst);
+    *typeDst = *statsSrc->type;
+
+    ///< for memory alignment, the type will take 32bit in the shared
memory
+    int32_t offset = (sizeof(*statsSrc->type) + SHARED_DATA_ALIGNMENT - 1)
& ~(SHARED_DATA_ALIGNMENT - 1);
+    uint16_t *statsDst = reinterpret_cast<uint16_t *>(typeDst + offset);
+    memcpy(statsDst, statsSrc->stats, size - offset);
+}
+
+
 inline double qScale2bits(RateControlEntry *rce, double qScale)
 {
     if (qScale < 0.1)
@@ -146,7 +181,7 @@ x265_zone* RateControl::getZone()
     return NULL;
 }

-RateControl::RateControl(x265_param& p, Encoder *top)
+RateControl::RateControl(x265_param& p, Encoder *top, char * dataShr)
 {
     m_param = &p;
     m_top = top;
@@ -209,6 +244,14 @@ RateControl::RateControl(x265_param& p, Encoder *top)
     m_lastAbrResetPoc = -1;
     m_statFileOut = NULL;
     m_cutreeStatFileOut = m_cutreeStatFileIn = NULL;
+    ///< store the cutree data in file by default
+    m_cutreeStorageMode = !dataShr ? SHARED_MODE_FILE : SHARED_MODE_MEM;
+    m_shrname = NULL;
+    if (dataShr)
+    {
+        m_shrname = strdup(dataShr);
+    }
+    m_cutreeShrMem = NULL;
     m_rce2Pass = NULL;
     m_encOrder = NULL;
     m_lastBsliceSatdCost = 0;
@@ -320,6 +363,42 @@ RateControl::RateControl(x265_param& p, Encoder *top)
         m_cuTreeStats.qpBuffer[i] = NULL;
 }

+bool RateControl::initCUTreeSharedMem()
+{
+    if (!m_cutreeShrMem) {
+        m_cutreeShrMem = new RingMem();
+        if (!m_cutreeShrMem)
+        {
+            return false;
+        }
+
+        ///< now cutree data form at most 3 gops would be stored in the
shared memory at the same time
+        int32_t itemSize = (sizeof(uint8_t) + SHARED_DATA_ALIGNMENT - 1) &
~(SHARED_DATA_ALIGNMENT - 1);
+        if (m_param->rc.qgSize == 8)
+        {
+            itemSize += sizeof(uint16_t) * m_ncu * 4;
+        }
+        else
+        {
+            itemSize += sizeof(uint16_t) * m_ncu;
+        }
+
+        int32_t itemCnt = X265_MIN(m_param->keyframeMax, (int)(m_fps +
0.5));
+        itemCnt *= GOP_CNT_CU_TREE;
+
+        char shrname[MAX_SHR_NAME_LEN] = { 0 };
+        strcpy(shrname, m_shrname);
+        strcat(shrname, CUTREE_SHARED_MEM_NAME);
+
+        if (!m_cutreeShrMem->init(itemSize, itemCnt, shrname))
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 bool RateControl::init(const SPS& sps)
 {
     if (m_isVbv && !m_initVbv)
@@ -421,244 +500,261 @@ bool RateControl::init(const SPS& sps)
         /* Load stat file and init 2pass algo */
         if (m_param->rc.bStatRead)
         {
-            m_expectedBitsSum = 0;
-            char *p, *statsIn, *statsBuf;
-            /* read 1st pass stats */
-            statsIn = statsBuf = x265_slurp_file(fileName);
-            if (!statsBuf)
-                return false;
-            if (m_param->rc.cuTree)
+            if (SHARED_MODE_FILE == m_cutreeStorageMode)
             {
-                char *tmpFile = strcatFilename(fileName, ".cutree");
-                if (!tmpFile)
+                m_expectedBitsSum = 0;
+                char *p, *statsIn, *statsBuf;
+                /* read 1st pass stats */
+                statsIn = statsBuf = x265_slurp_file(fileName);
+                if (!statsBuf)
                     return false;
-                m_cutreeStatFileIn = x265_fopen(tmpFile, "rb");
-                X265_FREE(tmpFile);
-                if (!m_cutreeStatFileIn)
+                if (m_param->rc.cuTree)
                 {
-                    x265_log_file(m_param, X265_LOG_ERROR, "can't open
stats file %s.cutree\n", fileName);
-                    return false;
+                    char *tmpFile = strcatFilename(fileName, ".cutree");
+                    if (!tmpFile)
+                        return false;
+                    m_cutreeStatFileIn = x265_fopen(tmpFile, "rb");
+                    X265_FREE(tmpFile);
+                    if (!m_cutreeStatFileIn)
+                    {
+                        x265_log_file(m_param, X265_LOG_ERROR, "can't open
stats file %s.cutree\n", fileName);
+                        return false;
+                    }
                 }
-            }

-            /* check whether 1st pass options were compatible with current
options */
-            if (strncmp(statsBuf, "#options:", 9))
-            {
-                x265_log(m_param, X265_LOG_ERROR,"options list in stats
file not valid\n");
-                return false;
-            }
-            {
-                int i, j, m;
-                uint32_t k , l;
-                bool bErr = false;
-                char *opts = statsBuf;
-                statsIn = strchr(statsBuf, '\n');
-                if (!statsIn)
+                /* check whether 1st pass options were compatible with
current options */
+                if (strncmp(statsBuf, "#options:", 9))
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "Malformed stats
file\n");
+                    x265_log(m_param, X265_LOG_ERROR, "options list in
stats file not valid\n");
                     return false;
                 }
-                *statsIn = '\0';
-                statsIn++;
-                if ((p = strstr(opts, " input-res=")) == 0 || sscanf(p, "
input-res=%dx%d", &i, &j) != 2)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "Resolution
specified in stats file not valid\n");
+                    int i, j, m;
+                    uint32_t k, l;
+                    bool bErr = false;
+                    char *opts = statsBuf;
+                    statsIn = strchr(statsBuf, '\n');
+                    if (!statsIn)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "Malformed stats
file\n");
+                        return false;
+                    }
+                    *statsIn = '\0';
+                    statsIn++;
+                    if ((p = strstr(opts, " input-res=")) == 0 ||
sscanf(p, " input-res=%dx%d", &i, &j) != 2)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "Resolution
specified in stats file not valid\n");
+                        return false;
+                    }
+                    if ((p = strstr(opts, " fps=")) == 0 || sscanf(p, "
fps=%u/%u", &k, &l) != 2)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "fps specified
in stats file not valid\n");
+                        return false;
+                    }
+                    if (((p = strstr(opts, " vbv-maxrate=")) == 0 ||
sscanf(p, " vbv-maxrate=%d", &m) != 1) && m_param->rc.rateControlMode ==
X265_RC_CRF)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "Constant
rate-factor is incompatible with 2pass without vbv-maxrate in the previous
pass\n");
+                        return false;
+                    }
+                    if (k != m_param->fpsNum || l != m_param->fpsDenom)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "fps mismatch
with 1st pass (%u/%u vs %u/%u)\n",
+                            m_param->fpsNum, m_param->fpsDenom, k, l);
+                        return false;
+                    }
+                    if (m_param->analysisMultiPassRefine)
+                    {
+                        p = strstr(opts, "ref=");
+                        sscanf(p, "ref=%d", &i);
+                        if (i > m_param->maxNumReferences)
+                        {
+                            x265_log(m_param, X265_LOG_ERROR,
"maxNumReferences cannot be less than 1st pass (%d vs %d)\n",
+                                i, m_param->maxNumReferences);
+                            return false;
+                        }
+                    }
+                    if (m_param->analysisMultiPassRefine ||
m_param->analysisMultiPassDistortion)
+                    {
+                        p = strstr(opts, "ctu=");
+                        sscanf(p, "ctu=%u", &k);
+                        if (k != m_param->maxCUSize)
+                        {
+                            x265_log(m_param, X265_LOG_ERROR, "maxCUSize
mismatch with 1st pass (%u vs %u)\n",
+                                k, m_param->maxCUSize);
+                            return false;
+                        }
+                    }
+                    CMP_OPT_FIRST_PASS("bitdepth",
m_param->internalBitDepth);
+                    CMP_OPT_FIRST_PASS("weightp",
m_param->bEnableWeightedPred);
+                    CMP_OPT_FIRST_PASS("bframes", m_param->bframes);
+                    CMP_OPT_FIRST_PASS("b-pyramid", m_param->bBPyramid);
+                    CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP);
+                    CMP_OPT_FIRST_PASS(" keyint", m_param->keyframeMax);
+                    CMP_OPT_FIRST_PASS("scenecut",
m_param->scenecutThreshold);
+                    CMP_OPT_FIRST_PASS("intra-refresh",
m_param->bIntraRefresh);
+                    CMP_OPT_FIRST_PASS("frame-dup",
m_param->bEnableFrameDuplication);
+                    if (m_param->bMultiPassOptRPS)
+                    {
+                        CMP_OPT_FIRST_PASS("multi-pass-opt-rps",
m_param->bMultiPassOptRPS);
+                        CMP_OPT_FIRST_PASS("repeat-headers",
m_param->bRepeatHeaders);
+                        CMP_OPT_FIRST_PASS("min-keyint",
m_param->keyframeMin);
+                    }
+
+                    if ((p = strstr(opts, "b-adapt=")) != 0 && sscanf(p,
"b-adapt=%d", &i) && i >= X265_B_ADAPT_NONE && i <= X265_B_ADAPT_TRELLIS)
+                    {
+                        m_param->bFrameAdaptive = i;
+                    }
+                    else if (m_param->bframes)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "b-adapt method
specified in stats file not valid\n");
+                        return false;
+                    }
+
+                    if ((p = strstr(opts, "rc-lookahead=")) != 0 &&
sscanf(p, "rc-lookahead=%d", &i))
+                        m_param->lookaheadDepth = i;
+                }
+                /* find number of pics */
+                p = statsIn;
+                int numEntries;
+                for (numEntries = -1; p; numEntries++)
+                    p = strchr(p + 1, ';');
+                if (!numEntries)
+                {
+                    x265_log(m_param, X265_LOG_ERROR, "empty stats
file\n");
                     return false;
                 }
-                if ((p = strstr(opts, " fps=")) == 0 || sscanf(p, "
fps=%u/%u", &k, &l) != 2)
+                m_numEntries = numEntries;
+
+                if (m_param->totalFrames < m_numEntries &&
m_param->totalFrames > 0)
+                {
+                    x265_log(m_param, X265_LOG_WARNING, "2nd pass has
fewer frames than 1st pass (%d vs %d)\n",
+                        m_param->totalFrames, m_numEntries);
+                }
+                if (m_param->totalFrames > m_numEntries &&
!m_param->bEnableFrameDuplication)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "fps specified in
stats file not valid\n");
+                    x265_log(m_param, X265_LOG_ERROR, "2nd pass has more
frames than 1st pass (%d vs %d)\n",
+                        m_param->totalFrames, m_numEntries);
                     return false;
                 }
-                if (((p = strstr(opts, " vbv-maxrate=")) == 0 || sscanf(p,
" vbv-maxrate=%d", &m) != 1) && m_param->rc.rateControlMode == X265_RC_CRF)
+
+                m_rce2Pass = X265_MALLOC(RateControlEntry, m_numEntries);
+                if (!m_rce2Pass)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "Constant
rate-factor is incompatible with 2pass without vbv-maxrate in the previous
pass\n");
+                    x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2
pass cannot be allocated\n");
                     return false;
                 }
-                if (k != m_param->fpsNum || l != m_param->fpsDenom)
+                m_encOrder = X265_MALLOC(int, m_numEntries);
+                if (!m_encOrder)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "fps mismatch with
1st pass (%u/%u vs %u/%u)\n",
-                              m_param->fpsNum, m_param->fpsDenom, k, l);
+                    x265_log(m_param, X265_LOG_ERROR, "Encode order for 2
pass cannot be allocated\n");
                     return false;
                 }
-                if (m_param->analysisMultiPassRefine)
+                /* init all to skipped p frames */
+                for (int i = 0; i < m_numEntries; i++)
                 {
-                    p = strstr(opts, "ref=");
-                    sscanf(p, "ref=%d", &i);
-                    if (i > m_param->maxNumReferences)
+                    RateControlEntry *rce = &m_rce2Pass[i];
+                    rce->sliceType = P_SLICE;
+                    rce->qScale = rce->newQScale = x265_qp2qScale(20);
+                    rce->miscBits = m_ncu + 10;
+                    rce->newQp = 0;
+                }
+                /* read stats */
+                p = statsIn;
+                double totalQpAq = 0;
+                for (int i = 0; i < m_numEntries; i++)
+                {
+                    RateControlEntry *rce, *rcePocOrder;
+                    int frameNumber;
+                    int encodeOrder;
+                    char picType;
+                    int e;
+                    char *next;
+                    double qpRc, qpAq, qNoVbv, qRceq;
+                    next = strstr(p, ";");
+                    if (next)
+                        *next++ = 0;
+                    e = sscanf(p, " in:%d out:%d", &frameNumber,
&encodeOrder);
+                    if (frameNumber < 0 || frameNumber >= m_numEntries)
                     {
-                        x265_log(m_param, X265_LOG_ERROR,
"maxNumReferences cannot be less than 1st pass (%d vs %d)\n",
-                            i, m_param->maxNumReferences);
+                        x265_log(m_param, X265_LOG_ERROR, "bad frame
number (%d) at stats line %d\n", frameNumber, i);
                         return false;
                     }
-                }
-                if (m_param->analysisMultiPassRefine ||
m_param->analysisMultiPassDistortion)
-                {
-                    p = strstr(opts, "ctu=");
-                    sscanf(p, "ctu=%u", &k);
-                    if (k != m_param->maxCUSize)
+                    rce = &m_rce2Pass[encodeOrder];
+                    rcePocOrder = &m_rce2Pass[frameNumber];
+                    m_encOrder[frameNumber] = encodeOrder;
+                    if (!m_param->bMultiPassOptRPS)
                     {
-                        x265_log(m_param, X265_LOG_ERROR, "maxCUSize
mismatch with 1st pass (%u vs %u)\n",
-                            k, m_param->maxCUSize);
+                        int scenecut = 0;
+                        e += sscanf(p, " in:%*d out:%*d type:%c q:%lf
q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf
scu:%lf sc:%d",
+                            &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
+                            &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
+                            &rce->skipCuCount, &scenecut);
+                        rcePocOrder->scenecut = scenecut != 0;
+                    }
+                    else
+                    {
+                        char deltaPOC[128];
+                        char bUsed[40];
+                        memset(deltaPOC, 0, sizeof(deltaPOC));
+                        memset(bUsed, 0, sizeof(bUsed));
+                        e += sscanf(p, " in:%*d out:%*d type:%c q:%lf
q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf
scu:%lf nump:%d numnegp:%d numposp:%d deltapoc:%s bused:%s",
+                            &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
+                            &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
+                            &rce->skipCuCount,
&rce->rpsData.numberOfPictures, &rce->rpsData.numberOfNegativePictures,
&rce->rpsData.numberOfPositivePictures, deltaPOC, bUsed);
+                        splitdeltaPOC(deltaPOC, rce);
+                        splitbUsed(bUsed, rce);
+                        rce->rpsIdx = -1;
+                    }
+                    rce->keptAsRef = true;
+                    rce->isIdr = false;
+                    if (picType == 'b' || picType == 'p')
+                        rce->keptAsRef = false;
+                    if (picType == 'I')
+                        rce->isIdr = true;
+                    if (picType == 'I' || picType == 'i')
+                        rce->sliceType = I_SLICE;
+                    else if (picType == 'P' || picType == 'p')
+                        rce->sliceType = P_SLICE;
+                    else if (picType == 'B' || picType == 'b')
+                        rce->sliceType = B_SLICE;
+                    else
+                        e = -1;
+                    if (e < 10)
+                    {
+                        x265_log(m_param, X265_LOG_ERROR, "statistics are
damaged at line %d, parser out=%d\n", i, e);
                         return false;
                     }
+                    rce->qScale = rce->newQScale = x265_qp2qScale(qpRc);
+                    totalQpAq += qpAq;
+                    rce->qpNoVbv = qNoVbv;
+                    rce->qpaRc = qpRc;
+                    rce->qpAq = qpAq;
+                    rce->qRceq = qRceq;
+                    p = next;
                 }
-                CMP_OPT_FIRST_PASS("bitdepth", m_param->internalBitDepth);
-                CMP_OPT_FIRST_PASS("weightp",
m_param->bEnableWeightedPred);
-                CMP_OPT_FIRST_PASS("bframes", m_param->bframes);
-                CMP_OPT_FIRST_PASS("b-pyramid", m_param->bBPyramid);
-                CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP);
-                CMP_OPT_FIRST_PASS(" keyint", m_param->keyframeMax);
-                CMP_OPT_FIRST_PASS("scenecut", m_param->scenecutThreshold);
-                CMP_OPT_FIRST_PASS("intra-refresh",
m_param->bIntraRefresh);
-                CMP_OPT_FIRST_PASS("frame-dup",
m_param->bEnableFrameDuplication);
-                if (m_param->bMultiPassOptRPS)
-                {
-                    CMP_OPT_FIRST_PASS("multi-pass-opt-rps",
m_param->bMultiPassOptRPS);
-                    CMP_OPT_FIRST_PASS("repeat-headers",
m_param->bRepeatHeaders);
-                    CMP_OPT_FIRST_PASS("min-keyint", m_param->keyframeMin);
-                }
-
-                if ((p = strstr(opts, "b-adapt=")) != 0 && sscanf(p,
"b-adapt=%d", &i) && i >= X265_B_ADAPT_NONE && i <= X265_B_ADAPT_TRELLIS)
+                X265_FREE(statsBuf);
+                if (m_param->rc.rateControlMode != X265_RC_CQP)
                 {
-                    m_param->bFrameAdaptive = i;
-                }
-                else if (m_param->bframes)
-                {
-                    x265_log(m_param, X265_LOG_ERROR, "b-adapt method
specified in stats file not valid\n");
-                    return false;
-                }
-
-                if ((p = strstr(opts, "rc-lookahead=")) != 0 && sscanf(p,
"rc-lookahead=%d", &i))
-                    m_param->lookaheadDepth = i;
-            }
-            /* find number of pics */
-            p = statsIn;
-            int numEntries;
-            for (numEntries = -1; p; numEntries++)
-                p = strchr(p + 1, ';');
-            if (!numEntries)
-            {
-                x265_log(m_param, X265_LOG_ERROR, "empty stats file\n");
-                return false;
-            }
-            m_numEntries = numEntries;
-
-            if (m_param->totalFrames < m_numEntries &&
m_param->totalFrames > 0)
-            {
-                x265_log(m_param, X265_LOG_WARNING, "2nd pass has fewer
frames than 1st pass (%d vs %d)\n",
-                         m_param->totalFrames, m_numEntries);
-            }
-            if (m_param->totalFrames > m_numEntries &&
!m_param->bEnableFrameDuplication)
-            {
-                x265_log(m_param, X265_LOG_ERROR, "2nd pass has more
frames than 1st pass (%d vs %d)\n",
-                         m_param->totalFrames, m_numEntries);
-                return false;
+                    m_start = 0;
+                    m_isQpModified = true;
+                    if (!initPass2())
+                        return false;
+                } /* else we're using constant quant, so no need to run
the bitrate allocation */
             }
-
-            m_rce2Pass = X265_MALLOC(RateControlEntry, m_numEntries);
-            if (!m_rce2Pass)
+            else if (SHARED_MODE_MEM == m_cutreeStorageMode)
             {
-                 x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass
cannot be allocated\n");
-                 return false;
+                if (m_param->rc.cuTree)
+                {
+                    if (!initCUTreeSharedMem())
+                    {
+                        return false;
+                    }
+                }
             }
-            m_encOrder = X265_MALLOC(int, m_numEntries);
-            if (!m_encOrder)
+            else
             {
-                x265_log(m_param, X265_LOG_ERROR, "Encode order for 2 pass
cannot be allocated\n");
                 return false;
             }
-            /* init all to skipped p frames */
-            for (int i = 0; i < m_numEntries; i++)
-            {
-                RateControlEntry *rce = &m_rce2Pass[i];
-                rce->sliceType = P_SLICE;
-                rce->qScale = rce->newQScale = x265_qp2qScale(20);
-                rce->miscBits = m_ncu + 10;
-                rce->newQp = 0;
-            }
-            /* read stats */
-            p = statsIn;
-            double totalQpAq = 0;
-            for (int i = 0; i < m_numEntries; i++)
-            {
-                RateControlEntry *rce, *rcePocOrder;
-                int frameNumber;
-                int encodeOrder;
-                char picType;
-                int e;
-                char *next;
-                double qpRc, qpAq, qNoVbv, qRceq;
-                next = strstr(p, ";");
-                if (next)
-                    *next++ = 0;
-                e = sscanf(p, " in:%d out:%d", &frameNumber, &encodeOrder);
-                if (frameNumber < 0 || frameNumber >= m_numEntries)
-                {
-                    x265_log(m_param, X265_LOG_ERROR, "bad frame number
(%d) at stats line %d\n", frameNumber, i);
-                    return false;
-                }
-                rce = &m_rce2Pass[encodeOrder];
-                rcePocOrder = &m_rce2Pass[frameNumber];
-                m_encOrder[frameNumber] = encodeOrder;
-                if (!m_param->bMultiPassOptRPS)
-                {
-                    int scenecut = 0;
-                    e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf sc:%d",
-                        &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
-                        &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
-                        &rce->skipCuCount, &scenecut);
-                    rcePocOrder->scenecut = scenecut != 0;
-                }
-                else
-                {
-                    char deltaPOC[128];
-                    char bUsed[40];
-                    memset(deltaPOC, 0, sizeof(deltaPOC));
-                    memset(bUsed, 0, sizeof(bUsed));
-                    e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf nump:%d
numnegp:%d numposp:%d deltapoc:%s bused:%s",
-                        &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
-                        &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
-                        &rce->skipCuCount, &rce->rpsData.numberOfPictures,
&rce->rpsData.numberOfNegativePictures,
&rce->rpsData.numberOfPositivePictures, deltaPOC, bUsed);
-                    splitdeltaPOC(deltaPOC, rce);
-                    splitbUsed(bUsed, rce);
-                    rce->rpsIdx = -1;
-                }
-                rce->keptAsRef = true;
-                rce->isIdr = false;
-                if (picType == 'b' || picType == 'p')
-                    rce->keptAsRef = false;
-                if (picType == 'I')
-                    rce->isIdr = true;
-                if (picType == 'I' || picType == 'i')
-                    rce->sliceType = I_SLICE;
-                else if (picType == 'P' || picType == 'p')
-                    rce->sliceType = P_SLICE;
-                else if (picType == 'B' || picType == 'b')
-                    rce->sliceType = B_SLICE;
-                else
-                    e = -1;
-                if (e < 10)
-                {
-                    x265_log(m_param, X265_LOG_ERROR, "statistics are
damaged at line %d, parser out=%d\n", i, e);
-                    return false;
-                }
-                rce->qScale = rce->newQScale = x265_qp2qScale(qpRc);
-                totalQpAq += qpAq;
-                rce->qpNoVbv = qNoVbv;
-                rce->qpaRc = qpRc;
-                rce->qpAq = qpAq;
-                rce->qRceq = qRceq;
-                p = next;
-            }
-            X265_FREE(statsBuf);
-            if (m_param->rc.rateControlMode != X265_RC_CQP)
-            {
-                m_start = 0;
-                m_isQpModified = true;
-                if (!initPass2())
-                    return false;
-            } /* else we're using constant quant, so no need to run the
bitrate allocation */
         }
         /* Open output file */
         /* If input and output files are the same, output to a temp file
@@ -682,19 +778,33 @@ bool RateControl::init(const SPS& sps)
             X265_FREE(p);
             if (m_param->rc.cuTree && !m_param->rc.bStatRead)
             {
-                statFileTmpname = strcatFilename(fileName, ".cutree.temp");
-                if (!statFileTmpname)
-                    return false;
-                m_cutreeStatFileOut = x265_fopen(statFileTmpname, "wb");
-                X265_FREE(statFileTmpname);
-                if (!m_cutreeStatFileOut)
+                if (SHARED_MODE_FILE == m_cutreeStorageMode)
+                {
+                    statFileTmpname = strcatFilename(fileName,
".cutree.temp");
+                    if (!statFileTmpname)
+                        return false;
+                    m_cutreeStatFileOut = x265_fopen(statFileTmpname,
"wb");
+                    X265_FREE(statFileTmpname);
+                    if (!m_cutreeStatFileOut)
+                    {
+                        x265_log_file(m_param, X265_LOG_ERROR, "can't open
mbtree stats file %s.cutree.temp\n", fileName);
+                        return false;
+                    }
+                }
+                else if (SHARED_MODE_MEM == m_cutreeStorageMode)
+                {
+                    if (!initCUTreeSharedMem())
+                    {
+                        return false;
+                    }
+                }
+                else
                 {
-                    x265_log_file(m_param, X265_LOG_ERROR, "can't open
mbtree stats file %s.cutree.temp\n", fileName);
                     return false;
                 }
             }
         }
-        if (m_param->rc.cuTree)
+        if (m_param->rc.cuTree && !m_cuTreeStats.qpBuffer[0])
         {
             if (m_param->rc.qgSize == 8)
             {
@@ -714,6 +824,10 @@ bool RateControl::init(const SPS& sps)
     return true;
 }

+void RateControl::skipCUTreeSharedMemRead(int32_t cnt)
+{
+    m_cutreeShrMem->skipRead(cnt);
+}
 void RateControl::reconfigureRC()
 {
     if (m_isVbv)
@@ -1670,10 +1784,28 @@ bool RateControl::cuTreeReadFor2Pass(Frame* frame)
             {
                 m_cuTreeStats.qpBufPos++;

-                if (!fread(&type, 1, 1, m_cutreeStatFileIn))
-                    goto fail;
-                if (fread(m_cuTreeStats.qpBuffer[m_cuTreeStats.qpBufPos],
sizeof(uint16_t), ncu, m_cutreeStatFileIn) != (size_t)ncu)
-                    goto fail;
+                if (SHARED_MODE_FILE == m_cutreeStorageMode)
+                {
+                    if (!fread(&type, 1, 1, m_cutreeStatFileIn))
+                        goto fail;
+                    if
(fread(m_cuTreeStats.qpBuffer[m_cuTreeStats.qpBufPos], sizeof(uint16_t),
ncu, m_cutreeStatFileIn) != (size_t)ncu)
+                        goto fail;
+                }
+                else
+                {
+                    if (SHARED_MODE_MEM == m_cutreeStorageMode)
+                    {
+                        if (!m_cutreeShrMem)
+                        {
+                            goto fail;
+                        }
+
+                        CUTreeSharedDataItem shrItem;
+                        shrItem.type = &type;
+                        shrItem.stats =
m_cuTreeStats.qpBuffer[m_cuTreeStats.qpBufPos];
+                        m_cutreeShrMem->readNext(&shrItem,
ReadSharedCUTreeData);
+                    }
+                }

                 if (type != sliceTypeActual && m_cuTreeStats.qpBufPos == 1)
                 {
@@ -3064,10 +3196,34 @@ int RateControl::writeRateControlFrameStats(Frame*
curFrame, RateControlEntry* r
     {
         uint8_t sliceType = (uint8_t)rce->sliceType;
         primitives.fix8Pack(m_cuTreeStats.qpBuffer[0],
curFrame->m_lowres.qpCuTreeOffset, ncu);
-        if (fwrite(&sliceType, 1, 1, m_cutreeStatFileOut) < 1)
-            goto writeFailure;
-        if (fwrite(m_cuTreeStats.qpBuffer[0], sizeof(uint16_t), ncu,
m_cutreeStatFileOut) < (size_t)ncu)
+
+        if (SHARED_MODE_FILE == m_cutreeStorageMode)
+        {
+            if (fwrite(&sliceType, 1, 1, m_cutreeStatFileOut) < 1)
+                goto writeFailure;
+            if (fwrite(m_cuTreeStats.qpBuffer[0], sizeof(uint16_t), ncu,
m_cutreeStatFileOut) < (size_t)ncu)
+                goto writeFailure;
+        }
+        else if (SHARED_MODE_MEM == m_cutreeStorageMode)
+        {
+            if (SHARED_MODE_MEM == m_cutreeStorageMode)
+            {
+                if (!m_cutreeShrMem)
+                {
+                    goto writeFailure;
+                }
+
+                CUTreeSharedDataItem shrItem;
+                shrItem.type = &sliceType;
+                shrItem.stats = m_cuTreeStats.qpBuffer[0];
+                m_cutreeShrMem->writeData(&shrItem, WriteSharedCUTreeData);
+            }
+        }
+        else
+        {
             goto writeFailure;
+        }
+
     }
     return 0;

@@ -3143,6 +3299,13 @@ void RateControl::destroy()
     if (m_cutreeStatFileIn)
         fclose(m_cutreeStatFileIn);

+    if (m_cutreeShrMem)
+    {
+        m_cutreeShrMem->release();
+        delete m_cutreeShrMem;
+        m_cutreeShrMem = NULL;
+    }
+
     X265_FREE(m_rce2Pass);
     X265_FREE(m_encOrder);
     for (int i = 0; i < 2; i++)
@@ -3151,6 +3314,8 @@ void RateControl::destroy()
     if (m_relativeComplexity)
         X265_FREE(m_relativeComplexity);

+    free(m_shrname);
+
 }

 void RateControl::splitdeltaPOC(char deltapoc[], RateControlEntry *rce)
diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
index 204bd71e1..19c8676b4 100644
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -28,6 +28,7 @@

 #include "common.h"
 #include "sei.h"
+#include "ringmem.h"

 namespace X265_NS {
 // encoder namespace
@@ -126,6 +127,13 @@ struct RateControlEntry
     bool     isFadeEnd;
 };

+enum DataSharedMode
+{
+    SHARED_MODE_FILE = 0,
+    SHARED_MODE_MEM,
+    SHARED_MODE_CNT
+};
+
 class RateControl
 {
 public:
@@ -237,9 +245,16 @@ public:
     int     m_numEntries;
     int     m_start;
     int     m_reencode;
+    ///< store the cutree data in file or shared memory
+    ///< it is not necessary to store the cutree in shared memory.
+    ///< However, for further use, shared memeory is a better choice
+    DataSharedMode m_cutreeStorageMode;
+    char   *m_shrname;
     FILE*   m_statFileOut;
     FILE*   m_cutreeStatFileOut;
     FILE*   m_cutreeStatFileIn;
+    ///< store the cutree data in memory instead of file
+    RingMem *m_cutreeShrMem;
     double  m_lastAccumPNorm;
     double  m_expectedBitsSum;   /* sum of qscale2bits after rceq,
ratefactor, and overflow, only includes finished frames */
     int64_t m_predictedBits;
@@ -254,7 +269,7 @@ public:
                                 * This value is the current position (0 or
1). */
     } m_cuTreeStats;

-    RateControl(x265_param& p, Encoder *enc);
+    RateControl(x265_param& p, Encoder *enc, char *dataShr);
     bool init(const SPS& sps);
     void initHRD(SPS& sps);
     void reconfigureRC();
@@ -274,6 +289,9 @@ public:
     int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce);
     bool   initPass2();

+    bool initCUTreeSharedMem();
+    void skipCUTreeSharedMemRead(int32_t cnt);
+
     double forwardMasking(Frame* curFrame, double q);
     double backwardMasking(Frame* curFrame, double q);

-- 
2.22.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20211006/ed42a4e1/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Enable-sharing-cutree-data-among-encoders.patch
Type: application/octet-stream
Size: 53479 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20211006/ed42a4e1/attachment-0001.obj>


More information about the x265-devel mailing list