zoukankan      html  css  js  c++  java
  • openh264 动态调整码率

    正文

    openh264 提供动态码率调整功能,可以通过ISVCEncoder::setOption()实现, 如下所示,更改了编码视频空域层的码率;

    SEncParamExt encParamExt;
    encoder->GetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
    encParamExt.sSpatialLayers[0].iSpatialBitrate =  100 * 1000;
    encParamExt.sSpatialLayers[0].iMaxSpatialBitrate =  100 * 1000;
    encoder->SetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
    

    直接设置编码器的bitrate没有效果,需要改变空域层bitrate,实测发现变更的码率设置的太低会导致一些帧被过滤掉,完整代码如下(bufferReader没有贴上来),完整工程在此

    #include <iostream>
    #include <wels/codec_api.h>
    #include <wels/codec_app_def.h>
    #include <wels/codec_def.h>
    #include <wels/codec_ver.h>
    #include <assert.h>
    #include <string.h>
    #include "bufferReader.h"
    #include <stdio.h>
    
    struct Args{
        int picHeight= 288;
        int picWidth = 352;
        const char* srcFile =  "../res/soccor.yuv";
        const char* dstFile =  "../res/output.264";
    };
    
    void InitParam(SEncParamBase& param, const int picWidth, const int picHeight){
        memset(&param, 0, sizeof(SEncParamBase));
        param.iUsageType = CAMERA_VIDEO_REAL_TIME;
        param.fMaxFrameRate = 50;
        param.iPicWidth = picWidth;
        param.iPicHeight = picHeight;
        param.iTargetBitrate = 900 * 1000;
        param.iRCMode = RC_BITRATE_MODE;
    }
    
    void  SetupEncoder(ISVCEncoder*& encoder, const SEncParamBase& param){
        int rv = WelsCreateSVCEncoder(&encoder);
        assert(0 == rv);
        assert(encoder != NULL);
        assert(encoder->Initialize(&param) == 0);
    
        //changing logging granularity
        int g_LevelSetting = 1;
        encoder->SetOption(ENCODER_OPTION_TRACE_LEVEL, &g_LevelSetting);
    
        int videoFormat = videoFormatI420;
        encoder->SetOption(ENCODER_OPTION_DATAFORMAT, &videoFormat);
    
        //changing encoding param
        //encoder->SetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, &param);
    
    }
    
    void SetupPic(unsigned char* data, SFrameBSInfo& info, SSourcePicture& pic, const int& picHeight, const int& picWidth){  
        memset(&info, 0, sizeof(SFrameBSInfo));
        memset(&pic, 0, sizeof(SSourcePicture));
        pic.iPicWidth = picWidth;
        pic.iPicHeight = picHeight;
        pic.iColorFormat = videoFormatI420;
        pic.iStride[0] = pic.iPicWidth;
        pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
        pic.pData[0] = data;
        pic.pData[1] = pic.pData[0] + picWidth * picHeight;
        pic.pData[2] = pic.pData[1] + (picWidth * picHeight >> 2);
    }
    
    void Encode(ISVCEncoder* encoder, const Args& args){
        
        const char* file_name = args.srcFile;
        sshsu::BufferReader buf(args.picWidth, args.picHeight, file_name);
        FILE* outFd = fopen(args.dstFile, "w+");
        assert(outFd!= nullptr);
        
        SFrameBSInfo info;
        SSourcePicture pic;
        SetupPic(buf.Data(), info, pic, args.picHeight, args.picWidth);
    
        
        SEncParamExt encParamExt;
        encoder->GetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
    
        int frame_num = 0;
        int total_bytes = 0;
        while(buf.ReadFrame()){
            if(frame_num == 100){
                std::cout<<"change bitrate to 100kb/s"<<std::endl;
                encParamExt.sSpatialLayers[0].iSpatialBitrate =  100 * 1000;
                encParamExt.sSpatialLayers[0].iMaxSpatialBitrate =  100 * 1000;
                encoder->SetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
            }
            int rv = encoder->EncodeFrame(&pic, &info);
            assert(rv == cmResultSuccess);
            if (info.eFrameType != videoFrameTypeSkip)
            {   
                
                int iLayerNum = info.iLayerNum; 
                for(int i = 0;i<iLayerNum;++i){
                    SLayerBSInfo &layer = info.sLayerInfo[i];
                    int iLayerSize = 0;
                    int iLNalIdx = layer.iNalCount - 1;
                    do
                    {
                        iLayerSize += layer.pNalLengthInByte[iLNalIdx];
                    } while (--iLNalIdx >= 0);
                    fwrite(layer.pBsBuf, 1, iLayerSize, outFd);
                    ++frame_num;
                    total_bytes += iLayerSize;
                    std::cout << "save frame: " << frame_num << ", size:" << iLayerSize << std::endl;
                }
            }
            else{
                std::cout<<"videoFrameTypeskip for rate control"<<std::endl;
            }
        }
        std::cout << "save frame to file: "" <<args.dstFile << "", total bytes: " << total_bytes <<std::endl;
        fflush(outFd);
        fclose(outFd);
    }
    
    int main(int, char**) {
        Args args;
        SEncParamBase encoderParam;
        InitParam(encoderParam, args.picWidth, args.picHeight);
        ISVCEncoder* encoder;
        SetupEncoder(encoder, encoderParam);
        Encode(encoder, args);
        encoder->Uninitialize();
        WelsDestroySVCEncoder(encoder);
        return 0;
    }
    

    通过elecard streameye去看调整前后调整后的图像,分明可以看到大小不一样, 以下是将码率设置成500kb/s然后调整到250kb/s的结果,量化步长变大了,编码过程中有一些丢帧,可能将很多intra-block改成了inter-block

  • 相关阅读:
    夯实Java基础系列5:Java文件和Java包结构
    夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理
    夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!
    夯实Java基础系列1:Java面向对象三大特性(基础篇)
    走进JavaWeb技术世界16:极简配置的SpringBoot
    深入JavaWeb技术世界15:深入浅出Mybatis基本原理
    走进JavaWeb技术世界14:Mybatis入门
    走进JavaWeb技术世界13:Hibernate入门经典与注解式开发
    [转]ssm整合1(环境搭建)
    [转]基于S2SH框架的项目—antlr-2.7.2.jar包冲突问题
  • 原文地址:https://www.cnblogs.com/ishen/p/14800370.html
Copyright © 2011-2022 走看看