From 82fb0dae37119d3a56282834461cfe9e68ea326a Mon Sep 17 00:00:00 2001 From: Eloi BAIL <eloi.bail@savoirfairelinux.com> Date: Wed, 28 Oct 2015 17:35:46 -0400 Subject: [PATCH] media/video: use crf rather than bitrate Dynamic quality change was done by increase/decreasing encoder bitrate. It led to video artefact issues, specialy at low bitrates. In addition, it does not make sence to use same bitrate with different resolutions and fps. With high resolutions and fps, maximal bitrate need to be higher. It is possible for H264 and VP8 to set video quality using CRF. This parameter solves video artefact issues and choose a different output bitrate depending on input resolution and fps. Tuleap: #80 Change-Id: I07d37175dfc335b5fc70cf54798f82eafe921ea9 --- src/dring/account_const.h | 3 + src/media/media_codec.cpp | 23 ++++- src/media/media_codec.h | 29 +++++- src/media/media_encoder.cpp | 40 ++++++-- src/media/system_codec_container.cpp | 14 ++- src/media/video/video_rtp_session.cpp | 128 ++++++++++++++++++++------ src/media/video/video_rtp_session.h | 24 +++-- 7 files changed, 210 insertions(+), 51 deletions(-) diff --git a/src/dring/account_const.h b/src/dring/account_const.h index 379b4d4b49..cce6bc9679 100644 --- a/src/dring/account_const.h +++ b/src/dring/account_const.h @@ -223,6 +223,9 @@ constexpr static const char FRAME_RATE [] = "CodecInfo.frameRate"; constexpr static const char BITRATE [] = "CodecInfo.bitrate"; constexpr static const char MIN_BITRATE [] = "CodecInfo.min_bitrate"; constexpr static const char MAX_BITRATE [] = "CodecInfo.max_bitrate"; +constexpr static const char QUALITY [] = "CodecInfo.quality"; +constexpr static const char MIN_QUALITY [] = "CodecInfo.min_quality"; +constexpr static const char MAX_QUALITY [] = "CodecInfo.max_quality"; constexpr static const char CHANNEL_NUMBER [] = "CodecInfo.channelNumber"; } //namespace DRing::Account::ConfProperties::CodecInfo diff --git a/src/media/media_codec.cpp b/src/media/media_codec.cpp index d340753771..b1939b204c 100644 --- a/src/media/media_codec.cpp +++ b/src/media/media_codec.cpp @@ -42,7 +42,10 @@ generateId() SystemCodecInfo::SystemCodecInfo(unsigned avcodecId, const std::string name, std::string libName, MediaType mediaType, CodecType codecType, - unsigned bitrate, unsigned payloadType) + unsigned bitrate, + unsigned payloadType, + unsigned minQuality, + unsigned maxQuality) : id(generateId()) , avcodecId(avcodecId) , name(name) @@ -51,6 +54,8 @@ SystemCodecInfo::SystemCodecInfo(unsigned avcodecId, const std::string name, , mediaType(mediaType) , payloadType(payloadType) , bitrate(bitrate) + , minQuality(minQuality) + , maxQuality(maxQuality) {} SystemCodecInfo::~SystemCodecInfo() @@ -94,11 +99,13 @@ SystemVideoCodecInfo::SystemVideoCodecInfo(unsigned m_avcodecId, std::string m_libName, CodecType m_type, unsigned m_bitrate, + unsigned m_minQuality, + unsigned m_maxQuality, unsigned m_payloadType, unsigned m_frameRate, unsigned m_profileId) : SystemCodecInfo(m_avcodecId, m_name, m_libName, MEDIA_VIDEO, - m_type, m_bitrate, m_payloadType) + m_type, m_bitrate, m_payloadType, m_minQuality, m_maxQuality) , frameRate(m_frameRate), profileId(m_profileId) {} @@ -124,7 +131,10 @@ AccountCodecInfo::AccountCodecInfo(const SystemCodecInfo& sysCodecInfo) , isActive(true) , payloadType(sysCodecInfo.payloadType) , bitrate(sysCodecInfo.bitrate) -{} +{ + if (sysCodecInfo.minQuality != SystemCodecInfo::DEFAULT_NO_QUALITY) + quality = SystemCodecInfo::DEFAULT_CODEC_QUALITY; +} AccountCodecInfo::~AccountCodecInfo() {} @@ -187,6 +197,9 @@ AccountVideoCodecInfo::getCodecSpecifications() {DRing::Account::ConfProperties::CodecInfo::BITRATE, to_string(bitrate)}, {DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE, to_string(systemCodecInfo.maxBitrate)}, {DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE, to_string(systemCodecInfo.minBitrate)}, + {DRing::Account::ConfProperties::CodecInfo::QUALITY, to_string(quality)}, + {DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY, to_string(systemCodecInfo.maxQuality)}, + {DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY, to_string(systemCodecInfo.minQuality)}, {DRing::Account::ConfProperties::CodecInfo::FRAME_RATE, to_string(frameRate)} }; } @@ -201,6 +214,10 @@ AccountVideoCodecInfo::setCodecSpecifications(const std::map<std::string, std::s it = details.find(DRing::Account::ConfProperties::CodecInfo::FRAME_RATE); if (it != details.end()) frameRate = ring::stoi(it->second); + + it = details.find(DRing::Account::ConfProperties::CodecInfo::QUALITY); + if (it != details.end()) + quality = ring::stoi(it->second); } AccountVideoCodecInfo::~AccountVideoCodecInfo() diff --git a/src/media/media_codec.h b/src/media/media_codec.h index 5f2d6a3f36..46ed7896ea 100644 --- a/src/media/media_codec.h +++ b/src/media/media_codec.h @@ -59,16 +59,29 @@ enum MediaType : unsigned { */ struct SystemCodecInfo { + static constexpr unsigned DEFAULT_CODEC_QUALITY {35}; +#ifdef RING_VIDEO + static constexpr unsigned DEFAULT_H264_MIN_QUALITY {50}; + static constexpr unsigned DEFAULT_H264_MAX_QUALITY {25}; + static constexpr unsigned DEFAULT_VP8_MIN_QUALITY {50}; + static constexpr unsigned DEFAULT_VP8_MAX_QUALITY {20}; +#endif + + // indicates that the codec does not use quality factor + static constexpr unsigned DEFAULT_NO_QUALITY {0}; + + static constexpr unsigned DEFAULT_MIN_BITRATE {250}; + static constexpr unsigned DEFAULT_MAX_BITRATE {2000}; + SystemCodecInfo(unsigned avcodecId, const std::string name, std::string libName, MediaType mediaType, CodecType codecType = CODEC_NONE, unsigned bitrate = 0, - unsigned payloadType = 0); + unsigned payloadType = 0, + unsigned m_minQuality = DEFAULT_NO_QUALITY, + unsigned m_maxQuality = DEFAULT_NO_QUALITY); virtual ~SystemCodecInfo(); - static constexpr unsigned DEFAULT_MIN_BITRATE {250}; - static constexpr unsigned DEFAULT_MAX_BITRATE {2000}; - /* generic codec information */ unsigned id; /* id of the codec used with dbus */ unsigned avcodecId; /* read as AVCodecID libav codec identifier */ @@ -82,6 +95,8 @@ struct SystemCodecInfo unsigned bitrate; unsigned minBitrate = DEFAULT_MIN_BITRATE; unsigned maxBitrate = DEFAULT_MAX_BITRATE; + unsigned minQuality = DEFAULT_NO_QUALITY; + unsigned maxQuality = DEFAULT_NO_QUALITY; }; /* @@ -114,7 +129,10 @@ struct SystemVideoCodecInfo : SystemCodecInfo SystemVideoCodecInfo(unsigned avcodecId, const std::string name, std::string libName, CodecType type = CODEC_NONE, unsigned bitrate = 0, - unsigned payloadType = 0, unsigned frameRate = 0, + unsigned m_minQuality = 0, + unsigned m_maxQuality = 0, + unsigned payloadType = 0, + unsigned frameRate = 0, unsigned profileId = 0); ~SystemVideoCodecInfo(); @@ -142,6 +160,7 @@ struct AccountCodecInfo /* account custom values */ unsigned payloadType; unsigned bitrate; + unsigned quality; std::map<std::string, std::string> getCodecSpecifications(); }; diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index 6705bdeac1..ea93b19bf9 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2013-2015 Savoir-faire Linux Inc. * * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> + * Author: Eloi Bail <Eloi.Bail@savoirfairelinux.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 @@ -75,6 +76,7 @@ void MediaEncoder::setOptions(const MediaDescription& args) av_dict_set(&options_, "payload_type", ring::to_string(args.payload_type).c_str(), 0); av_dict_set(&options_, "max_rate", ring::to_string(args.codec->bitrate).c_str(), 0); + av_dict_set(&options_, "crf", ring::to_string(args.codec->quality).c_str(), 0); if (args.codec->systemCodecInfo.mediaType == MEDIA_AUDIO) { auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(args.codec); @@ -140,17 +142,30 @@ MediaEncoder::openOutput(const char *filename, prepareEncoderContext(args.codec->systemCodecInfo.mediaType == MEDIA_VIDEO); auto maxBitrate = 1000 * atoi(av_dict_get(options_, "max_rate", NULL, 0)->value); - encoderCtx_->rc_buffer_size = maxBitrate; - RING_DBG("Using max bitrate %d", maxBitrate ); + auto crf = atoi(av_dict_get(options_, "crf", NULL, 0)->value); + /* let x264 preset override our encoder settings */ if (args.codec->systemCodecInfo.avcodecId == AV_CODEC_ID_H264) { extractProfileLevelID(args.parameters, encoderCtx_); forcePresetX264(); - // For H264 : define max bitrate in rc_max_rate - encoderCtx_->rc_max_rate = maxBitrate; + // For H264 : + // 1- if quality is set use it + // 2- otherwise set rc_max_rate and rc_buffer_size + if (crf != SystemCodecInfo::DEFAULT_NO_QUALITY) { + av_opt_set(encoderCtx_->priv_data, "crf", av_dict_get(options_, "crf", NULL, 0)->value, 0); + RING_DBG("Using quality factor %d", crf); + } else { + encoderCtx_->rc_buffer_size = maxBitrate; + encoderCtx_->rc_max_rate = maxBitrate; + RING_DBG("Using max bitrate %d", maxBitrate ); + } } else if (args.codec->systemCodecInfo.avcodecId == AV_CODEC_ID_VP8) { + // For VP8 : + // 1- if quality is set use it + // bitrate need to be set. The target bitrate becomes the maximum allowed bitrate + // 2- otherwise set rc_max_rate and rc_buffer_size // Using information given on this page: // http://www.webmproject.org/docs/encoder-parameters/ av_opt_set(encoderCtx_->priv_data, "quality", "realtime", 0); @@ -161,11 +176,22 @@ MediaEncoder::openOutput(const char *filename, encoderCtx_->qmin = 4; encoderCtx_->qmax = 56; encoderCtx_->gop_size = 999999; - // For VP8 : define max bitrate in bit_rate + + encoderCtx_->rc_buffer_size = maxBitrate; encoderCtx_->bit_rate = maxBitrate; + if (crf != SystemCodecInfo::DEFAULT_NO_QUALITY) { + av_opt_set(encoderCtx_->priv_data, "crf", av_dict_get(options_, "crf", NULL, 0)->value, 0); + RING_DBG("Using quality factor %d", crf); + } else { + RING_DBG("Using Max bitrate %d", maxBitrate); + } } else if (args.codec->systemCodecInfo.avcodecId == AV_CODEC_ID_MPEG4) { - // For MPEG4 : define max bitrate in bit_rate - encoderCtx_->bit_rate = maxBitrate; + // For MPEG4 : + // No CRF avaiable. + // Use CBR (set bitrate) + encoderCtx_->rc_buffer_size = maxBitrate; + encoderCtx_->bit_rate = encoderCtx_->rc_min_rate = encoderCtx_->rc_max_rate = maxBitrate; + RING_DBG("Using Max bitrate %d", maxBitrate); } int ret; diff --git a/src/media/system_codec_container.cpp b/src/media/system_codec_container.cpp index 3a8a0ae258..ec23e5d92b 100644 --- a/src/media/system_codec_container.cpp +++ b/src/media/system_codec_container.cpp @@ -46,18 +46,28 @@ SystemCodecContainer::~SystemCodecContainer() void SystemCodecContainer::initCodecConfig() { +#ifdef RING_VIDEO + auto minH264 = SystemCodecInfo::DEFAULT_H264_MIN_QUALITY; + auto maxH264 = SystemCodecInfo::DEFAULT_H264_MAX_QUALITY; + auto minVP8 = SystemCodecInfo::DEFAULT_VP8_MIN_QUALITY; + auto maxVP8 = SystemCodecInfo::DEFAULT_VP8_MAX_QUALITY; +#endif availableCodecList_ = { #ifdef RING_VIDEO /* Define supported video codec*/ std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_H264, "H264", "libx264", CODEC_ENCODER_DECODER, - DEFAULT_VIDEO_BITRATE), + DEFAULT_VIDEO_BITRATE, + minH264, + maxH264), std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_VP8, "VP8", "libvpx", CODEC_ENCODER_DECODER, - DEFAULT_VIDEO_BITRATE), + DEFAULT_VIDEO_BITRATE, + minVP8, + maxVP8), std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_MPEG4, "MP4V-ES", "mpeg4", diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 219d4da360..0727065548 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -310,10 +310,44 @@ VideoRtpSession::checkPeerPacketLoss() return NO_PACKET_LOSS_CALCULATED; } +unsigned +VideoRtpSession::getLowerQuality() +{ + // if lower quality was stored we return it + unsigned quality = videoBitrateInfo_.videoQualityCurrent; + while ( not histoQuality_.empty()) { + quality = histoQuality_.back(); + histoQuality_.pop_back(); + if (quality > videoBitrateInfo_.videoQualityCurrent) + return quality; + } + + // if no appropriate quality found, calculate it with dichotomie + quality = (videoBitrateInfo_.videoQualityCurrent + videoBitrateInfo_.videoQualityMin) / 2; + return quality; +} + +unsigned +VideoRtpSession::getLowerBitrate() +{ + // if a lower bitrate was stored we return it + unsigned bitrate = videoBitrateInfo_.videoBitrateCurrent; + while ( not histoBitrate_.empty()) { + bitrate = histoBitrate_.back(); + histoBitrate_.pop_back(); + if (bitrate < videoBitrateInfo_.videoBitrateCurrent) + return bitrate; + } + + // if no appropriate bitrate found, calculate it with dichotomie + bitrate = (videoBitrateInfo_.videoBitrateCurrent + videoBitrateInfo_.videoBitrateMin) / 2; + return bitrate; +} + void -VideoRtpSession::adaptBitrate() +VideoRtpSession::adaptQualityAndBitrate() { - bool needToCheckBitrate = false; + bool needToCheckQuality = false; bool mediaRestartNeeded = false; float packetLostRate = 0.0; @@ -321,65 +355,87 @@ VideoRtpSession::adaptBitrate() auto rtcpLongCheckTimer = std::chrono::duration_cast<std::chrono::seconds> (std::chrono::system_clock::now() - lastLongRTCPCheck_); if (rtcpCheckTimer.count() >= RTCP_CHECKING_INTERVAL) { - needToCheckBitrate = true; + needToCheckQuality = true; lastRTCPCheck_ = std::chrono::system_clock::now(); } if (rtcpLongCheckTimer.count() >= RTCP_LONG_CHECKING_INTERVAL) { - needToCheckBitrate = true; + needToCheckQuality = true; lastLongRTCPCheck_ = std::chrono::system_clock::now(); - //we force iterative bitrate adaptation + // we force iterative bitrate adaptation videoBitrateInfo_.cptBitrateChecking = 0; } - if (needToCheckBitrate) { + if (needToCheckQuality) { + videoBitrateInfo_.cptBitrateChecking++; - auto oldBitrate = videoBitrateInfo_.videoBitrateCurrent; - //packetLostRate is not already available. Do nothing + // packetLostRate is not already available. Do nothing if ((packetLostRate = checkPeerPacketLoss()) == NO_PACKET_LOSS_CALCULATED) { - //we force iterative bitrate adaptation + // we force iterative bitrate adaptation videoBitrateInfo_.cptBitrateChecking = 0; - //too much packet lost : decrease bitrate + // too much packet lost : decrease quality and bitrate } else if (packetLostRate >= videoBitrateInfo_.packetLostThreshold) { - //calculate new bitrate by dichotomie - videoBitrateInfo_.videoBitrateCurrent = - (videoBitrateInfo_.videoBitrateCurrent + videoBitrateInfo_.videoBitrateMin) / 2; + // calculate new quality by dichotomie + videoBitrateInfo_.videoQualityCurrent = getLowerQuality(); + + // calculate new bitrate by dichotomie + videoBitrateInfo_.videoBitrateCurrent = getLowerBitrate(); + + // boundaries low + if (videoBitrateInfo_.videoQualityCurrent > videoBitrateInfo_.videoQualityMin) + videoBitrateInfo_.videoQualityCurrent = videoBitrateInfo_.videoQualityMin; - //boundaries low if (videoBitrateInfo_.videoBitrateCurrent < videoBitrateInfo_.videoBitrateMin) videoBitrateInfo_.videoBitrateCurrent = videoBitrateInfo_.videoBitrateMin; - //we force iterative bitrate adaptation + + // we force iterative bitrate and quality adaptation videoBitrateInfo_.cptBitrateChecking = 0; - //asynchronous A/V media restart - if (videoBitrateInfo_.videoBitrateCurrent != oldBitrate) + // asynchronous A/V media restart + // we give priority to quality + if (((videoBitrateInfo_.videoQualityCurrent != SystemCodecInfo::DEFAULT_NO_QUALITY) && + (videoBitrateInfo_.videoQualityCurrent != (histoQuality_.empty() ? 0 : histoQuality_.back()))) || + ((videoBitrateInfo_.videoQualityCurrent == SystemCodecInfo::DEFAULT_NO_QUALITY) && + (videoBitrateInfo_.videoBitrateCurrent != (histoBitrate_.empty() ? 0 : histoBitrate_.back())))) mediaRestartNeeded = true; - //no packet lost: increase bitrate + + // no packet lost: increase quality and bitrate } else if (videoBitrateInfo_.cptBitrateChecking <= videoBitrateInfo_.maxBitrateChecking) { - //calculate new bitrate by dichotomie + // calculate new quality by dichotomie + videoBitrateInfo_.videoQualityCurrent = + (videoBitrateInfo_.videoQualityCurrent + videoBitrateInfo_.videoQualityMax) / 2; + + // calculate new bitrate by dichotomie videoBitrateInfo_.videoBitrateCurrent = ( videoBitrateInfo_.videoBitrateCurrent + videoBitrateInfo_.videoBitrateMax) / 2; - //boundaries high + // boundaries high + if (videoBitrateInfo_.videoQualityCurrent < videoBitrateInfo_.videoQualityMax) + videoBitrateInfo_.videoQualityCurrent = videoBitrateInfo_.videoQualityMax; + if (videoBitrateInfo_.videoBitrateCurrent > videoBitrateInfo_.videoBitrateMax) videoBitrateInfo_.videoBitrateCurrent = videoBitrateInfo_.videoBitrateMax; - //asynchronous A/V media restart - if (videoBitrateInfo_.videoBitrateCurrent != oldBitrate) + // asynchronous A/V media restart + // we give priority to quality + if (((videoBitrateInfo_.videoQualityCurrent != SystemCodecInfo::DEFAULT_NO_QUALITY) && + (videoBitrateInfo_.videoQualityCurrent != (histoQuality_.empty() ? 0 : histoQuality_.back()))) || + ((videoBitrateInfo_.videoQualityCurrent == SystemCodecInfo::DEFAULT_NO_QUALITY) && + (videoBitrateInfo_.videoBitrateCurrent != (histoBitrate_.empty() ? 0 : histoBitrate_.back())))) mediaRestartNeeded = true; if (videoBitrateInfo_.cptBitrateChecking == videoBitrateInfo_.maxBitrateChecking) lastLongRTCPCheck_ = std::chrono::system_clock::now(); } else { - //nothing we reach maximal tries + // nothing we reach maximal tries } } @@ -387,10 +443,11 @@ VideoRtpSession::adaptBitrate() storeVideoBitrateInfo(); const auto& cid = callID_; - RING_WARN("[%u/%u] packetLostRate=%f -> change bitrate to %d", + RING_WARN("[%u/%u] packetLostRate=%f -> change quality to %d bitrate to %d", videoBitrateInfo_.cptBitrateChecking, videoBitrateInfo_.maxBitrateChecking, packetLostRate, + videoBitrateInfo_.videoQualityCurrent, videoBitrateInfo_.videoBitrateCurrent); runOnMainThread([cid]{ @@ -399,7 +456,6 @@ VideoRtpSession::adaptBitrate() }); } } - void VideoRtpSession::getVideoBitrateInfo() { auto codecVideo = std::static_pointer_cast<ring::AccountVideoCodecInfo>(send_.codec); @@ -408,12 +464,15 @@ VideoRtpSession::getVideoBitrateInfo() { (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::BITRATE])), (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE])), (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE])), + (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::QUALITY])), + (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY])), + (unsigned)(ring::stoi(codecVideo->getCodecSpecifications()[DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY])), videoBitrateInfo_.cptBitrateChecking, videoBitrateInfo_.maxBitrateChecking, videoBitrateInfo_.packetLostThreshold, }; } else { - videoBitrateInfo_ = {0,0,0,0,0,0}; + videoBitrateInfo_ = {0,0,0,0,0,0,0,0,0}; } } @@ -425,8 +484,21 @@ VideoRtpSession::storeVideoBitrateInfo() { codecVideo->setCodecSpecifications({ {DRing::Account::ConfProperties::CodecInfo::BITRATE, ring::to_string(videoBitrateInfo_.videoBitrateCurrent)}, {DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE, ring::to_string(videoBitrateInfo_.videoBitrateMin)}, - {DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE, ring::to_string(videoBitrateInfo_.videoBitrateMax)} + {DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE, ring::to_string(videoBitrateInfo_.videoBitrateMax)}, + {DRing::Account::ConfProperties::CodecInfo::QUALITY, ring::to_string(videoBitrateInfo_.videoQualityCurrent)}, + {DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY, ring::to_string(videoBitrateInfo_.videoQualityMin)}, + {DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY, ring::to_string(videoBitrateInfo_.videoQualityMax)} }); + + if (histoQuality_.size() > MAX_SIZE_HISTO_QUALITY_) + histoQuality_.pop_front(); + + if (histoBitrate_.size() > MAX_SIZE_HISTO_BITRATE_) + histoBitrate_.pop_front(); + + histoQuality_.push_back(videoBitrateInfo_.videoQualityCurrent); + histoBitrate_.push_back(videoBitrateInfo_.videoBitrateCurrent); + } } bool @@ -439,7 +511,7 @@ VideoRtpSession::setupRtcpChecker() void VideoRtpSession::processRtcpChecker() { - adaptBitrate(); + adaptQualityAndBitrate(); rtcpCheckerThread_.wait_for(std::chrono::seconds(RTCP_CHECKING_INTERVAL)); } diff --git a/src/media/video/video_rtp_session.h b/src/media/video/video_rtp_session.h index ca469b828f..5010cb62f4 100644 --- a/src/media/video/video_rtp_session.h +++ b/src/media/video/video_rtp_session.h @@ -45,6 +45,9 @@ struct VideoBitrateInfo { unsigned videoBitrateCurrent; unsigned videoBitrateMin; unsigned videoBitrateMax; + unsigned videoQualityCurrent; + unsigned videoQualityMin; + unsigned videoQualityMax; unsigned cptBitrateChecking; unsigned maxBitrateChecking; float packetLostThreshold; @@ -92,19 +95,28 @@ private: uint16_t initSeqVal_ = 0; float checkPeerPacketLoss(); - void adaptBitrate(); + unsigned getLowerQuality(); + unsigned getLowerBitrate(); + void adaptQualityAndBitrate(); void storeVideoBitrateInfo(); void getVideoBitrateInfo(); - //interval in seconds between RTCP checkings + // interval in seconds between RTCP checkings const unsigned RTCP_CHECKING_INTERVAL {4}; - //long interval in seconds between RTCP checkings + // long interval in seconds between RTCP checkings const unsigned RTCP_LONG_CHECKING_INTERVAL {30}; - //not packet loss can be calculated as no data in input + // no packet loss can be calculated as no data in input static constexpr float NO_PACKET_LOSS_CALCULATED {-1.0}; - //bitrate info struct - VideoBitrateInfo videoBitrateInfo_ = {0,0,0,0, MAX_ADAPTATIVE_BITRATE_ITERATION, PACKET_LOSS_THRESHOLD}; + // bitrate and quality info struct + VideoBitrateInfo videoBitrateInfo_ = {0,0,0,0,0,0,0, MAX_ADAPTATIVE_BITRATE_ITERATION, PACKET_LOSS_THRESHOLD}; + // previous quality and bitrate used if quality or bitrate need to be decreased + std::list<unsigned> histoQuality_ {}; + std::list<unsigned> histoBitrate_ {}; + // max size of quality and bitrate historic + static constexpr unsigned MAX_SIZE_HISTO_QUALITY_ {30}; + static constexpr unsigned MAX_SIZE_HISTO_BITRATE_ {100}; + //5 tries in a row static constexpr unsigned MAX_ADAPTATIVE_BITRATE_ITERATION {5}; //packet loss threshold -- GitLab