x265-1.7版本-encoder/dpb.cpp注释

注:问号以及未注释部分 会在x265-1.8版本内更新

/*****************************************************************************
 * Copyright (C) 2013 x265 project
 *
 * Authors: Steve Borho <steve@borho.org>
 *
 * 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 "common.h"
#include "frame.h"
#include "framedata.h"
#include "picyuv.h"
#include "slice.h"

#include "dpb.h"

using namespace x265;

DPB::~DPB()
{
    while (!m_freeList.empty())
    {
        Frame* curFrame = m_freeList.popFront();
        curFrame->destroy();
        delete curFrame;
    }

    while (!m_picList.empty())
    {
        Frame* curFrame = m_picList.popFront();
        curFrame->destroy();
        delete curFrame;
    }

    while (m_picSymFreeList)
    {
        FrameData* next = m_picSymFreeList->m_freeListNext;
        m_picSymFreeList->destroy();

        m_picSymFreeList->m_reconPic->destroy();
        delete m_picSymFreeList->m_reconPic;

        delete m_picSymFreeList;
        m_picSymFreeList = next;
    }
}

// move unreferenced pictures from picList to freeList for recycle
void DPB::recycleUnreferenced()
{
    Frame *iterFrame = m_picList.first();

    while (iterFrame)
    {
        Frame *curFrame = iterFrame;
        iterFrame = iterFrame->m_next;
        if (!curFrame->m_encData->m_bHasReferences && !curFrame->m_countRefEncoders)
        {
            curFrame->m_reconRowCount.set(0);
            curFrame->m_bChromaExtended = false;

            // iterator is invalidated by remove, restart scan
            m_picList.remove(*curFrame);
            iterFrame = m_picList.first();

            m_freeList.pushBack(*curFrame);
            curFrame->m_encData->m_freeListNext = m_picSymFreeList;
            m_picSymFreeList = curFrame->m_encData;
            curFrame->m_encData = NULL;
            curFrame->m_reconPic = NULL;
        }
    }
}
/** 函数功能       : 设置NAL单元类型,将待编码帧加入DPB列表,获取slice参考帧列表等slice参量,将该帧的参考帧的被参考次数加一
/*  调用范围       : 只在Encoder::encode函数中被调用
* \参数 newFrame   : 待编码帧
*   返回值         : null
**/
void DPB::prepareEncode(Frame *newFrame)
{
    Slice* slice = newFrame->m_encData->m_slice;//获取当前frame的slice
    slice->m_poc = newFrame->m_poc;//设置当前slice的poc

    int pocCurr = slice->m_poc;//当前poc
    int type = newFrame->m_lowres.sliceType;//获取当前帧类型
    bool bIsKeyFrame = newFrame->m_lowres.bKeyframe;//当前是否为关键帧

    slice->m_nalUnitType = getNalUnitType(pocCurr, bIsKeyFrame);//返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型(并不是最终类型)
    if (slice->m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL)//如果是IDR类型,设置最近的一个关键帧位置 (只在openGOP关闭下)
        m_lastIDR = pocCurr;
    slice->m_lastIDR = m_lastIDR;//设置关键帧位置(所有poc=0都是此类型,所以可以不再if里面)
    slice->m_sliceType = IS_X265_TYPE_B(type) ? B_SLICE : (type == X265_TYPE_P) ? P_SLICE : I_SLICE;//确定slice类型

    if (type == X265_TYPE_B)//如果是不可参考B帧
    {
        newFrame->m_encData->m_bHasReferences = false;//没有帧参考它 设为false

        // Adjust NAL type for unreferenced B frames (change from _R "referenced"
        // to _N "non-referenced" NAL unit type)
        switch (slice->m_nalUnitType)
        {
        case NAL_UNIT_CODED_SLICE_TRAIL_R: //被参考的后置图像,且非TSA、非STSA的视频片段
            slice->m_nalUnitType = m_bTemporalSublayer ? NAL_UNIT_CODED_SLICE_TSA_N : NAL_UNIT_CODED_SLICE_TRAIL_N;//设置未被参考
            break;
        case NAL_UNIT_CODED_SLICE_RADL_R://RADL 前置图像(不依赖IRAP前的帧) 被参考的前置图像  只在openGOP关闭才会有此类型
            slice->m_nalUnitType = NAL_UNIT_CODED_SLICE_RADL_N;//设置未被参考
            break;
        case NAL_UNIT_CODED_SLICE_RASL_R://RASL 前置图像(依赖IRAP前的帧)   被参考的前置图像  只在openGOP打开才会有此类型
            slice->m_nalUnitType = NAL_UNIT_CODED_SLICE_RASL_N;//设置未被参考
            break;
        default:
            break;
        }
    }
    else
    {
        /* m_bHasReferences starts out as true for non-B pictures, and is set to false
         * once no more pictures reference it */
        newFrame->m_encData->m_bHasReferences = true;//可能有帧参考它设为true
    }

    m_picList.pushFront(*newFrame);//将帧加入到队列首位置

    // Do decoding refresh marking if any
    decodingRefreshMarking(pocCurr, slice->m_nalUnitType);//遇到关键帧,设置关键帧前的被参考状态(一般置为false)

    computeRPS(pocCurr, slice->isIRAP(), &slice->m_rps, slice->m_sps->maxDecPicBuffering);//slice中rps获取参考帧列表

    // Mark pictures in m_piclist as unreferenced if they are not included in RPS
    applyReferencePictureSet(&slice->m_rps, pocCurr);//将DPB m_picList列表中在不属于当前帧的参考帧列表的参考状态置为false

    slice->m_numRefIdx[0] = X265_MIN(m_maxRefL0, slice->m_rps.numberOfNegativePictures); // 获取L0最大帧数 Ensuring L0 contains just the -ve POC
    slice->m_numRefIdx[1] = X265_MIN(m_maxRefL1, slice->m_rps.numberOfPositivePictures); // 获取L1最大帧数
    slice->setRefPicList(m_picList);//获取参考帧List 以及 POC

    X265_CHECK(slice->m_sliceType != B_SLICE || slice->m_numRefIdx[1], "B slice without L1 references (non-fatal)\n");

    if (slice->m_sliceType == B_SLICE)
    {
        /* TODO: the lookahead should be able to tell which reference picture
         * had the least motion residual.  We should be able to use that here to
         * select a colocation reference list and index */
        slice->m_colFromL0Flag = false;//时域MV预测的collocated块标记位
        slice->m_colRefIdx = 0;//时域MV预测的collocated图像的参考索引号
        slice->m_bCheckLDC = false;//暂时没发现其用途
    }
    else
    {
        slice->m_bCheckLDC = true;//暂时没发现其用途
        slice->m_colFromL0Flag = true;//时域MV预测的collocated块标记位
        slice->m_colRefIdx = 0;//时域MV预测的collocated图像的参考索引号
    }
    slice->m_sLFaseFlag = (SLFASE_CONSTANT & (1 << (pocCurr % 31))) > 0;//计算m_sLFaseFlag值

    /* Increment reference count of all motion-referenced frames to prevent them
     * from being recycled. These counts are decremented at the end of
     * compressFrame() */
    //将当前帧的参考帧的参考次数都自加一
    int numPredDir = slice->isInterP() ? 1 : slice->isInterB() ? 2 : 0;//获取当前有几个list
    for (int l = 0; l < numPredDir; l++)
    {
        for (int ref = 0; ref < slice->m_numRefIdx[l]; ref++)
        {
            Frame *refpic = slice->m_refPicList[l][ref];
            ATOMIC_INC(&refpic->m_countRefEncoders);//原子锁,自加一
        }
    }
}
/** 函数功能           : slice中rps获取参考帧列表
/*  调用范围           : 只在DPB::prepareEncode函数中被调用
* \参数 curPoc         : 当前帧的POC
* \参数 isRAP          : 是否关键帧
* \参数 rps            : slice中的rps &slice->m_rps
* \参数 maxDecPicBuffer: 解码需要的最大buffer大小
*   返回值             : null
**/
void DPB::computeRPS(int curPoc, bool isRAP, RPS * rps, unsigned int maxDecPicBuffer)
{
    unsigned int poci = 0, numNeg = 0, numPos = 0;//poci:计数参考帧, numNeg:计数前向参考帧, numPos:计数后向参考帧;

    Frame* iterPic = m_picList.first();

    while (iterPic && (poci < maxDecPicBuffer - 1))//在最大buffer内寻求参考帧
    {
        if ((iterPic->m_poc != curPoc) && iterPic->m_encData->m_bHasReferences)//不是当前帧且是可被参考的帧
        {
            rps->poc[poci] = iterPic->m_poc;//获取参考帧poc
            rps->deltaPOC[poci] = rps->poc[poci] - curPoc;//获取参考帧间的poc差值
            (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++;//记录前后参考帧个数
            rps->bUsed[poci] = !isRAP;//记录是否应用
            poci++;//计数
        }
        iterPic = iterPic->m_next;
    }

    rps->numberOfPictures = poci;//获取参考帧数目
    rps->numberOfPositivePictures = numPos;//后向帧个数
    rps->numberOfNegativePictures = numNeg;//前向帧个数

    rps->sortDeltaPOC();//将RPS列表中的deltaPOC和bused 按照 远 近 (当前帧) 近 远的次序排序
}

/* Marking reference pictures when an IDR/CRA is encountered. */
/** 函数功能       : 遇到关键帧,设置关键帧前的被参考状态(一般置为false)
/*  调用范围       : 只在DPB::prepareEncode函数中被调用
* \参数 pocCurr    : 当前帧的POC
* \参数 nalUnitType: 帧类型
*   返回值         : null
**/
void DPB::decodingRefreshMarking(int pocCurr, NalUnitType nalUnitType)
{
    if (nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL)//如果当前是IDR 不是CRA
    {
        /* If the nal_unit_type is IDR, all pictures in the reference picture
         * list are marked as "unused for reference" */
        Frame* iterFrame = m_picList.first();//获取队列第一帧
        while (iterFrame)
        {
            if (iterFrame->m_poc != pocCurr)
                iterFrame->m_encData->m_bHasReferences = false;  //将buffer里面的帧都置为没有帧参考 因为当前IDR帧之后的帧一定不会继续参考前面这些帧了
            iterFrame = iterFrame->m_next;
        }
    }
    else // CRA or No DR
    {
        if (m_bRefreshPending && pocCurr > m_pocCRA)//当前帧已经在CRA帧后面 并且 m_bRefreshPending为true  将CRA前的帧的参考置为false
        {
            /* If the bRefreshPending flag is true (a deferred decoding refresh
             * is pending) and the current temporal reference is greater than
             * the temporal reference of the latest CRA picture (pocCRA), mark
             * all reference pictures except the latest CRA picture as "unused
             * for reference" and set the bRefreshPending flag to false */
            Frame* iterFrame = m_picList.first();
            while (iterFrame)
            {
                if (iterFrame->m_poc != pocCurr && iterFrame->m_poc != m_pocCRA)
                    iterFrame->m_encData->m_bHasReferences = false;  //在CRA帧之后,前置帧将不被参考
                iterFrame = iterFrame->m_next;
            }

            m_bRefreshPending = false;//前置状态置为false
        }
        if (nalUnitType == NAL_UNIT_CODED_SLICE_CRA)//CRA 关键帧 在openGOP时使用
        {
            /* If the nal_unit_type is CRA, set the bRefreshPending flag to true
             * and pocCRA to the temporal reference of the current picture */
            m_bRefreshPending = true; //表示有CRA前置帧
            m_pocCRA = pocCurr;//在openGOP打开下 最近的一个关键帧位置
        }
    }

    /* Note that the current picture is already placed in the reference list and
     * its marking is not changed.  If the current picture has a nal_ref_idc
     * that is not 0, it will remain marked as "used for reference" */
}

/** Function for applying picture marking based on the Reference Picture Set */
/** 函数功能           : 将DPB m_picList列表中在不属于当前帧的参考帧列表的参考状态置为false
/*  调用范围           : 只在DPB::prepareEncode函数中被调用
* \参数 rps            : slice中的rps &slice->m_rps
* \参数 curPoc         : 当前帧的POC
*   返回值             : null
**/
void DPB::applyReferencePictureSet(RPS *rps, int curPoc)
{
    // loop through all pictures in the reference picture buffer
    Frame* iterFrame = m_picList.first();
    while (iterFrame)
    {
        if (iterFrame->m_poc != curPoc && iterFrame->m_encData->m_bHasReferences)
        {
            // loop through all pictures in the Reference Picture Set
            // to see if the picture should be kept as reference picture
            bool referenced = false;
            for (int i = 0; i < rps->numberOfPositivePictures + rps->numberOfNegativePictures; i++)//将需要参考的置为ture
            {
                if (iterFrame->m_poc == curPoc + rps->deltaPOC[i])
                {
                    referenced = true;
                    break;
                }
            }
            if (!referenced)
                iterFrame->m_encData->m_bHasReferences = false;//不在上述列表中的 ,其参考位置为false
        }
        iterFrame = iterFrame->m_next;
    }
}

/* deciding the nal_unit_type */
/** 函数功能       : 返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型(并不是最终类型)
/*  调用范围       : 只在DPB::prepareEncode函数中被调用
* \参数 curPOC     : 当前poc
* \参数 bIsKeyFrame: 是否为IDR帧
*   返回值         : 返回前置图像NAL类型,后置图像NAL类型,关键帧NAL类型
**/
NalUnitType DPB::getNalUnitType(int curPOC, bool bIsKeyFrame)
{
    if (!curPOC)
        return NAL_UNIT_CODED_SLICE_IDR_W_RADL;//视频序列第一帧, IDR帧,前置帧无参考前面的帧

    if (bIsKeyFrame)//当前为关键帧
        return m_bOpenGOP ? NAL_UNIT_CODED_SLICE_CRA : NAL_UNIT_CODED_SLICE_IDR_W_RADL;//如果打开GOP , 则当前的关键帧为CRA(其前置图像可以为RASL可以参考前面的帧)

    if (m_pocCRA && curPOC < m_pocCRA)
        // All leading pictures are being marked as TFD pictures here since
        // current encoder uses all reference pictures while encoding leading
        // pictures. An encoder can ensure that a leading picture can be still
        // decodable when random accessing to a CRA/CRANT/BLA/BLANT picture by
        // controlling the reference pictures used for encoding that leading
        // picture. Such a leading picture need not be marked as a TFD picture.
        return NAL_UNIT_CODED_SLICE_RASL_R;//只在打开openGOP情况下进入:如果当前帧号小于最近的关键帧,返回前置图像为RASL_R(被参考的前置图像,并且前置图像也参考其前面的帧)

    if (m_lastIDR && curPOC < m_lastIDR)
        return NAL_UNIT_CODED_SLICE_RADL_R;//只在关闭openGOP情况下进入:如果当前帧号小于最近的关键帧,返回前置图像为RADL_R(被参考的前置图像,并且前置图像不参考其前面的帧)

    return NAL_UNIT_CODED_SLICE_TRAIL_R;//被参考的后置图像,且非TSA、非STSA的视频片段
}


 

LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf LDF Modes: Finder ~ chain, Compatibility ~ soft Found 37 compatible libraries Scanning dependencies... Dependency Graph |-- ESP32Encoder @ 0.11.8 Building in release mode Compiling .pio/build/esp32-c3-devkitm-1/src/main.cpp.o Linking .pio/build/esp32-c3-devkitm-1/firmware.elf /Users/gengwenhao/.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: .pio/build/esp32-c3-devkitm-1/src/main.cpp.o: in function `setup()': /Users/gengwenhao/Documents/PlatformIO/Projects/9KEY_ENCODER/src/main.cpp:22: undefined reference to `ESP32Encoder::attachHalfQuad(int, int)' /Users/gengwenhao/.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /Users/gengwenhao/Documents/PlatformIO/Projects/9KEY_ENCODER/src/main.cpp:25: undefined reference to `ESP32Encoder::clearCount()' /Users/gengwenhao/.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /Users/gengwenhao/Documents/PlatformIO/Projects/9KEY_ENCODER/src/main.cpp:31: undefined reference to `ESP32Encoder::getCount()' /Users/gengwenhao/.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: .pio/build/esp32-c3-devkitm-1/src/main.cpp.o: in function `_GLOBAL__sub_I_encoder': /Users/gengwenhao/Documents/PlatformIO/Projects/9KEY_ENCODER/src/main.cpp:70: undefined reference to `ESP32Encoder::ESP32Encoder(bool, void (*)(void*), void*)' collect2: error: ld returned 1 exit status *** [.pio/build/esp32-c3-devkitm-1/firmware.elf] Error 1 =================================================== [FAILED] Took 1.36 seconds ===
最新发布
08-04
<think>我们正在解决ESP32Encoder库在PlatformIO中出现的未定义引用错误。这种错误通常发生在链接阶段,表明编译器找到了函数声明,但没有找到其实现。以下是一些常见原因及解决方法: ### 1. **检查库的安装** - 确保已正确安装ESP32Encoder库。在PlatformIO中,可以通过`platformio.ini`文件添加依赖。 - 在`platformio.ini`中添加: ``` lib_deps = madhephaestus/ESP32Encoder @ ^0.12.0 ``` ### 2. **检查库的兼容性** - 确保所安装的库版本支持ESP32-C3。由于ESP32-C3是RISC-V架构,某些库可能不支持。ESP32Encoder库从0.12.0版本开始支持ESP32-C3[^1]。 ### 3. **检查头文件包含** - 在代码中正确包含头文件: ```cpp #include <ESP32Encoder.h> ``` ### 4. **链接器错误的具体分析** - 错误信息类似`undefined reference to 'ESP32Encoder::ESP32Encoder()'`,这通常意味着链接器找不到库的实现。可能的原因: - 库未正确安装:检查`.pio/libdeps`目录下是否存在`ESP32Encoder`文件夹。 - 构建系统未链接库:确保PlatformIO能够自动链接已安装的库。 ### 5. **清理并重新构建** - 在PlatformIO中,执行清理并重新构建: ``` pio run --target clean pio run ``` ### 6. **检查硬件支持** - 确保在`platformio.ini`中正确设置了板子型号: ``` board = esp32-c3-devkitm-1 platform = espressif32 ``` ### 7. **更新PlatformIO和平台** - 更新PlatformIO核心和Espressif32平台: ``` pio upgrade pio platform update espressif32 ``` ### 8. **使用正确的命名空间** - 根据库的文档,使用正确的类名。例如: ```cpp ESP32Encoder encoder; ``` ### 9. **检查库的依赖** - 某些库可能依赖其他库。ESP32Encoder依赖于`driver`库,但PlatformIO通常会自动处理。 ### 10. **查看库的示例** - 参考官方示例代码,确保使用方式正确。 ### 示例代码 ```cpp #include <Arduino.h> #include <ESP32Encoder.h> ESP32Encoder encoder; void setup() { encoder.attachSingleEdge(0, 1); // 根据实际引脚调整 } void loop() { Serial.println(encoder.getCount()); delay(100); } ``` ### 如果问题仍然存在 - 查看库的源代码,确认函数实现是否存在。 - 在GitHub上搜索类似问题。 §§相关问题§§ 1. 如何为ESP32-C3在PlatformIO中添加第三方库? 2. 如何更新PlatformIO的核心和平台? 3. ESP32Encoder库在ESP32-C3上使用时需要注意什么?</think>### ESP32Encoder库在PlatformIO中的链接错误解决方案 您在ESP32-C3-DevKitM-1开发板上使用ESP32Encoder库时遇到的`undefined reference`错误,通常是由于链接器找不到库函数的实现代码导致的。以下是系统化的解决步骤: #### 1. **检查库安装与依赖** - 在`platformio.ini`中添加库依赖(使用最新兼容版本): ```ini lib_deps = madhephaestus/ESP32Encoder @ ^0.12.0 ``` - 执行清理重建: ```bash pio run --target clean && pio run ``` - **注意**:ESP32-C3需要库版本≥0.12.0才能支持RISC-V架构[^1] #### 2. **验证硬件配置** - 确保`platformio.ini`正确定义开发板: ```ini [env:esp32-c3] platform = espressif32 board = esp32-c3-devkitm-1 framework = arduino ``` #### 3. **检查代码包含关系** - 在`.cpp`文件中正确包含头文件: ```cpp #include <ESP32Encoder.h> // 注意不是"ESP32Encoder.h" ``` - 全局初始化编码器对象(避免局部声明): ```cpp ESP32Encoder encoder; // 全局对象声明 void setup() { encoder.attachSingleEdge(0, 1); // GPIO0和GPIO1 } ``` #### 4. **解决架构兼容性问题** - 如果是旧版库导致的RISC-V兼容问题: 1. 打开`.pio/libdeps/esp32-c3/ESP32Encoder/src/ESP32Encoder.h` 2. 确保存在以下宏定义: ```cpp #if CONFIG_IDF_TARGET_ESP32C3 #define _ENCODER_USE_RMT #endif ``` #### 5. **更新开发环境** - 升级PlatformIO核心: ```bash pio upgrade ``` - 更新ESP32平台: ```bash pio platform update espressif32 ``` #### 6. **验证最小可运行示例** ```cpp #include <Arduino.h> #include <ESP32Encoder.h> ESP32Encoder encoder; void setup() { Serial.begin(115200); ESP32Encoder::useInternalWeakPullResistors = UP; // 启用内部上拉 encoder.attachSingleEdge(0, 1); // 使用单边沿计数模式 } void loop() { Serial.printf("Count: %d\n", encoder.getCount()); delay(100); } ``` > **常见错误模式**: > `undefined reference to ESP32Encoder::attachSingleEdge(...)` > ➜ 通常表示库未正确链接,检查`.pio/libdeps`目录是否存在库文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值