ayamir / openh264-differentiated-streaming

openh264 for unity object-level ROI encoding
BSD 2-Clause "Simplified" License
2 stars 1 forks source link

how use the roi function? #1

Closed rick1018 closed 6 months ago

rick1018 commented 7 months ago

Hello, it seems you're using the EncodeFrame function with some code to set different priorities for blocks in the left and right halves of the image. However, not observing the expected effects.

how to use?

    virtual int EXTAPI EncodeFrame (const SSourcePicture* kpSrcPic, SFrameBSInfo* pBsInfo, float* pPriorityArray) = 0;
        int iWidth = 720;
        int iHeight = 1280;
        const int iWidthInBlocks = iWidth / 16;  // 每行的宏块数
        const int iHeightInBlocks = iHeight / 16;  // 每列的宏块数

        // 划分图像为左右两半
        const int iLeftHalfWidth = iWidthInBlocks / 2;  // 左半部分的宏块数

        // 设置左半部分为超级模糊,右半部分为正常画质
        for (int i = 0; i < iHeightInBlocks; ++i) {
            for (int j = 0; j < iWidthInBlocks; ++j) {
                int iBlockIndex = i * iWidthInBlocks + j;
                if (j < iLeftHalfWidth) {
                    pPriorityArray[iBlockIndex] = 10;  // 设置较高的量化参数,模拟模糊效果
                } else {
                    pPriorityArray[iBlockIndex] = 3;  // 设置正常的量化参数
                }
            }
        }
ayamir commented 7 months ago

I have a repo for test: https://github.com/ayamir/openh264_test Higher value in priorityArray means higher quality and lower QP. The picture quality also depends on the targetBitrates. The logic of ROI encoding is to maintain RC requirements as much as possible while accepting foreign weights. So it's maybe not so intuitive. If you want to check the effect in the intuitive way, it's better to use ffmpeg to extract each encoded frame and make a comparison of the ROI-enabled and the original version. Here is my own test result of setting the laptop region with higher weights under 2.5Mbps: image

rick1018 commented 7 months ago

Hello, it seems you're using the EncodeFrame function with some code to set different priorities for blocks in the left and right halves of the image. However, not observing the expected effects.

how to use?

 virtual int EXTAPI EncodeFrame (const SSourcePicture* kpSrcPic, SFrameBSInfo* pBsInfo, float* pPriorityArray) = 0;
     int iWidth = 720;
     int iHeight = 1280;
     const int iWidthInBlocks = iWidth / 16;  // 每行的宏块数
     const int iHeightInBlocks = iHeight / 16;  // 每列的宏块数

     // 划分图像为左右两半
     const int iLeftHalfWidth = iWidthInBlocks / 2;  // 左半部分的宏块数

     // 设置左半部分为超级模糊,右半部分为正常画质
     for (int i = 0; i < iHeightInBlocks; ++i) {
         for (int j = 0; j < iWidthInBlocks; ++j) {
             int iBlockIndex = i * iWidthInBlocks + j;
             if (j < iLeftHalfWidth) {
                 pPriorityArray[iBlockIndex] = 10;  // 设置较高的量化参数,模拟模糊效果
             } else {
                 pPriorityArray[iBlockIndex] = 3;  // 设置正常的量化参数
             }
         }
     }

Thank you for your response. I will use the you provided project and give it a try.

rick1018 commented 7 months ago

excuse me ,could you provide your pPriorityArray for my reference?

ayamir commented 7 months ago

I just uploaded my test bins on google drive, you can download the yuv file and the weights file here: https://drive.google.com/drive/folders/1bj7N5ASK3KuCuV6-Ws3C0os0tRioZiuD?usp=sharing

rick1018 commented 7 months ago

I'm sorry, but even with the same configuration as yours, I can't achieve the same output. I only notice a noticeable change in image quality when I adjust the QP values. Is there something I'm overlooking?

const string weightsDir = testbinDir + "weights";
    const string weightLog = testbinDir + "weight_cut.log";
    if (!fs::is_directory(weightsDir)) {
        fs::create_directory(weightsDir);
        splitWeightLog(weightLog, weightsDir);
    }
    int targetBitrate = 2500*1024;
    SEncParamExt param;
    memset(&param, 0, sizeof(SEncParamExt));
    param.iUsageType = EUsageType::CAMERA_VIDEO_REAL_TIME;
    param.bSimulcastAVC = false;
    param.iPicWidth = width;
    param.iPicHeight = height;
    param.fMaxFrameRate = outputFps;
    param.iTemporalLayerNum = 1;
    param.uiIntraPeriod = 0;
    param.eSpsPpsIdStrategy = EParameterSetStrategy::INCREASING_ID;
    param.bEnableFrameCroppingFlag = 1;
    param.iEntropyCodingModeFlag = 0;
    param.uiMaxNalSize = 0;
    param.iComplexityMode = ECOMPLEXITY_MODE::LOW_COMPLEXITY;
    param.iLoopFilterDisableIdc = 0;
    param.iLoopFilterAlphaC0Offset = 0;
    param.iLoopFilterBetaOffset = 0;
    param.iMultipleThreadIdc = 1;
    param.bUseLoadBalancing = true;
    param.iRCMode = RC_BITRATE_MODE;
    param.iTargetBitrate = 288*1000*1000;
    param.iMaxBitrate = UNSPECIFIED_BIT_RATE;
    param.bEnableFrameSkip = false;
    param.iMaxQp = 51;
    param.iMinQp = 0;
    param.bEnableDenoise = false;
    param.bEnableSceneChangeDetect = false;
    param.bEnableBackgroundDetection = false;
    param.bEnableAdaptiveQuant = false;
    param.bEnableLongTermReference = false;
    param.iLtrMarkPeriod = 30;
    param.bPrefixNalAddingCtrl = false;
    param.iSpatialLayerNum = 1;

    SSpatialLayerConfig *pDLayer = &param.sSpatialLayers[0];
    pDLayer->iVideoWidth = width;
    pDLayer->iVideoHeight = height;
    pDLayer->fFrameRate = outputFps;
    pDLayer->uiProfileIdc = PRO_BASELINE;
    pDLayer->iSpatialBitrate = (int)(targetBitrate);
    pDLayer->iMaxSpatialBitrate = UNSPECIFIED_BIT_RATE;
    pDLayer->iDLayerQp = 24;
    pDLayer->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;

    const string diffSuffix = isDiffEncoding ? "-diff" : "";
//    const string qpSuffix = "-minqp" + to_string(iMinQp) + "-maxqp" + to_string(iMaxQp);
//    const string outFileName = testbinDir + "out" + diffSuffix + qpSuffix + ".h264";
    const string outFileDir = testbinDir + to_string(targetBitrate) + "m/";
    if (!fs::is_directory(outFileDir)) {
        assert(fs::create_directory(outFileDir) == true);
    }
    const string outFile = outFileDir + "out" + diffSuffix;

    TestCallback cbk;
    BaseEncoderTest *pTest = new BaseEncoderTest();
    pTest->SetUp();
    pTest->EncodeFile(inputFileName.c_str(), &param, &cbk, outFile + h264Suffix);
    pTest->TearDown();

    assert(h264ToMp4(outFile) == 0);
ayamir commented 7 months ago

Are you using the same input file? You can view the weight distribution info in the log file and the corresponding region will have higher quality while maintaining orverall bitrates constant. As I said before, you should do it to see a intuitive effect. (command: ffmpeg -i out-diff.mp4 out-diff/frame-diff-%04d.png)

If you want to check the effect in the intuitive way, it's better to use ffmpeg to extract each encoded frame and make a comparison of the ROI-enabled and the original version.

rick1018 commented 6 months ago

thanks ,I followed your suggestion and it made a difference. But now that I’m using it on my mobile phone, the effect isn’t that obvious, and I’m still trying to figure it out.