Skip to content
Snippets Groups Projects
Commit 588a23f7 authored by Pierre Lespagnol's avatar Pierre Lespagnol Committed by Adrien Béraud
Browse files

recorder: use CQ mode for recording

Use RateMode parameter instead of autoQuality, it makes more sense for the encoder

Change-Id: Ia5b6acdfb08fb146dec11b75f1d26127a0ed520b
parent b9834d78
No related branches found
No related tags found
No related merge requests found
......@@ -51,6 +51,12 @@ enum MediaType : unsigned {
MEDIA_ALL = MEDIA_AUDIO | MEDIA_VIDEO
};
enum class RateMode : unsigned {
CRF_CONSTRAINED,
CQ,
CBR
};
/*
* SystemCodecInfo
* represent information of a codec available on the system (using libav)
......@@ -278,7 +284,7 @@ struct MediaDescription {
/** Video parameters */
std::string parameters {};
bool auto_quality {false};
RateMode mode {RateMode::CRF_CONSTRAINED};
bool linkableHW {false};
/** Crypto parameters */
......
......@@ -108,14 +108,14 @@ void
MediaEncoder::setOptions(const MediaDescription& args)
{
int ret;
if ((ret = av_opt_set_int(reinterpret_cast<void*>(outputCtx_),
"payload_type", args.payload_type, AV_OPT_SEARCH_CHILDREN)) < 0)
if (args.payload_type and (ret = av_opt_set_int(reinterpret_cast<void*>(outputCtx_),
"payload_type", args.payload_type, AV_OPT_SEARCH_CHILDREN) < 0))
JAMI_ERR() << "Failed to set payload type: " << libav_utils::getError(ret);
if (not args.parameters.empty())
libav_utils::setDictValue(&options_, "parameters", args.parameters);
auto_quality = args.auto_quality;
mode_ = args.mode;
linkableHW_ = args.linkableHW;
}
......@@ -785,7 +785,6 @@ MediaEncoder::setBitrate(uint64_t br)
if(not encoderCtx)
return;
AVMediaType codecType = encoderCtx->codec_type;
AVCodecID codecId = encoderCtx->codec_id;
// No need to restart encoder for h264, h263 and MPEG4
......@@ -811,7 +810,7 @@ void
MediaEncoder::initH264(AVCodecContext* encoderCtx, uint64_t br)
{
// If auto quality disabled use CRF mode
if(not auto_quality) {
if(mode_ == RateMode::CRF_CONSTRAINED) {
uint64_t maxBitrate = 1000 * br;
uint8_t crf = (uint8_t) std::round(LOGREG_PARAM_A + log(pow(maxBitrate, LOGREG_PARAM_B))); // CRF = A + B*ln(maxBitrate)
uint64_t bufSize = maxBitrate * 2;
......@@ -824,7 +823,7 @@ MediaEncoder::initH264(AVCodecContext* encoderCtx, uint64_t br)
JAMI_DBG("H264 encoder setup: crf=%u, maxrate=%lu, bufsize=%lu", crf, maxBitrate, bufSize);
}
// If auto quality enabled use CRB mode
else {
else if (mode_ == RateMode::CBR) {
av_opt_set_int(encoderCtx, "b", br * 1000, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "maxrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "minrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
......@@ -839,13 +838,12 @@ void
MediaEncoder::initH265(AVCodecContext* encoderCtx, uint64_t br)
{
// If auto quality disabled use CRF mode
if(not auto_quality) {
if(mode_ == RateMode::CRF_CONSTRAINED) {
uint64_t maxBitrate = 1000 * br;
// H265 use 50% less bitrate compared to H264 (half bitrate is equivalent to a change 6 for CRF)
// https://slhck.info/video/2017/02/24/crf-guide.html
uint8_t crf = (uint8_t) std::round(LOGREG_PARAM_A + log(pow(maxBitrate, LOGREG_PARAM_B)) - 6); // CRF = A + B*ln(maxBitrate)
uint64_t bufSize = maxBitrate * 2;
av_opt_set_int(encoderCtx, "crf", crf, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "b", maxBitrate, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "maxrate", maxBitrate, AV_OPT_SEARCH_CHILDREN);
......@@ -853,13 +851,12 @@ MediaEncoder::initH265(AVCodecContext* encoderCtx, uint64_t br)
av_opt_set_int(encoderCtx, "bufsize", bufSize, AV_OPT_SEARCH_CHILDREN);
JAMI_DBG("H265 encoder setup: crf=%u, maxrate=%lu, bufsize=%lu", crf, maxBitrate, bufSize);
}
else {
else if (mode_ == RateMode::CBR) {
av_opt_set_int(encoderCtx, "b", br * 1000, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "maxrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "minrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "bufsize", br * 500, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "crf", -1, AV_OPT_SEARCH_CHILDREN);
JAMI_DBG("H265 encoder setup cbr: bitrate=%lu kbit/s", br);
}
......@@ -868,6 +865,19 @@ MediaEncoder::initH265(AVCodecContext* encoderCtx, uint64_t br)
void
MediaEncoder::initVP8(AVCodecContext* encoderCtx, uint64_t br)
{
if (mode_ == RateMode::CQ) {
av_opt_set_int(encoderCtx, "g", 120, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "lag-in-frames", 0, AV_OPT_SEARCH_CHILDREN);
av_opt_set(encoderCtx, "deadline", "good", AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "cpu-used", 0, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "vprofile", 0, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "qmax", 50, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "qmin", 0, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "slices", 4, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "crf", 10, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(encoderCtx, "b", 0, AV_OPT_SEARCH_CHILDREN);
JAMI_DBG("VP8 encoder setup: crf=10");
} else {
// 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
......@@ -895,6 +905,7 @@ MediaEncoder::initVP8(AVCodecContext* encoderCtx, uint64_t br)
encoderCtx->rc_max_rate = maxBitrate;
JAMI_DBG("VP8 encoder setup: crf=%u, maxrate=%lu, bufsize=%lu", crf, maxBitrate, maxBitrate);
}
}
void
MediaEncoder::initMPEG4(AVCodecContext* encoderCtx, uint64_t br)
......
......@@ -123,6 +123,11 @@ private:
AVCodecContext* getCurrentVideoAVCtx();
void stopEncoder();
AVCodecContext* initCodec(AVMediaType mediaType, AVCodecID avcodecId, uint64_t br);
void initH264(AVCodecContext* encoderCtx, uint64_t br);
void initH265(AVCodecContext* encoderCtx, uint64_t br);
void initVP8(AVCodecContext* encoderCtx, uint64_t br);
void initMPEG4(AVCodecContext* encoderCtx, uint64_t br);
void initH263(AVCodecContext* encoderCtx, uint64_t br);
std::vector<AVCodecContext*> encoders_;
AVFormatContext *outputCtx_ = nullptr;
......@@ -134,14 +139,8 @@ private:
unsigned int currentVideoCodecID_ {0};
AVCodec* outputCodec_ = nullptr;
std::mutex encMutex_;
bool auto_quality {false};
bool linkableHW_ {false};
void initH264(AVCodecContext* encoderCtx, uint64_t br);
void initH265(AVCodecContext* encoderCtx, uint64_t br);
void initVP8(AVCodecContext* encoderCtx, uint64_t br);
void initMPEG4(AVCodecContext* encoderCtx, uint64_t br);
void initH263(AVCodecContext* encoderCtx, uint64_t br);
RateMode mode_ {RateMode::CRF_CONSTRAINED};
#ifdef ENABLE_VIDEO
video::VideoScaler scaler_;
......
......@@ -280,7 +280,10 @@ MediaRecorder::initRecord()
JAMI_ERR() << "Could not retrieve video recorder stream properties";
return -1;
}
MediaDescription args;
args.mode = RateMode::CQ;
encoder_->setOptions(videoStream);
encoder_->setOptions(args);
}
audioFilter_.reset();
......
......@@ -129,7 +129,7 @@ void VideoRtpSession::startSender()
auto codecVideo = std::static_pointer_cast<jami::AccountVideoCodecInfo>(send_.codec);
auto autoQuality = codecVideo->isAutoQualityEnabled;
send_.auto_quality = autoQuality;
send_.mode = autoQuality ? RateMode::CBR : RateMode::CRF_CONSTRAINED;
send_.linkableHW = conference_ == nullptr;
if (sender_)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment