diff --git a/meson.build b/meson.build index 2702788..5ac3776 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('LibMebo', 'c', +project('LibMebo', ['c' , 'cpp'], version : '0.1.0.1', meson_version : '>= 0.49', default_options: [ 'warning_level=2', diff --git a/src/Handlers/AV1RateControlHandler.cpp b/src/Handlers/AV1RateControlHandler.cpp new file mode 100644 index 0000000..0b42aa5 --- /dev/null +++ b/src/Handlers/AV1RateControlHandler.cpp @@ -0,0 +1,203 @@ +#include "AV1RateControlHandler.hpp" +#include + +#include "../../aom/av1/ratectrl_rtc.h" + +Libmebo_brc_AV1::Libmebo_brc_AV1(LibMeboBrcAlgorithmID algo_id) + : Libmebo_brc(LIBMEBO_CODEC_AV1, algo_id), handle(nullptr), + ptrCreateAV1Controller(nullptr) { + enc_params_libmebo.num_sl = 1; + enc_params_libmebo.num_tl = 1; + enc_params_libmebo.bitrate = 288; // in kbps. + enc_params_libmebo.dynamic_rate_change = 0; + enc_params_libmebo.framecount = 100; + enc_params_libmebo.framerate = 60; + enc_params_libmebo.width = 320; + enc_params_libmebo.height = 160; + enc_params_libmebo.id = static_cast(LIBMEBO_CODEC_AV1); + enc_params_libmebo.preset = 0; + enc_params_libmebo.buf_optimal_sz = 600; +} + +Libmebo_brc_AV1::~Libmebo_brc_AV1() { + if (handle) { + dlclose(handle); + } +} + +aom::AV1RateControlRtcConfig *config; +void *controller; + +int Libmebo_brc_AV1::InitSymbolsFromLiray() { + char path[] = "/lib64/libaom_av1_rc.so"; // this needs to be at config time. + handle = dlopen(path, RTLD_LAZY); + if (!handle) { + return kMainHandleLibError; + } + + ptrCreateAV1Controller = + (createAV1Controller_t)dlsym(handle, "create_av1_ratecontrol_rtc"); + if (!ptrCreateAV1Controller) { + return kAv1CreateSymbLoadError; + } + + create_av1_ratecontrol_config = (create_av1_rate_control_config_t)dlsym( + handle, "create_av1_ratecontrol_config"); + + if (!create_av1_ratecontrol_config) { + return kAV1RateCtrlConfigSymbLoadError; + } + + ptrUpdateRateControl_AV1 = + (UpdateRateControl_AV1_t)dlsym(handle, "update_ratecontrol_av1"); + if (!ptrUpdateRateControl_AV1) { + return kUpdateRateControlSymbLoadError; + } + + ptrComputeQP_AV1 = + (ComputeQP_AV1_t)dlsym(handle, "compute_qp_ratecontrol_av1"); + if (!ptrComputeQP_AV1) { + return kCompueQPSymbLoadError; + } + + ptrPostEncodeUpdate_AV1 = (PostEncodeUpdate_AV1_t)dlsym( + handle, "post_encode_update_ratecontrol_av1"); + if (!ptrPostEncodeUpdate_AV1) { + return kPostEncodeSymbLoadError; + } + + ptrGetQP_AV1 = (GetQP_AV1_t)dlsym(handle, "get_qp_ratecontrol_av1"); + if (!ptrGetQP_AV1) { + return kGetQpSymbLoadError; + } + + ptrGetLoopfilterLevel_AV1 = (GetLoopfilterLevel_AV1_t)dlsym( + handle, "get_loop_filter_level_ratecontrol_av1"); + if (!ptrGetLoopfilterLevel_AV1) { + return kGetLoopFilterSymbError; + } + + return kNoError; +} + +LibMeboRateController * +Libmebo_brc_AV1::init(LibMeboRateController *libmebo_rc, + LibMeboRateControllerConfig *libmebo_rc_config) { + + int result = InitSymbolsFromLiray(); + if (result != kNoError) { + return nullptr; + } + libmebo_rc = Libmebo_brc::init(libmebo_rc, libmebo_rc_config); + + config = create_av1_ratecontrol_config(); + if (config == nullptr) + return nullptr; + + constexpr int kMinQP = 10; + constexpr int kMaxQP = 56; + config->width = 640; + config->height = 480; + // third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc + config->max_quantizer = kMaxQP; + config->min_quantizer = kMinQP; + + config->buf_initial_sz = 600; + config->buf_optimal_sz = 500; + config->target_bandwidth = 800000 / 1000; + config->buf_sz = 1000; + config->undershoot_pct = 25; + config->overshoot_pct = 50; + config->max_intra_bitrate_pct = 300; + config->max_inter_bitrate_pct = 50; + config->framerate = 60; + config->layer_target_bitrate[0] = 800000 / 1000; + + config->ts_rate_decimator[0] = 1; + config->aq_mode = 1; + config->ss_number_layers = 1; + config->ts_number_layers = 1; + config->max_quantizers[0] = kMaxQP; + config->min_quantizers[0] = kMinQP; + config->scaling_factor_num[0] = 1; + config->scaling_factor_den[0] = 1; + config->frame_drop_thresh = 30; + config->max_consec_drop = 8; + + controller = ptrCreateAV1Controller(*config); + if (controller == nullptr) + return nullptr; + return libmebo_rc; +} + +LibMeboStatus +Libmebo_brc_AV1::update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) { + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + + if (!rc || !rc_config) + return LIBMEBO_STATUS_ERROR; + + ptrUpdateRateControl_AV1(controller, *config); + + return status; +} + +LibMeboStatus Libmebo_brc_AV1::post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) { + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + + if (!rc) + return LIBMEBO_STATUS_ERROR; + + ptrPostEncodeUpdate_AV1(controller, encoded_frame_size); + + return status; +} + +LibMeboStatus +Libmebo_brc_AV1::compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) { + + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + + if (!rc) + return LIBMEBO_STATUS_ERROR; + aom::AV1FrameParamsRTC frame_params_aom; + + if (rc_frame_params->frame_type == LIBMEBO_KEY_FRAME) + frame_params_aom.frame_type = aom::kKeyFrame; + else + frame_params_aom.frame_type = aom::kInterFrame; + + ptrComputeQP_AV1(controller, frame_params_aom); + return status; +} + +LibMeboStatus Libmebo_brc_AV1::get_qp(LibMeboRateController *rc, int *qp) { + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + + if (!rc) + return LIBMEBO_STATUS_ERROR; + + *qp = ptrGetQP_AV1(controller); + return status; +} + +LibMeboStatus Libmebo_brc_AV1::get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) { + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + if (!rc) + return LIBMEBO_STATUS_ERROR; + + aom::AV1LoopfilterLevel loop_filter_level; + + loop_filter_level = ptrGetLoopfilterLevel_AV1(controller); + + filter_level[0] = loop_filter_level.filter_level[0]; + filter_level[1] = loop_filter_level.filter_level[1]; + filter_level[2] = loop_filter_level.filter_level_u; + filter_level[3] = loop_filter_level.filter_level_v; + + return status; +} diff --git a/src/Handlers/AV1RateControlHandler.hpp b/src/Handlers/AV1RateControlHandler.hpp new file mode 100644 index 0000000..837b3c8 --- /dev/null +++ b/src/Handlers/AV1RateControlHandler.hpp @@ -0,0 +1,68 @@ +#pragma once +#include + +extern "C" { +#include "../lib/libmebo.hpp" +} +#include "../../aom/av1/ratectrl_rtc.h" +#include "LibMeboControlHandler.hpp" + +typedef enum ErrorsLoadingSymbols { + kNoError = 0, + kMainHandleLibError = -1, + kAv1CreateSymbLoadError = -2, + kAV1RateCtrlConfigSymbLoadError = -3, + kUpdateRateControlSymbLoadError = -4, + kCompueQPSymbLoadError = -5, + kPostEncodeSymbLoadError = -6, + kGetQpSymbLoadError = -7, + kGetLoopFilterSymbError = -8, +} ErrosLibmeboSymbols; + +class Libmebo_brc_AV1 : public Libmebo_brc { +public: + Libmebo_brc_AV1(LibMeboBrcAlgorithmID algo_id); + virtual ~Libmebo_brc_AV1() override; + LibMeboRateController *init(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) override; + LibMeboStatus update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) override; + LibMeboStatus post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) override; + LibMeboStatus compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) override; + LibMeboStatus get_qp(LibMeboRateController *rc, int *qp) override; + LibMeboStatus get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) override; + int InitSymbolsFromLiray(); + +private: + typedef void *BrcCodecEnginePtr; + BrcCodecEnginePtr brc_codec_handler; + // std::unique_ptr av1_rc_rtc_; + void *handle; + typedef aom::AV1RateControlRtcConfig *(*create_av1_rate_control_config_t)(); + typedef void *(*createAV1Controller_t)( + const aom::AV1RateControlRtcConfig &rc_cfg); + typedef bool (*UpdateRateControl_AV1_t)( + void *controller, const aom::AV1RateControlRtcConfig &rc_cfg); + typedef int (*GetQP_AV1_t)(void *controller); + typedef aom::FrameDropDecision (*ComputeQP_AV1_t)( + void *controller, const aom::AV1FrameParamsRTC &frame_params); + typedef aom::AV1LoopfilterLevel (*GetLoopfilterLevel_AV1_t)(void *controller); + typedef void (*PostEncodeUpdate_AV1_t)(void *controller, + uint64_t encoded_frame_size); + typedef bool (*GetSegmentationData_AV1_t)( + void *controller, aom::AV1SegmentationData *segmentation_data); + typedef aom::AV1CdefInfo (*GetCdefInfo_AV1_t)(void *controller); + + create_av1_rate_control_config_t create_av1_ratecontrol_config; + createAV1Controller_t ptrCreateAV1Controller; + UpdateRateControl_AV1_t ptrUpdateRateControl_AV1; + GetQP_AV1_t ptrGetQP_AV1; + ComputeQP_AV1_t ptrComputeQP_AV1; + GetLoopfilterLevel_AV1_t ptrGetLoopfilterLevel_AV1; + PostEncodeUpdate_AV1_t ptrPostEncodeUpdate_AV1; + GetSegmentationData_AV1_t ptrGetSegmentationData_AV1; + GetCdefInfo_AV1_t ptrGetCdefInfo_AV1; +}; diff --git a/src/Handlers/LibMeboControlHandler.cpp b/src/Handlers/LibMeboControlHandler.cpp new file mode 100644 index 0000000..202f5fd --- /dev/null +++ b/src/Handlers/LibMeboControlHandler.cpp @@ -0,0 +1,148 @@ +#include +#include +extern "C" { +#include "../lib/libmebo.hpp" +} + +#include "LibMeboControlHandler.hpp" + +Libmebo_brc::Libmebo_brc(LibMeboCodecType codec_type_in, + LibMeboBrcAlgorithmID algo_id_in) { + /* will init encparams based on algo id*/ + codec_type = codec_type_in; + algo_id = algo_id_in; +} + +uint32_t +Libmebo_brc::MaxSizeOfKeyframeAsPercentage(uint32_t optimal_buffer_size, + uint32_t max_framerate) { + // Set max to the optimal buffer level (normalized by target BR), + // and scaled by a scale_par. + // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. + // This value is presented in percentage of perFrameBw: + // perFrameBw = targetBR[Kbps] * 1000 / framerate. + // The target in % is as follows: + const double target_size_byte_per_frame = optimal_buffer_size * 0.5; + const uint32_t target_size_kbyte = + target_size_byte_per_frame * max_framerate / 1000; + const uint32_t target_size_kbyte_as_percent = target_size_kbyte * 100; + + // Don't go below 3 times the per frame bandwidth. + const uint32_t kMinIntraSizePercentage = 300u; + if (kMinIntraSizePercentage > target_size_kbyte_as_percent) + return kMinIntraSizePercentage; + else + return target_size_kbyte_as_percent; +} + +int Libmebo_brc::GetBitratekBps_l(int sl_id, int tl_id) { + return layered_bitrates[sl_id][tl_id]; +} + +void Libmebo_brc::InitLayeredFramerate(int num_tl, int framerate, + int *ts_rate_decimator) { + for (int tl = 0; tl < num_tl; tl++) { + if (tl == 0) + layered_frame_rate[tl] = framerate / ts_rate_decimator[tl]; + else + layered_frame_rate[tl] = (framerate / ts_rate_decimator[tl]) - + (framerate / ts_rate_decimator[tl - 1]); + } +} + +#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl)) + +void Libmebo_brc::InitLayeredBitrateAlloc(int num_sl, int num_tl, int bitrate) { + int sl, tl; + + assert(num_sl && num_sl <= MaxSpatialLayers); + assert(num_tl && num_tl <= MaxTemporalLayers); + + for (sl = 0; sl < num_sl; sl++) { + int sl_rate = bitrate / num_sl; + for (tl = 0; tl < num_tl; tl++) { + layered_bitrates[sl][tl] = sl_rate / num_tl; + } + } +} + +LibMeboRateController * +Libmebo_brc::init(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) { + InitLayeredBitrateAlloc(enc_params_libmebo.num_sl, enc_params_libmebo.num_tl, + enc_params_libmebo.bitrate); + rc_config->width = enc_params_libmebo.width; + rc_config->height = enc_params_libmebo.height; + rc_config->max_quantizer = 63; + rc_config->min_quantizer = 0; + rc_config->target_bandwidth = enc_params_libmebo.bitrate; + rc_config->buf_initial_sz = 500; + rc_config->buf_optimal_sz = 600; + ; + rc_config->buf_sz = 1000; + rc_config->undershoot_pct = 50; + rc_config->overshoot_pct = 50; + rc_config->buf_initial_sz = 500; + rc_config->buf_optimal_sz = 600; + ; + rc_config->buf_sz = 1000; + rc_config->undershoot_pct = 50; + rc_config->overshoot_pct = 50; + // Fixme + rc_config->max_intra_bitrate_pct = MaxSizeOfKeyframeAsPercentage( + rc_config->buf_optimal_sz, enc_params_libmebo.framerate); + rc_config->max_intra_bitrate_pct = 0; + rc_config->framerate = enc_params_libmebo.framerate; + + rc_config->max_quantizers[0] = rc_config->max_quantizer; + rc_config->min_quantizers[0] = rc_config->min_quantizer; + + rc_config->ss_number_layers = enc_params_libmebo.num_sl; + rc_config->ts_number_layers = enc_params_libmebo.num_tl; + + switch (enc_params_libmebo.num_sl) { + case 1: + rc_config->scaling_factor_num[0] = 1; + rc_config->scaling_factor_den[0] = 1; + break; + case 2: + rc_config->scaling_factor_num[0] = 1; + rc_config->scaling_factor_den[0] = 2; + rc_config->scaling_factor_num[1] = 1; + rc_config->scaling_factor_den[1] = 1; + break; + case 3: + rc_config->scaling_factor_num[0] = 1; + rc_config->scaling_factor_den[0] = 4; + rc_config->scaling_factor_num[1] = 1; + rc_config->scaling_factor_den[1] = 2; + rc_config->scaling_factor_num[2] = 1; + rc_config->scaling_factor_den[2] = 1; + break; + default: + break; + } + + std::cout << "enc params - width, height, bitrate, sl, tl :" + << enc_params_libmebo.width << "," << enc_params_libmebo.height + << "," << enc_params_libmebo.num_tl << "," + << enc_params_libmebo.num_sl << "," << enc_params_libmebo.bitrate + << "\n"; + for (unsigned int sl = 0; sl < enc_params_libmebo.num_sl; sl++) { + int bitrate_sum = 0; + for (unsigned int tl = 0; tl < enc_params_libmebo.num_tl; tl++) { + const int layer_id = LAYER_IDS_TO_IDX(sl, tl, enc_params_libmebo.num_tl); + rc_config->max_quantizers[layer_id] = rc_config->max_quantizer; + rc_config->min_quantizers[layer_id] = rc_config->min_quantizer; + bitrate_sum += GetBitratekBps_l(sl, tl); + rc_config->layer_target_bitrate[layer_id] = bitrate_sum; + std::cout << "bitrate_sum : " << bitrate_sum << std::endl; + rc_config->ts_rate_decimator[tl] = + 1u << (enc_params_libmebo.num_tl - tl - 1); + } + InitLayeredFramerate(enc_params_libmebo.num_tl, + enc_params_libmebo.framerate, + rc_config->ts_rate_decimator); + } + return rc; +} \ No newline at end of file diff --git a/src/Handlers/LibMeboControlHandler.hpp b/src/Handlers/LibMeboControlHandler.hpp new file mode 100644 index 0000000..0513aa9 --- /dev/null +++ b/src/Handlers/LibMeboControlHandler.hpp @@ -0,0 +1,55 @@ + +#pragma once +extern "C" { +#include "../lib/libmebo.hpp" +} + +#define MaxSpatialLayers 3 +#define MaxTemporalLayers 3 + +struct EncParams_1 { + unsigned int preset; + unsigned int id; + unsigned int bitrate; // in kbps + unsigned int framerate; + unsigned int width; + unsigned int height; + unsigned int framecount; // Number of Frames to be encoded + unsigned int num_sl; // Number of Spatial Layers + unsigned int num_tl; // Number of Temporal Layers + unsigned int dynamic_rate_change; // dynamic rate change enablement flag + int64_t buf_optimal_sz; +}; + +class Libmebo_brc { +public: + Libmebo_brc(LibMeboCodecType codec_type, LibMeboBrcAlgorithmID algo_id); + virtual ~Libmebo_brc() = default; + + virtual LibMeboRateController * + init(LibMeboRateController *rc, LibMeboRateControllerConfig *rc_config) = 0; + virtual LibMeboStatus update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) = 0; + virtual LibMeboStatus post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) = 0; + virtual LibMeboStatus compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) = 0; + virtual LibMeboStatus get_qp(LibMeboRateController *rc, int *qp) = 0; + virtual LibMeboStatus get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) = 0; + + uint32_t MaxSizeOfKeyframeAsPercentage(uint32_t optimal_buffer_size, + uint32_t max_framerate); + int GetBitratekBps_l(int sl_id, int tl_id); + void InitLayeredFramerate(int num_tl, int framerate, int *ts_rate_decimator); + void InitLayeredBitrateAlloc(int num_sl, int num_tl, int bitrate); + + LibMeboCodecType getCodecType() const { return codec_type; } + +protected: + LibMeboCodecType codec_type; + LibMeboBrcAlgorithmID algo_id; + EncParams_1 enc_params_libmebo; + int layered_frame_rate[MaxTemporalLayers]; + int layered_bitrates[MaxSpatialLayers][MaxTemporalLayers]; +}; diff --git a/src/Handlers/VP8RateControlHandler.cpp b/src/Handlers/VP8RateControlHandler.cpp new file mode 100644 index 0000000..cd3deb9 --- /dev/null +++ b/src/Handlers/VP8RateControlHandler.cpp @@ -0,0 +1,107 @@ +#include "VP8RateControlHandler.hpp" +#include +extern "C" { +#include "../brc/vp8/libvpx_derived/libvpx_vp8_rtc.h" + +Libmebo_brc_VP8::Libmebo_brc_VP8(LibMeboBrcAlgorithmID algo_id) + : Libmebo_brc(LIBMEBO_CODEC_VP8, algo_id) { + enc_params_libmebo.num_sl = 1; + enc_params_libmebo.num_tl = 1; + enc_params_libmebo.bitrate = 288; // in kbps. + enc_params_libmebo.dynamic_rate_change = 0; + enc_params_libmebo.framecount = 100; + enc_params_libmebo.framerate = 60; + enc_params_libmebo.width = 320; + enc_params_libmebo.height = 160; + enc_params_libmebo.id = static_cast(LIBMEBO_CODEC_VP8); + enc_params_libmebo.preset = 0; + enc_params_libmebo.buf_optimal_sz = 600; +} + +LibMeboRateController * +Libmebo_brc_VP8::init(LibMeboRateController *libmebo_rc, + LibMeboRateControllerConfig *libmebo_rc_config) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + if (!libmebo_rc || !libmebo_rc_config) + return nullptr; + + libmebo_rc = Libmebo_brc::init(libmebo_rc, libmebo_rc_config); + status = brc_vp8_rate_control_init(libmebo_rc_config, &brc_codec_handler); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to Initialize the RateController\n"); + + // ToDo: Make it explicit to enforce the algorithm implementor to validate + // the input params + // brc_status = priv->brc_interface.validate (rc_config, + // &priv->brc_codec_handler); + + return libmebo_rc; +} + +LibMeboStatus +Libmebo_brc_VP8::update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc || !rc_cfg) + return status; + status = brc_vp8_update_rate_control(brc_codec_handler, rc_cfg); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to Update the RateController\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP8::post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + if (!rc) + return status; + + status = brc_vp8_post_encode_update(brc_codec_handler, encoded_frame_size); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to do the post encode update \n"); + + return status; +} + +LibMeboStatus +Libmebo_brc_VP8::compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp8_compute_qp(brc_codec_handler, rc_frame_params); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to compute the QP\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP8::get_qp(LibMeboRateController *rc, int *qp) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + if (!rc) + return status; + status = brc_vp8_get_qp(brc_codec_handler, qp); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to get the QP\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP8::get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp8_get_loop_filter_level(brc_codec_handler, filter_level); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to get the Loop filter level\n"); + + return status; +} +} // extern "C" diff --git a/src/Handlers/VP8RateControlHandler.hpp b/src/Handlers/VP8RateControlHandler.hpp new file mode 100644 index 0000000..9614c22 --- /dev/null +++ b/src/Handlers/VP8RateControlHandler.hpp @@ -0,0 +1,26 @@ +#pragma once +extern "C" { +#include "../lib/libmebo.hpp" +} +#include "LibMeboControlHandler.hpp" + +class Libmebo_brc_VP8 : public Libmebo_brc { +public: + Libmebo_brc_VP8(LibMeboBrcAlgorithmID algo_id); + virtual ~Libmebo_brc_VP8() override = default; + LibMeboRateController *init(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) override; + LibMeboStatus update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) override; + LibMeboStatus post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) override; + LibMeboStatus compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) override; + LibMeboStatus get_qp(LibMeboRateController *rc, int *qp) override; + LibMeboStatus get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) override; + +private: + typedef void *BrcCodecEnginePtr; + BrcCodecEnginePtr brc_codec_handler; +}; \ No newline at end of file diff --git a/src/Handlers/VP9RateControlHandler.cpp b/src/Handlers/VP9RateControlHandler.cpp new file mode 100644 index 0000000..ec66721 --- /dev/null +++ b/src/Handlers/VP9RateControlHandler.cpp @@ -0,0 +1,107 @@ +#include "VP9RateControlHandler.hpp" +#include +extern "C" { +#include "../brc/vp9/libvpx_derived/libvpx_vp9_rtc.h" + +Libmebo_brc_VP9::Libmebo_brc_VP9(LibMeboBrcAlgorithmID algo_id) + : Libmebo_brc(LIBMEBO_CODEC_VP9, algo_id) { + enc_params_libmebo.num_sl = 1; + enc_params_libmebo.num_tl = 1; + enc_params_libmebo.bitrate = 288; // in kbps. + enc_params_libmebo.dynamic_rate_change = 0; + enc_params_libmebo.framecount = 100; + enc_params_libmebo.framerate = 60; + enc_params_libmebo.width = 320; + enc_params_libmebo.height = 160; + enc_params_libmebo.id = static_cast(LIBMEBO_CODEC_VP9); + enc_params_libmebo.preset = 0; + enc_params_libmebo.buf_optimal_sz = 600; +} + +LibMeboRateController * +Libmebo_brc_VP9::init(LibMeboRateController *libmebo_rc, + LibMeboRateControllerConfig *libmebo_rc_config) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!libmebo_rc || !libmebo_rc_config) + return nullptr; + libmebo_rc = Libmebo_brc::init(libmebo_rc, libmebo_rc_config); + status = brc_vp9_rate_control_init(libmebo_rc_config, &brc_codec_handler); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to Initialize the RateController\n"); + + return libmebo_rc; +} + +LibMeboStatus +Libmebo_brc_VP9::update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc || !rc_cfg) + return status; + + status = brc_vp9_update_rate_control(brc_codec_handler, rc_cfg); + + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to Update the RateController\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP9::post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp9_post_encode_update(brc_codec_handler, encoded_frame_size); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to do the post encode update \n"); + + return status; +} + +LibMeboStatus +Libmebo_brc_VP9::compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp9_compute_qp(brc_codec_handler, rc_frame_params); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to compute the QP\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP9::get_qp(LibMeboRateController *rc, int *qp) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp9_get_qp(brc_codec_handler, qp); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to get the QP\n"); + + return status; +} + +LibMeboStatus Libmebo_brc_VP9::get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) { + LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; + + if (!rc) + return status; + + status = brc_vp9_get_loop_filter_level(brc_codec_handler, filter_level); + if (status != LIBMEBO_STATUS_SUCCESS) + fprintf(stderr, "Failed to get the Loop filter level\n"); + + return status; +} +} // extern "C" \ No newline at end of file diff --git a/src/Handlers/VP9RateControlHandler.hpp b/src/Handlers/VP9RateControlHandler.hpp new file mode 100644 index 0000000..b5c9c40 --- /dev/null +++ b/src/Handlers/VP9RateControlHandler.hpp @@ -0,0 +1,27 @@ +#pragma once +extern "C" { +#include "../lib/libmebo.hpp" +} + +#include "LibMeboControlHandler.hpp" + +class Libmebo_brc_VP9 : public Libmebo_brc { +public: + Libmebo_brc_VP9(LibMeboBrcAlgorithmID algo_id); + virtual ~Libmebo_brc_VP9() override = default; + LibMeboRateController *init(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) override; + LibMeboStatus update_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) override; + LibMeboStatus post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) override; + LibMeboStatus compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) override; + LibMeboStatus get_qp(LibMeboRateController *rc, int *qp) override; + LibMeboStatus get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) override; + +private: + typedef void *BrcCodecEnginePtr; + BrcCodecEnginePtr brc_codec_handler; +}; \ No newline at end of file diff --git a/src/Handlers/meson.build b/src/Handlers/meson.build new file mode 100644 index 0000000..8651d20 --- /dev/null +++ b/src/Handlers/meson.build @@ -0,0 +1,43 @@ +libbrc_controller_sources = [] +libbrc_controller_headers = [] + +libbrc_controller_sources += [ + 'LibMeboControlHandler.cpp', + 'AV1RateControlHandler.cpp', + 'VP8RateControlHandler.cpp', + 'VP9RateControlHandler.cpp' +] + +libbrc_controller_headers +=[ + 'LibMeboControlHandler.hpp', + 'AV1RateControlHandler.hpp', + 'VP8RateControlHandler.hpp', + 'VP9RateControlHandler.hpp' +] + +c_compiler = meson.get_compiler('c') +cpp_compiler = meson.get_compiler('cpp') + + +dl_dep_c = c_compiler.find_library('dl', required:true) +dl_dep_cpp = cpp_compiler.find_library('dl', required:true) + +libbrc_find = c_compiler.find_library('libbrc', required:true) + +brc_controller = shared_library('brc_controller', + libbrc_controller_sources + libbrc_controller_headers, + c_args : libmebo_args, + include_directories: [configinc, libbrcinc], + link_args: '-ldl', + link_with: libbrc, + dependencies: [dl_dep_c, dl_dep_cpp], + install:true, + #include_directories: [configinc, libbrcinc, aom_av1_include_dir, aom_av1_include_build_dir], +) + + libbrc_controller_dep = declare_dependency (link_with: brc_controller, + include_directories: [configinc, libbrcinc], + #include_directories: [configinc, libbrcinc, aom_av1_include_dir , aom_av1_include_build_dir], + dependencies: [dl_dep_c, dl_dep_cpp, libbrc_find] + ) + \ No newline at end of file diff --git a/src/brc/av1/aom_derived/aom_av1_rtc.h b/src/brc/av1/aom_derived/aom_av1_rtc.h index 6692ec6..b3643e3 100644 --- a/src/brc/av1/aom_derived/aom_av1_rtc.h +++ b/src/brc/av1/aom_derived/aom_av1_rtc.h @@ -15,7 +15,7 @@ #define LIBMEBO_AV1_RATECTRL_RTC_H #include "aom_av1_common.h" -#include "../../../lib/libmebo.h" +#include "../../../lib/libmebo.hpp" // This interface allows using AV1 real-time rate control without initializing // the encoder. diff --git a/src/brc/meson.build b/src/brc/meson.build index 4d44623..f1feba8 100644 --- a/src/brc/meson.build +++ b/src/brc/meson.build @@ -55,6 +55,7 @@ libbrc = static_library('libbrc', libbrc_sources + libbrc_headers, c_args : libmebo_args, include_directories: [configinc, libbrcinc], + install:true ) libbrc_dep = declare_dependency (link_with: libbrc, diff --git a/src/brc/vp8/libvpx_derived/libvpx_vp8_rtc.h b/src/brc/vp8/libvpx_derived/libvpx_vp8_rtc.h index 9e634a9..bd57bb8 100644 --- a/src/brc/vp8/libvpx_derived/libvpx_vp8_rtc.h +++ b/src/brc/vp8/libvpx_derived/libvpx_vp8_rtc.h @@ -13,7 +13,7 @@ #define LIBMEBO_VP8_RATECTRL_RTC_H #include "libvpx_vp8_common.h" -#include "../../../lib/libmebo.h" +#include "../../../lib/libmebo.hpp" // This interface allows using VP8 real-time rate control without initializing // the encoder. diff --git a/src/brc/vp9/libvpx_derived/libvpx_vp9_rtc.h b/src/brc/vp9/libvpx_derived/libvpx_vp9_rtc.h index f42702d..bce111b 100644 --- a/src/brc/vp9/libvpx_derived/libvpx_vp9_rtc.h +++ b/src/brc/vp9/libvpx_derived/libvpx_vp9_rtc.h @@ -14,7 +14,7 @@ #define LIBMEBO_VP9_RATECTRL_RTC_H #include "libvpx_vp9_common.h" -#include "../../../lib/libmebo.h" +#include "../../../lib/libmebo.hpp" typedef struct _VP9FrameParamsQpRTC { FRAME_TYPE frame_type; diff --git a/src/lib/RateControlFactory.hpp b/src/lib/RateControlFactory.hpp new file mode 100644 index 0000000..424df95 --- /dev/null +++ b/src/lib/RateControlFactory.hpp @@ -0,0 +1,40 @@ +#pragma once +#include +#include "../src/Handlers/AV1RateControlHandler.hpp" +#include "../src/Handlers/LibMeboControlHandler.hpp" +#include "../src/Handlers/VP8RateControlHandler.hpp" +#include "../src/Handlers/VP9RateControlHandler.hpp" + +class Libmebo_brc_factory +{ + public: + static std::unique_ptr create(unsigned int id ) + { + LibMeboCodecType codecType; + switch(static_cast(id)) + { + case LIBMEBO_CODEC_VP8: + codecType = LIBMEBO_CODEC_VP8; + break; + case LIBMEBO_CODEC_VP9: + codecType = LIBMEBO_CODEC_VP9; + break; + case LIBMEBO_CODEC_AV1: + codecType = LIBMEBO_CODEC_AV1; + break; + } + + switch(codecType) + { + case LIBMEBO_CODEC_VP8: + return std::make_unique(static_cast(id));//this is calling construcotr. + case LIBMEBO_CODEC_VP9: + return std::make_unique(static_cast(id)); + case LIBMEBO_CODEC_AV1: + return std::make_unique(static_cast(id)); + case LIBMEBO_CODEC_UNKNOWN: + break; + } + + } +}; \ No newline at end of file diff --git a/src/lib/libmebo.c b/src/lib/libmebo.c deleted file mode 100644 index fa767ab..0000000 --- a/src/lib/libmebo.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation. All Rights Reserved. - * Copyright (c) 2020 Sreerenj Balachandran - * Author: Sreerenj Balachandran - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBMEBO_CONFIG_H -# include "libmebo_config.h" -#endif - -#include "libmebo.h" -#if LIBMEBO_ENABLE_VP9 -#include "brc/vp9/libvpx_derived/libvpx_vp9_rtc.h" -#endif -#if LIBMEBO_ENABLE_VP8 -#include "brc/vp8/libvpx_derived/libvpx_vp8_rtc.h" -#endif -#if LIBMEBO_ENABLE_AV1 -#include "brc/av1/aom_derived/aom_av1_rtc.h" -#endif - -#define GET_LAYER_INDEX(s_layer, t_layer, num_temporal_layers) \ - ((s_layer) * (num_temporal_layers) + (t_layer)) - -typedef LibMeboStatus (*libmebo_brc_init_fn)( - LibMeboRateControllerConfig *rc_config, BrcCodecEnginePtr *handler); - -typedef LibMeboStatus (*libmebo_brc_update_config_fn)( - BrcCodecEnginePtr handler, LibMeboRateControllerConfig *rc_config); - -typedef LibMeboStatus (*libmebo_brc_compute_qp_fn)( - BrcCodecEnginePtr handler, LibMeboRCFrameParams *rc_frame_params); - -typedef LibMeboStatus (*libmebo_brc_get_qp_fn)( - BrcCodecEnginePtr handler, int *qp); - -typedef LibMeboStatus (*libmebo_brc_get_loop_filter_fn)( - BrcCodecEnginePtr handler, int *lf); - -typedef LibMeboStatus (*libmebo_brc_post_encode_update_fn)( - BrcCodecEnginePtr handler, uint64_t encoded_frame_size); - -typedef void (*libmebo_brc_free_fn)( - BrcCodecEnginePtr handler); - -typedef struct LibMeboCodecInterface { - libmebo_brc_init_fn init; - libmebo_brc_update_config_fn update_config; - libmebo_brc_compute_qp_fn compute_qp; - libmebo_brc_get_qp_fn get_qp; - libmebo_brc_get_loop_filter_fn get_loop_filter; - libmebo_brc_post_encode_update_fn post_encode_update; - libmebo_brc_free_fn free; -} LibMeboCodecInterface; - -typedef struct { - LibMeboCodecInterface brc_interface; - BrcCodecEnginePtr brc_codec_handler; -} LibMeboRateControllerPrivate; - -typedef struct _brc_algo_map { - LibMeboCodecType codec_type; - LibMeboBrcAlgorithmID algo_id; - const char *description; - LibMeboCodecInterface algo_interface; -} brc_algo_map; - -static const brc_algo_map algo_impl_map[] = { - { - LIBMEBO_CODEC_VP8, - LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP8, - "VP8 BRC algorithm derived from libvpx", - { -#if LIBMEBO_ENABLE_VP8 - brc_vp8_rate_control_init, - brc_vp8_update_rate_control, - brc_vp8_compute_qp, - brc_vp8_get_qp, - brc_vp8_get_loop_filter_level, - brc_vp8_post_encode_update, - brc_vp8_rate_control_free, -#else - NULL, NULL, NULL, NULL, NULL, NULL, NULL, -#endif - }, - }, - { - LIBMEBO_CODEC_VP9, - LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP9, - "VP9 BRC algorithm derivded from libvpx", - { -#if LIBMEBO_ENABLE_VP9 - brc_vp9_rate_control_init, - brc_vp9_update_rate_control, - brc_vp9_compute_qp, - brc_vp9_get_qp, - brc_vp9_get_loop_filter_level, - brc_vp9_post_encode_update, - brc_vp9_rate_control_free, -#else - NULL, NULL, NULL, NULL, NULL, NULL, NULL, -#endif - }, - }, - { - LIBMEBO_CODEC_AV1, - LIBMEBO_BRC_ALGORITHM_DERIVED_AOM_AV1, - "AV1 BRC algorithm dervied from AOM", - { -#if LIBMEBO_ENABLE_AV1 - brc_av1_rate_control_init, - brc_av1_update_rate_control, - brc_av1_compute_qp, - brc_av1_get_qp, - brc_av1_get_loop_filter_level, - brc_av1_post_encode_update, - brc_av1_rate_control_free, -#else - NULL, NULL, NULL, NULL, NULL, NULL, NULL, -#endif - }, - }, - { - LIBMEBO_CODEC_UNKNOWN, - LIBMEBO_BRC_ALGORITHM_UNKNOWN, - "Unknown", - { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - }, -}; - -LibMeboBrcAlgorithmID -get_default_algorithm_id (LibMeboCodecType codec_type) -{ - switch (codec_type) { - case LIBMEBO_CODEC_VP8: - return LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP8; - case LIBMEBO_CODEC_VP9: - return LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP9; - case LIBMEBO_CODEC_AV1: - return LIBMEBO_BRC_ALGORITHM_DERIVED_AOM_AV1; - case LIBMEBO_CODEC_UNKNOWN: - return LIBMEBO_BRC_ALGORITHM_UNKNOWN; - default: - return LIBMEBO_BRC_ALGORITHM_UNKNOWN; - } - return LIBMEBO_BRC_ALGORITHM_UNKNOWN; -} - -const brc_algo_map * -get_backend_impl (LibMeboCodecType codec_type, - LibMeboBrcAlgorithmID algo_id) -{ - const brc_algo_map *bm = NULL; - - //Chose the default option - if (algo_id == LIBMEBO_BRC_ALGORITHM_DEFAULT) { - algo_id = get_default_algorithm_id (codec_type); - } - - for (bm = algo_impl_map; bm->codec_type != LIBMEBO_CODEC_UNKNOWN; bm++){ - if (bm->algo_id == algo_id) - return bm; - } - return NULL; -} - -/********************** API *************************/ - -/** - * \brief libmebo_rate_controller_get_loop_filter_level: - * - * Get the loop filter level for the current frame - * - * @param[in] rc LibMeboRateController to be initialized - * @param[out] lf Retruns proposed loop-filter level for the current frame - * - * \return Retruns LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_get_loop_filter_level(LibMeboRateController *rc, int *lf) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv; - - if (!rc) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.get_loop_filter (priv->brc_codec_handler, lf); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to get the Loop filter level\n"); - - return status; -} - -/** - * \brief libmebo_rate_controller_get_qp: - * - * Get the quantization parameter for the current frame - * - * @param[in] rc LibMeboRateController to be initialized - * @param[out] qp Retruns proposed qp for the current frame - * - * \return Retrun LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_get_qp(LibMeboRateController *rc, int *qp) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv; - - if (!rc) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.get_qp (priv->brc_codec_handler, qp); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to get the QP\n"); - - return status; -} - -/** - * \brief libmebo_rate_controller_compute_qp: - * - * Compute the quantization parameter for the current frame - * - * @param[in] rc LibMeboRateController to be initialized - * @param[in] rc_frame_params LibMeboRCFrameParams of current frame - * - * \return Retrun LibMeboStatus code - * - */ -LibMeboStatus -libmebo_rate_controller_compute_qp (LibMeboRateController *rc, - LibMeboRCFrameParams rc_frame_params) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv; - - if (!rc) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.compute_qp (priv->brc_codec_handler, &rc_frame_params); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to compute the QP\n"); - - return status; -} - -/** - * \brief libmebo_rate_controller_post_encode_update: - * - * Update the LibMeboRateConroller instance with - * the compressed sized of last encoded frame - * - * @param[in] rc LibMeboRateController to be initialized - * @param[in] encoded_frame_size Size of the last compressed frame - * - * \return Retrun LibMeboStatus code - * - */ -LibMeboStatus -libmebo_rate_controller_post_encode_update (LibMeboRateController *rc, - uint64_t encoded_frame_size) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv; - - if (!rc) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.post_encode_update (priv->brc_codec_handler, - encoded_frame_size); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to do the post encode update \n"); - - return status; -} - -/** - * \brief libmebo_rate_controller_update_config: - * - * Update the LibMeboRateConroller instance with - * brc params in LibMeboRateControllerConfig and returns - * LIBMEBO_STATUS_SUCCESS on success - * - * @param[in] rc LibMeboRateController to be initialized - * @param[in] rc_config LibMeboRateControllerConfig with brc params - * - * \return Retrun LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_update_config (LibMeboRateController *rc, - LibMeboRateControllerConfig* rc_config) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv; - - if (!rc || !rc_config) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.update_config (priv->brc_codec_handler, rc_config); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to Update the RateController\n"); - - return status; -} - -/** - * \brief libmebo_rate_controller_init: - * - * Initialize the LibMeboRateConroller instance with - * brc params in LibMeboRateControllerConfig and returns - * LIBMEBO_STATUS_SUCCESS on success - * - * @param[in] rc LibMeboRateController to be initialized - * @param[in] rc_config LibMeboRateControllerConfig with brc params - * - * \return Retrun LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_init (LibMeboRateController *rc, - LibMeboRateControllerConfig *rc_config) -{ - LibMeboStatus status = LIBMEBO_STATUS_UNKNOWN; - LibMeboRateControllerPrivate *priv;; - - if (!rc || !rc_config) - return status; - priv = (LibMeboRateControllerPrivate *)rc->priv; - - status = priv->brc_interface.init (rc_config, &priv->brc_codec_handler); - if (status != LIBMEBO_STATUS_SUCCESS) - fprintf(stderr, "Failed to Initialize the RateController\n"); - - //ToDo: Make it explicit to enforce the algorithm implementor to validate - //the input params - //brc_status = priv->brc_interface.validate (rc_config, &priv->brc_codec_handler); - - return status; -} - -/** - * \brief libmebo_rate_controller_free: - * - * Frees the @rc and set to NULL - * - * @param[in] rc LibMeboRateController to be freed. - * - */ -void -libmebo_rate_controller_free (LibMeboRateController *rc) -{ - if (!rc) - return; - - LibMeboRateControllerPrivate *priv = (LibMeboRateControllerPrivate *)rc->priv; - - priv->brc_interface.free (priv->brc_codec_handler); - free (rc->priv); - free (rc); - rc = NULL; -} - -/** - * \brief libmebo_rate_controller_new: - * - * Creates a new LibMeboRateController instance. - * It should be freed with libmebo_rate_controller_free() - * after the use. - * - * @param[in] codec_type LibMeboCodecType for video codec in use - * - * \return Retrun the newly created LibMeboRateController instance - */ -LibMeboRateController * -libmebo_rate_controller_new (LibMeboCodecType codec_type, - LibMeboBrcAlgorithmID algo_id) { - LibMeboRateController *rc; - LibMeboRateControllerPrivate *priv; - - const brc_algo_map *brc_backend = get_backend_impl (codec_type, algo_id); - if (brc_backend == NULL) { - fprintf (stderr, "Error: Unsupported Codec/Algorithm \n"); - return NULL; - } - - rc = (LibMeboRateController *) malloc (sizeof(LibMeboRateController)); - if (!rc) { - fprintf(stderr, "Failed allocation for LibMeboRateController \n"); - return NULL; - } - - priv = (LibMeboRateControllerPrivate *) malloc (sizeof (LibMeboRateControllerPrivate)); - if (!priv) { - fprintf(stderr, "Failed allocation for LibMeboRateController Private interface\n"); - if (rc) - free(rc); - return NULL; - } - priv->brc_interface = brc_backend->algo_interface; - - rc->priv = priv; - rc->codec_type = codec_type; - - return rc; -} diff --git a/src/lib/libmebo.cpp b/src/lib/libmebo.cpp new file mode 100644 index 0000000..348743f --- /dev/null +++ b/src/lib/libmebo.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Intel Corporation. All Rights Reserved. + * Copyright (c) 2020 Sreerenj Balachandran + * Author: Sreerenj Balachandran + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "libmebo.hpp" +#include "RateControlFactory.hpp" +#include +#include +#include "../src/Handlers/AV1RateControlHandler.hpp" +#include "../src/Handlers/LibMeboControlHandler.hpp" +#include "../src/Handlers/VP8RateControlHandler.hpp" +#include "../src/Handlers/VP9RateControlHandler.hpp" +typedef enum CodecID_ { + VP8_ID = 0, + VP9_ID = 1, + AV1_ID = 2, +} CodecID; + +LibMeboRateController * +libmebo_create_rate_controller(LibMeboCodecType CodecType, + LibMeboBrcAlgorithmID algo_id) { + std::unique_ptr brc = + Libmebo_brc_factory::create(static_cast(algo_id)); + if (!brc) + return nullptr; + LibMeboRateController *libmebo_rc = static_cast( + malloc(sizeof(LibMeboRateController))); + if (!libmebo_rc) { + return NULL; + } + + libmebo_rc->priv = brc.release(); + libmebo_rc->codec_type = static_cast(CodecType); // later change + return libmebo_rc; +} +void libmebo_release_rate_controller(LibMeboRateController *rc) { + if (rc) { + Libmebo_brc *brc = static_cast(rc->priv); + delete brc; + free(rc); + } +} + +LibMeboRateController * +libmebo_init_rate_controller(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return reinterpret_cast(brc->init(rc, rc_config)); +} + +LibMeboStatus +libmebo_update_rate_controller_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return static_cast(brc->update_config(rc, rc_cfg)); +} + +LibMeboStatus libmebo_post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return static_cast( + brc->post_encode_update(rc, encoded_frame_size)); +} + +LibMeboStatus libmebo_compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return static_cast(brc->compute_qp(rc, rc_frame_params)); +} + +LibMeboStatus libmebo_get_qp(LibMeboRateController *rc, int *qp) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return static_cast(brc->get_qp(rc, qp)); +} + +LibMeboStatus libmebo_get_loop_filter_level(LibMeboRateController *rc, + int *filter_level) { + Libmebo_brc *brc = reinterpret_cast(rc->priv); + return static_cast( + brc->get_loop_filter_level(rc, filter_level)); +} diff --git a/src/lib/libmebo.h b/src/lib/libmebo.hpp similarity index 75% rename from src/lib/libmebo.h rename to src/lib/libmebo.hpp index 5fbd3b9..45192d4 100644 --- a/src/lib/libmebo.h +++ b/src/lib/libmebo.hpp @@ -31,7 +31,8 @@ #include /** - * \mainpage Library for Media Encode Bitrate-control-algorithm Orchestration (LibMebo) + * \mainpage Library for Media Encode Bitrate-control-algorithm Orchestration + * (LibMebo) * * \section intro Introduction * LibMebo is an open-source library to orchestrate the bitrate @@ -57,7 +58,8 @@ * __InitializeConfig(rc_cfg); * * //Create an instance of libmebo - * rc = libmebo_rate_controller_new (LIBMEBO_CODEC_VP9, LIBMEBO_BRC_ALGORITHM_DEFAULT); + * rc = libmebo_rate_controller_new (LIBMEBO_CODEC_VP9, + * LIBMEBO_BRC_ALGORITHM_DEFAULT); * * //Initialize the libmebo instance with the rc_config * status = libmebo_rate_controller_init (rc, &rc_config); @@ -83,7 +85,7 @@ * * // Optional:libmebo can also recommend the loop-filter strength * status = libmebo_rate_controller_get_loop_filter_level (rc, &lf); - * + * * // Ensure the status == LIBMEBO_STATUS_SUCCESS before using * // the loop filter level since some algos are not supporting this API * @@ -95,14 +97,21 @@ * assert (status == LIBMEBO_STATUS_SUCCESS); * } * \endcode -*/ + */ + +// #include "../src/Handlers/LibMeboControlHandler.hpp" + #ifdef __cplusplus extern "C" { #endif -typedef void* BrcCodecEnginePtr; +#define LIBMEBO_ENABLE_AV1 1 +#define LIBMEBO_ENABLE_VP9 1 +#define LIBMEBO_ENABLE_VP8 1 -/** +typedef void *BrcCodecEnginePtr; + +/** * Codec Types */ typedef enum { @@ -115,8 +124,7 @@ typedef enum { /** * Backend algorithm IDs */ -typedef enum -{ +typedef enum { LIBMEBO_BRC_ALGORITHM_DEFAULT, LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP8, LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP9, @@ -139,15 +147,12 @@ typedef enum { LIBMEBO_STATUS_UNKNOWN, } LibMeboStatus; -/** +/** * Rate Control Modes */ -typedef enum { - LIBMEBO_RC_CBR, - LIBMEBO_RC_VBR -} LibMeboRateControlMode; +typedef enum { LIBMEBO_RC_CBR, LIBMEBO_RC_VBR } LibMeboRateControlMode; -/** +/** * Frame prediction types */ typedef enum { @@ -156,7 +161,7 @@ typedef enum { LIBMEBO_FRAME_TYPES, } LibMeboFrameType; -/** +/** * \biref Frame parameters * * This structure conveys frame level parameters and should be sent @@ -182,7 +187,7 @@ typedef struct _LibMeboRCFrameParams { */ #define LIBMEBO_SS_MAX_LAYERS 4 -/** +/** * Temporal + Spatial Scalability: Maximum number of coding layers * Not all codecs are supporting the LIBMEBO_MAX_LAYERS. The * libmebo_rate_controller_init() will perform the codec specific @@ -190,7 +195,7 @@ typedef struct _LibMeboRCFrameParams { */ #define LIBMEBO_MAX_LAYERS 32 -/** +/** * \biref LibMebo Rate Controller configuration structure * * This structure conveys the encoding parameters required @@ -306,7 +311,7 @@ typedef struct _LibMeboRateControllerConfig { * */ int max_intra_bitrate_pct; - + /*\brief Codec control attribute to set max data rate for Inter frames. * * This value controls additional clamping on the maximum size of an @@ -396,121 +401,33 @@ typedef struct _LibMeboRateController { uint32_t _libmebo_reserved[32]; } LibMeboRateController; -/******** API *************/ - -/** - * \brief libmebo_rate_controller_new: - * - * Creates a new LibMeboRateController instance. It should be freed with - * libmebo_rate_controller_free after use. - * - * \param[in] codec_type LibMeboCodecType of the codec - * \param[in] algo_id LibMeboBrcAlgorithmID of the backend implementation - * - * \returns Returns a pointer to LibMeboRateController, or NULL - * if fails to create the controller instance. - */ -LibMeboRateController * -libmebo_rate_controller_new (LibMeboCodecType codec_type, - LibMeboBrcAlgorithmID algo_id); - -/** - * \brief libmebo_rate_controller_init: - * - * Initialize the rate-controller instance with encode tuning - * parameters provided in LibMeboRateControllerConfig - * - * \param[in] rc LibMeboRateController to be initialized - * \param[in] rc_config LibMeboRateControllerConfig with pre-filled enc params - * - * \returns Returns a LibMeboStatus - */ -LibMeboStatus -libmebo_rate_controller_init (LibMeboRateController *rc, - LibMeboRateControllerConfig *rc_config); -/** - * libmebo_rate_controller_free - * - * \param[in] rc the LibMeboRateController to free - * - * Frees #rc and sets it to NULL - */ -void libmebo_rate_controller_free (LibMeboRateController *rc); -/** - * \brief libmebo_rate_controller_update_config: - * - * Update the rate-controller instance with encode tuning - * parameters provided in LibMeboRateControllerConfig - * - * \param[in] rc LibMeboRateController to be updated - * \param[in] rc_config LibMeboRateControllerConfig with pre-filled enc params - * - * \returns Returns a LibMeboStatus - */ -LibMeboStatus -libmebo_rate_controller_update_config (LibMeboRateController *rc, - LibMeboRateControllerConfig*rc_cfg); +/*these below API are exported using extern "C" to cleint side*/ +LibMeboRateController * +libmebo_create_rate_controller(LibMeboCodecType CodecType, + LibMeboBrcAlgorithmID algo_id); +void libmebo_release_rate_controller(LibMeboRateController *rc); -/** - * libmebo_rate_controller_post_encode_update: - * - * This is a post-encode operation. - * Update the currently encoded frame's size at #rc instance. - * - * \param[in] rc The LibMeboRateController to update framesize - * \param[in] encoded_frame_size Size of the compressed frame - * - * \returns Returns a LibMeboStatus - */ -LibMeboStatus -libmebo_rate_controller_post_encode_update (LibMeboRateController *rc, - uint64_t encoded_frame_size); +LibMeboRateController * +libmebo_init_rate_controller(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_config); -/** - * libmebo_rate_controller_compute_qp: - * - * Instruct the libmebo api to calculate the QP. - * At this point libmebo start executing the qp calculation algorithm. - * - * \param[in] rc the LibMeboRateController - * \param[in] rc_frame_params current frame params - * - * \returns Returns a LibMeboStatus - * - */ LibMeboStatus -libmebo_rate_controller_compute_qp (LibMeboRateController *rc, - LibMeboRCFrameParams rc_frame_params); +libmebo_update_rate_controller_config(LibMeboRateController *rc, + LibMeboRateControllerConfig *rc_cfg); +LibMeboStatus libmebo_post_encode_update(LibMeboRateController *rc, + uint64_t encoded_frame_size); +LibMeboStatus libmebo_compute_qp(LibMeboRateController *rc, + LibMeboRCFrameParams *rc_frame_params); -/** - * libmebo_rate_controller_get_qp: - * - * Retrieve the current qp estimate from libmebo instance - * - * \param[in] rc the LibMeboRateController instance - * \param[out] qp Retruns proposed qp for the current frame - * - * \returns LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_get_qp(LibMeboRateController *rc, int *qp); +LibMeboStatus libmebo_get_qp(LibMeboRateController *rc, int *qp); -/** - * libmebo_rate_controller_get_loop_filter_level: - * - * Retrieve the current loop filter strength estimate - * from libmebo instance - * - * \param[in] rc The LibMeboRateController instance - * \param[out] lf Retruns proposed loop-filter level for the current frame - * - * \return Retruns LibMeboStatus code - */ -LibMeboStatus -libmebo_rate_controller_get_loop_filter_level(LibMeboRateController *rc, int *lf); +LibMeboStatus libmebo_get_loop_filter_level(LibMeboRateController *rc, + int *filter_level); +void *create_brc_factory(unsigned int id); +void destroy_brc_factory(void *brc); #ifdef __cplusplus } #endif diff --git a/src/lib/meson.build b/src/lib/meson.build index 53a991f..5692f58 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -1,18 +1,18 @@ libmebo_sources = [ - 'libmebo.c', + 'libmebo.cpp', ] libmebo_headers = [ - 'libmebo.h', + 'libmebo.hpp', ] -install_headers ('libmebo.h', subdir : 'libmebo') +install_headers ('libmebo.hpp', subdir : 'libmebo') libmebo = shared_library('mebo', libmebo_sources, c_args : libmebo_args, include_directories: [configinc, libbrcinc], - dependencies: [libbrc_dep], + dependencies: [libbrc_dep , libbrc_controller_dep], version : libmebo_soname_version, soversion : libmebo_version_major, install : true, @@ -20,7 +20,7 @@ libmebo = shared_library('mebo', libmebo_dep_internal = declare_dependency(link_with: libmebo, include_directories : [configinc, libbrcinc], - dependencies : [libbrc_dep]) + dependencies : [libbrc_dep, libbrc_controller_dep]) pkgconfig.generate( name : 'libmebo', diff --git a/src/meson.build b/src/meson.build index 5b42980..ce5bb67 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,2 +1,3 @@ subdir ('brc') +subdir ('Handlers') subdir ('lib') diff --git a/test/fake-enc-test.c b/test/fake-enc-test.c deleted file mode 100644 index 45140ed..0000000 --- a/test/fake-enc-test.c +++ /dev/null @@ -1,727 +0,0 @@ -/* Copyright (c) 2020 Intel Corporation. All Rights Reserved. - * Copyright (c) 2020 Sreerenj Balachandran - * Author: Sreerenj Balachandran - * - * sample command: - ./fake-enc --codec=VP9 --preset=0 --framecount=120 -*/ - -#include -#include -#include -#include -#include -#include -#include - -#define MaxSpatialLayers 3 -#define MaxTemporalLayers 3 - -static LibMeboRateController *libmebo_rc; -static LibMeboRateControllerConfig libmebo_rc_config; - -typedef enum CodecID -{ - VP8_ID = 0, - VP9_ID = 1, - AV1_ID = 2, -} CodecID; - -struct EncParams { - unsigned int preset; - unsigned int id; - unsigned int bitrate; //in kbps - unsigned int framerate; - unsigned int width; - unsigned int height; - unsigned int framecount; //Number of Frames to be encoded - unsigned int num_sl; //Number of Spatial Layers - unsigned int num_tl; //Number of Temporal Layers - unsigned int dynamic_rate_change; //dynamic rate change enablement flag -}; - -struct BitrateBounds { - unsigned int lower; //in kbps - unsigned int upper; //in kbps -}; - -struct SvcBitrateBounds { - int layer_bitrate_lower[MaxSpatialLayers][MaxTemporalLayers]; - int layer_bitrate_upper[MaxSpatialLayers][MaxTemporalLayers]; -}; - -//Default config -static struct EncParams enc_params = -{ - .preset = 0, - .id = VP9_ID, - .bitrate = 1024, - .framerate = 30, - .width = 320, - .height = 240, - .framecount = 100, - .num_sl = 1, - .num_tl = 1, - .dynamic_rate_change = 0, - }; - -static struct EncParams preset_list [] = { - {0, 1, 256, 30, 320, 240, 100, 1, 1, 0}, - {1, 1, 512, 30, 320, 240, 100, 1, 1, 0}, - {2, 1, 1024, 30, 320, 240, 100, 1, 1, 0}, - {3, 1, 256, 30, 640, 480, 100, 1, 1, 0}, - {4, 1, 512, 30, 640, 480, 100, 1, 1, 0}, - {5, 1, 1024, 30, 640, 480, 100, 1, 1, 0}, - {6, 1, 1024, 30, 1280, 720, 100, 1, 1, 0}, - {7, 1, 2048, 30, 1280, 720, 100, 1, 1, 0}, - {8, 1, 4096, 30, 1280, 720, 100, 1, 1, 0}, - {9, 1, 1024, 30, 1920, 1080, 100, 1, 1, 0}, - {10, 1, 4096, 30, 1920, 1080, 100, 1, 1, 0}, - {11, 1, 8192, 30, 1920, 1080, 100,1, 1, 0}, - {12, 1, 8192, 30, 1920, 1080, 100,1, 1, 1}, - {13, 1, 4096, 30, 1280, 720, 100, 3, 2, 0}, -}; - -//heuristics to predict a decent key/intra-frame size -static struct BitrateBounds bitrate_bounds_intra [] = { - {3500, 4440}, {3700, 5600}, {5500,9500}, //qvga-intra-frames - {4100, 7400}, {3700, 11150}, {10100,16100}, //vga-intra-frames - {16000, 25600}, {27600,35800}, {30100,63100}, //hd-intra-frames - {14400,30000}, {60000,75100}, {65400,126600}, //full_hd-intra-frames - {65400,126600}, //full_hd-intra-frames -}; - -//heuristics to predict a decent inter-frame size -static struct BitrateBounds bitrate_bounds_inter [] = { - {800, 1170}, {1700, 2200}, {3000, 5000}, //qvga-inter-frames - {900, 1200}, {1800, 2200}, {3600, 4500}, //vga-inter-frames - {3000, 4500}, {7100, 8400}, {14700,17500}, //hd-inter-frames - {3100,8500}, {14100,16500}, {30000,35600}, //full_hd-inter-frames - {30000,35600}, //full_hd-inter-frames -}; - -//heuristics to predict a decent key/intra-frame size for SVC -static struct SvcBitrateBounds svc_bitrate_bounds_intra [] = { - { - .layer_bitrate_lower = { - {5957, 5957, 0}, - {8007, 8007, 0}, - {17520, 17520, 0}, - }, - .layer_bitrate_upper = { - {9884, 9884, 0}, - {17241, 17241, 0}, - {19084, 19084, 0}, - } - }, -}; - -//heuristics to predict a decent inter-frame size for SVC -static struct SvcBitrateBounds svc_bitrate_bounds_inter [] = { - { - .layer_bitrate_lower = { - {4520, 4520, 0}, - {4876, 4876, 0}, - {4327, 4327, 0}, - }, - .layer_bitrate_upper = { - {5700, 5700, 0}, - {5670, 5670, 0}, - {5689, 5689, 0}, - } - }, -}; - -int layered_bitrates[MaxSpatialLayers][MaxTemporalLayers]; -int layered_frame_rate[MaxTemporalLayers]; -int layered_stream_size[MaxSpatialLayers][MaxTemporalLayers]; -int layered_frame_count[MaxSpatialLayers][MaxTemporalLayers]; - -#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl)) - -unsigned int dynamic_size[2] = {0, 0}; -unsigned int dynamic_bitrates[2] = {0, 0}; - -static int verbose = 0; - -static char* -get_codec_id_string (CodecID id) -{ - switch (id) { - case VP8_ID: - return "VP8"; - case VP9_ID: - return "VP9"; - case AV1_ID: - return "AV1"; - default: - return "Unknown"; - } -} - -static void show_help() -{ - printf("Usage: \n" - " fake-enc [--codec=VP8|VP9|AV1] [--framecount=frame count] " - "[--preset= 0 to 13] \n\n" - " Preset0: QVGA_256kbps_30fps \n" - " Preset1: QVGA_512kbps_30fps \n" - " Preset2: QVGA_1024kbps_30fps \n" - " Preset3: VGA_256kbps_30fps \n" - " Preset4: VGA_512kbps_30fps \n" - " Preset5: VGA_1024kbps_30fps \n" - " Preset6: HD_1024kbps_30fps \n" - " Preset7: HD_2048kbps_30fps \n" - " Preset8: HD_4096kbps_30fps \n" - " Preset9: FULLHD_1024kbps_30fps \n" - " Preset10: FULLHD_4096kbps_30fps \n" - " Preset11: FULLHD_8192kbps_30fps \n" - //Please add any non-SVC, non-dynamirc-rate-change - // presets here and increment the SVC_PRESET_START_INDEX - // and DYNAMIC_RATE_CHAGE_PRESET_START_INDEX - " Preset12: FULLHD_8192kbps_30fps_DynamicRateChange \n" - //Please add any non-SVC presets here and - //increment the SVC_PRESET_START_INDEX - " Preset13: SVC_HD_4096kbps_30fps_S3T2 \n" - "\n"); -} - -#define DYNAMIC_RATE_CHAGE_PRESET_START_INDEX 12 -#define SVC_PRESET_START_INDEX 13 - -static void -parse_args(int argc, char **argv) -{ - int c,option_index; - - static const struct option long_options[] = { - {"help", no_argument, 0, 0}, - {"codec", required_argument, 0, 1}, - {"preset", required_argument, 0, 2}, - {"framecount", required_argument, 0, 3}, - {"temporal-layers", required_argument, 0, 4}, - {"spatial-layers", required_argument, 0, 5}, - {"dynamic-rate-change", required_argument, 0, 6}, - {"verbose", required_argument, 0, 7}, - { NULL, 0, NULL, 0 } - }; - - while (1) { - c = getopt_long_only (argc, argv, - "hcb:?", - long_options, - &option_index); - if (c == -1) - break; - - switch(c) { - case 1: - if (!strcmp (optarg, "VP8")) - enc_params.id = VP8_ID; - else if (!strcmp (optarg, "VP9")) - enc_params.id = VP9_ID; - else - enc_params.id = AV1_ID; - break; - case 2: { - int preset = atoi(optarg); - CodecID id = enc_params.id; - if (preset < 0 || preset > SVC_PRESET_START_INDEX) { - printf ("Unknown preset, Failed \n"); - exit(0); - } - enc_params = preset_list[preset]; - enc_params.id = id; - } - break; - case 3: - enc_params.framecount = atoi(optarg); - break; - case 7: - verbose = atoi(optarg); - break; - default: - break; - } - } -} - -// The return value is expressed as a percentage of the average. For example, -// to allocate no more than 4.5 frames worth of bitrate to a keyframe, the -// return value is 450. -uint32_t MaxSizeOfKeyframeAsPercentage(uint32_t optimal_buffer_size, - uint32_t max_framerate) { - // Set max to the optimal buffer level (normalized by target BR), - // and scaled by a scale_par. - // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. - // This value is presented in percentage of perFrameBw: - // perFrameBw = targetBR[Kbps] * 1000 / framerate. - // The target in % is as follows: - const double target_size_byte_per_frame = optimal_buffer_size * 0.5; - const uint32_t target_size_kbyte = - target_size_byte_per_frame * max_framerate / 1000; - const uint32_t target_size_kbyte_as_percent = target_size_kbyte * 100; - - // Don't go below 3 times the per frame bandwidth. - const uint32_t kMinIntraSizePercentage = 300u; - if (kMinIntraSizePercentage > target_size_kbyte_as_percent) - return kMinIntraSizePercentage; - else - return target_size_kbyte_as_percent; -} - -static void -InitLayeredBitrateAlloc (int num_sl, - int num_tl, int bitrate) -{ - int sl, tl; - - assert (num_sl && num_sl <= MaxSpatialLayers); - assert (num_tl && num_tl <= MaxTemporalLayers); - - for (sl=0; slwidth = enc_params.width; - rc_config->height = enc_params.height; - rc_config->max_quantizer = 63; - rc_config->min_quantizer = 0; - rc_config->target_bandwidth = enc_params.bitrate; - rc_config->buf_initial_sz = 500; - rc_config->buf_optimal_sz = 600;; - rc_config->buf_sz = 1000; - rc_config->undershoot_pct = 50; - rc_config->overshoot_pct = 50; - rc_config->buf_initial_sz = 500; - rc_config->buf_optimal_sz = 600;; - rc_config->buf_sz = 1000; - rc_config->undershoot_pct = 50; - rc_config->overshoot_pct = 50; - //Fixme - rc_config->max_intra_bitrate_pct = MaxSizeOfKeyframeAsPercentage( - rc_config->buf_optimal_sz, enc_params.framerate); - rc_config->max_intra_bitrate_pct = 0; - rc_config->framerate = enc_params.framerate; - - rc_config->max_quantizers[0] = rc_config->max_quantizer; - rc_config->min_quantizers[0] = rc_config->min_quantizer; - - rc_config->ss_number_layers = enc_params.num_sl; - rc_config->ts_number_layers = enc_params.num_tl; - - switch (enc_params.num_sl) { - case 1: - rc_config->scaling_factor_num[0] = 1; - rc_config->scaling_factor_den[0] = 1; - break; - case 2: - rc_config->scaling_factor_num[0] = 1; - rc_config->scaling_factor_den[0] = 2; - rc_config->scaling_factor_num[1] = 1; - rc_config->scaling_factor_den[1] = 1; - break; - case 3: - rc_config->scaling_factor_num[0] = 1; - rc_config->scaling_factor_den[0] = 4; - rc_config->scaling_factor_num[1] = 1; - rc_config->scaling_factor_den[1] = 2; - rc_config->scaling_factor_num[2] = 1; - rc_config->scaling_factor_den[2] = 1; - break; - default: - break; - } - for (unsigned int sl = 0; sl < enc_params.num_sl; sl++) { - int bitrate_sum = 0; - for (unsigned int tl = 0; tl < enc_params.num_tl; tl++) { - const int layer_id = LAYER_IDS_TO_IDX(sl, tl, enc_params.num_tl); - rc_config->max_quantizers[layer_id] = rc_config->max_quantizer; - rc_config->min_quantizers[layer_id] = rc_config->min_quantizer; - bitrate_sum += GetBitratekBps(sl, tl); - rc_config->layer_target_bitrate[layer_id] = bitrate_sum; - rc_config->ts_rate_decimator[tl] = 1u << (enc_params.num_tl - tl - 1); - } - InitLayeredFramerate (enc_params.num_tl,enc_params.framerate, - rc_config->ts_rate_decimator); - } - - status = libmebo_rate_controller_init (rc, rc_config); - if (status != LIBMEBO_STATUS_SUCCESS) - return 0; - - return 1; -} - -static void display_encode_status (unsigned int bitstream_size) { - - printf ("======= Encoder Input Configuration ======= \n"); - printf ( "Codec = %s \n" - "bitrate = %d kbps \n" - "framerate = %d \n" - "width = %d \n" - "height = %d \n" - "framecount = %d \n", - get_codec_id_string (enc_params.id), - enc_params.bitrate, - enc_params.framerate, - enc_params.width, - enc_params.height, - enc_params.framecount); - if (enc_params.num_sl > 1 || enc_params.num_tl > 1) { - printf ( "Target bitrates in kbps:\n"); - for (unsigned int sl = 0; sl 1 || enc_params.num_tl > 1) { - int total_bitrate = 0; - for (unsigned int sl = 0; sl < enc_params.num_sl; sl++) { - for (unsigned int tl = 0; tl < enc_params.num_tl; tl++) { - int bitrate = 0; - bitrate = (((layered_stream_size [sl][tl] / layered_frame_count[sl][tl]) * - layered_frame_rate[tl]) * 8) / 1000; - total_bitrate += bitrate; - printf ("SpatialLayer[%d]TemporlLayer[%d]: \n" - " Bitrate (with out including any other layers) = %d kbps \n" - " Bitrate (accumulated the lower layer targets) = %d kbps \n", - sl, tl, bitrate, total_bitrate); - } - } - } - - //Dynamic Rate Chaange - if (enc_params.dynamic_rate_change) { - int frames_count = enc_params.framecount/2; - printf ("Bitrate used for the streams with %d target bitrate = %d kbps\n\n", - dynamic_bitrates[0], - (((dynamic_size[0] / frames_count) * - enc_params.framerate) * 8 ) / 1000); - printf ("Bitrate used for the streams with %d target bitrate = %d kbps\n\n", - dynamic_bitrates[1], - (((dynamic_size[1] / frames_count) * - enc_params.framerate) * 8 ) / 1000); - } - printf ("Bitrate of the Compressed stream = %d kbps\n\n", - (((bitstream_size / enc_params.framecount) * - enc_params.framerate) * 8 ) / 1000); - printf ("\n"); -} - -static int _prev_temporal_id = 0; - -static void -get_layer_ids (int frame_count, int num_sl, int num_tl, - int *spatial_id, int *temporal_id) -{ - int s_id =0, t_id = 0; - - //spatial id - s_id = frame_count % num_sl; - - //Increment the temporal_id only when all the spatial - //variants are encoded for a particualr frame id - if (!(frame_count % num_sl)) { - //temporal id - if (num_tl > 1) { - switch (num_tl) { - case 2: - if (frame_count % 2 == 0) - t_id = 0; - else - t_id = 1; - break; - case 3: - if (frame_count % 4 == 0) - t_id = 0; - else if (frame_count % 2 == 0) - t_id = 1; - else - t_id = 2; - break; - default: - printf ("Exit: Not supporting more than 3 temporal layers \n"); - exit(0); - } - } else { - t_id = 0; - } - } else { - t_id = _prev_temporal_id; - } - - *spatial_id = s_id; - *temporal_id = t_id; - _prev_temporal_id = t_id; -} - -static void -start_virtual_encode (LibMeboRateController *rc) -{ - int i, qp = 0; - int key_frame_period = 30; - uint32_t buf_size = 1024; - uint32_t total_size = 0; - int prev_qp = 0; - uint32_t predicted_size = 0; - uint32_t lower =0, upper=0; - LibMeboFrameType libmebo_frame_type; - LibMeboRCFrameParams rc_frame_params; - unsigned int preset = enc_params.preset; - unsigned int svc_preset = 0; - int frame_count = 0; - unsigned int prev_is_key = 0; - - if (verbose) - printf ("=======Fake Encode starts ==============\n"); - - if (enc_params.num_sl > 1 || enc_params.num_tl >1) - svc_preset = preset - SVC_PRESET_START_INDEX; - - key_frame_period *= enc_params.num_sl; - - //Account spatial svc in frame_count - frame_count = enc_params.framecount * enc_params.num_sl; - - srand(time(NULL)); - for (i = 0; i < frame_count; i++) { - LibMeboStatus status; - int spatial_id; - int temporal_id; - int update_rate = 0; - unsigned int *dyn_size; - predicted_size = 0; - lower =0; - upper=0; - - get_layer_ids (i, - enc_params.num_sl, enc_params.num_tl, - &spatial_id, &temporal_id); - - //Dynamic rate reset: Reduce the framerate by 1/8 th - if (enc_params.dynamic_rate_change && - i >= frame_count/2){ - preset = 9;//bitrate change from 4096 to 1024 - dyn_size = &dynamic_size[1]; - update_rate = (i == frame_count/2) ? 1 : 0; - } else { - dyn_size = &dynamic_size[0]; - } - - if (i % key_frame_period == 0) { - libmebo_frame_type = LIBMEBO_KEY_FRAME; - if (preset < SVC_PRESET_START_INDEX) { - lower = bitrate_bounds_intra [preset].lower; - upper = bitrate_bounds_intra [preset].upper; - } else { - //SVC - lower = - svc_bitrate_bounds_intra[svc_preset]. - layer_bitrate_lower[spatial_id][temporal_id]; - upper = - svc_bitrate_bounds_intra[svc_preset]. - layer_bitrate_upper[spatial_id][temporal_id]; - } - } - else { - libmebo_frame_type = LIBMEBO_INTER_FRAME; - if (preset < SVC_PRESET_START_INDEX) { - lower = bitrate_bounds_inter [preset].lower; - upper = bitrate_bounds_inter [preset].upper; - } else { - //SVC - lower = - svc_bitrate_bounds_inter[svc_preset]. - layer_bitrate_lower[spatial_id][temporal_id]; - upper = - svc_bitrate_bounds_inter[svc_preset]. - layer_bitrate_upper[spatial_id][temporal_id]; - } - } - predicted_size = (rand() % (upper - lower)) + lower; - - //Update libmebo rate control config - if (update_rate) { - dynamic_bitrates[0] = libmebo_rc_config.target_bandwidth; - libmebo_rc_config.target_bandwidth /= 8; - dynamic_bitrates[1] = libmebo_rc_config.target_bandwidth; - status = libmebo_rate_controller_update_config (rc, &libmebo_rc_config); - assert (status == LIBMEBO_STATUS_SUCCESS); - } - - rc_frame_params.frame_type = libmebo_frame_type; - - //Set spatial layer id - rc_frame_params.spatial_layer_id = spatial_id; - rc_frame_params.temporal_layer_id = temporal_id; - - status = libmebo_rate_controller_compute_qp (rc, rc_frame_params); - assert (status == LIBMEBO_STATUS_SUCCESS); - - status = libmebo_rate_controller_get_qp (libmebo_rc, &qp); - assert (status == LIBMEBO_STATUS_SUCCESS); - - if (verbose) - printf ("QP = %d \n", qp); - - buf_size = predicted_size; - - //Heuristics to calculate a reasonable value of the - //compressed frame size - if (i != 0 && !prev_is_key) { - int qp_val = (qp == 0) ? 1 : qp; - int size_range = upper - lower; - int qp_range_length = size_range / 256; - int suggested_size = lower + (qp_val * qp_range_length); - int new_predicted_size = 0; - - if ((qp) < prev_qp) - new_predicted_size = (rand() % (upper - suggested_size)) + suggested_size; - else - new_predicted_size = (rand() % (suggested_size - lower)) + lower; - - buf_size = new_predicted_size; - } - - prev_qp = qp; - - if (verbose) - printf ("PostEncodeBufferSize = %d \n",buf_size); - - status = libmebo_rate_controller_post_encode_update (rc, buf_size); - assert (status == LIBMEBO_STATUS_SUCCESS); - - // Calculate per layer stream size - if (enc_params.num_tl > 1 || enc_params.num_sl > 1) { - layered_stream_size[spatial_id][temporal_id] += - buf_size; - layered_frame_count[spatial_id][temporal_id] += 1; - if (verbose) { - printf ("PostEncodeBufferSize of " - "spatial_layer[%d],temporal_layer[%d] = %d \n", - 0, rc_frame_params.temporal_layer_id, - buf_size); - } - } - total_size = total_size + buf_size; - *dyn_size += buf_size; - - prev_is_key = !(i % key_frame_period); - - } - - if (verbose) - printf ("=======Encode Finished==============\n"); - - display_encode_status (total_size); -} - -static void -ValidateInput () -{ - if (enc_params.num_sl > 3) { - printf ("Fixme: fake-enc only supports upto 3 spatail layers, exiting\n"); - exit (0); - } - if (enc_params.num_tl > 3) { - printf ("Fixme: fake-enc only supports upto 3 temporal layers, exiting\n"); - exit (0); - } -} - -void -get_codec_and_algo_id (CodecID id, int *codec_id, int *algo_id) -{ - switch (id) - { - case VP8_ID: - *codec_id = LIBMEBO_CODEC_VP8; - *algo_id = LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP8; - break; - case VP9_ID: - *codec_id = LIBMEBO_CODEC_VP9; - *algo_id = LIBMEBO_BRC_ALGORITHM_DERIVED_LIBVPX_VP9; - break; - case AV1_ID: - *codec_id = LIBMEBO_CODEC_VP8; - *algo_id = LIBMEBO_BRC_ALGORITHM_DERIVED_AOM_AV1; - break; - default: - *codec_id = LIBMEBO_CODEC_UNKNOWN; - *algo_id = LIBMEBO_BRC_ALGORITHM_UNKNOWN; - } -} - -int main (int argc,char **argv) -{ - int codec_type, algo_id; - if (argc < 3) { - show_help(); - return -1; - } - parse_args(argc, (char **)argv); - - ValidateInput (); - - //Init layered bitrate allocation estimation - InitLayeredBitrateAlloc (enc_params.num_sl, enc_params.num_tl, enc_params.bitrate); - - //Create the rate-controller - get_codec_and_algo_id (enc_params.id, &codec_type, &algo_id); - - libmebo_rc = libmebo_rate_controller_new (codec_type, algo_id); - if (!libmebo_rc) { - printf ("Failed to create the rate-controller \n"); - return -1; - } - - if (!libmebo_software_brc_init (libmebo_rc, &libmebo_rc_config)) { - printf ("Failed to init brc: \n"); - return -1; - } - - start_virtual_encode (libmebo_rc); - - libmebo_rate_controller_free (libmebo_rc); - - return 0; -} diff --git a/test/fake-enc-test.cpp b/test/fake-enc-test.cpp new file mode 100644 index 0000000..9870238 --- /dev/null +++ b/test/fake-enc-test.cpp @@ -0,0 +1,602 @@ + /* Copyright (c) 2020 Intel Corporation. All Rights Reserved. + * Copyright (c) 2020 Sreerenj Balachandran + * Author: Sreerenj Balachandran + * + * sample command: + ./fake-enc --codec=VP9 --preset=0 --framecount=120 + */ + + #include + #include + #include + #include + #include "../src/lib/libmebo.hpp" + #include + #include + #include + #include + + + #include "../src/Handlers/AV1RateControlHandler.hpp" + #include "../src/Handlers/LibMeboControlHandler.hpp" + #include "../src/Handlers/VP8RateControlHandler.hpp" + #include "../src/Handlers/VP9RateControlHandler.hpp" + + #define MaxSpatialLayers 3 + #define MaxTemporalLayers 3 + + static LibMeboRateController *libmebo_rc; + LibMeboRateControllerConfig libmebo_rc_config; + + typedef enum CodecID + { + VP8_ID = 0, + VP9_ID = 1, + AV1_ID = 2, + } CodecID; + + struct EncParams { + unsigned int preset; + unsigned int id; + unsigned int bitrate; //in kbps + unsigned int framerate; + unsigned int width; + unsigned int height; + unsigned int framecount; //Number of Frames to be encoded + unsigned int num_sl; //Number of Spatial Layers + unsigned int num_tl; //Number of Temporal Layers + unsigned int dynamic_rate_change; //dynamic rate change enablement flag + }; + + struct BitrateBounds { + unsigned int lower; //in kbps + unsigned int upper; //in kbps + }; + + struct SvcBitrateBounds { + int layer_bitrate_lower[MaxSpatialLayers][MaxTemporalLayers]; + int layer_bitrate_upper[MaxSpatialLayers][MaxTemporalLayers]; + }; + + //Default config + static struct EncParams enc_params = + { + .preset = 0, + .id = VP9_ID, + .bitrate = 1024, + .framerate = 30, + .width = 320, + .height = 240, + .framecount = 100, + .num_sl = 1, + .num_tl = 1, + .dynamic_rate_change = 0, + }; + + static struct EncParams preset_list [] = { + {0, 1, 256, 30, 320, 240, 100, 1, 1, 0}, + {1, 1, 512, 30, 320, 240, 100, 1, 1, 0}, + {2, 1, 1024, 30, 320, 240, 100, 1, 1, 0}, + {3, 1, 256, 30, 640, 480, 100, 1, 1, 0}, + {4, 1, 512, 30, 640, 480, 100, 1, 1, 0}, + {5, 1, 1024, 30, 640, 480, 100, 1, 1, 0}, + {6, 1, 1024, 30, 1280, 720, 100, 1, 1, 0}, + {7, 1, 2048, 30, 1280, 720, 100, 1, 1, 0}, + {8, 1, 4096, 30, 1280, 720, 100, 1, 1, 0}, + {9, 1, 1024, 30, 1920, 1080, 100, 1, 1, 0}, + {10, 1, 4096, 30, 1920, 1080, 100, 1, 1, 0}, + {11, 1, 8192, 30, 1920, 1080, 100,1, 1, 0}, + {12, 1, 8192, 30, 1920, 1080, 100,1, 1, 1}, + {13, 1, 4096, 30, 1280, 720, 100, 3, 2, 0}, + }; + + //heuristics to predict a decent key/intra-frame size + static struct BitrateBounds bitrate_bounds_intra [] = { + {3500, 4440}, {3700, 5600}, {5500,9500}, //qvga-intra-frames + {4100, 7400}, {3700, 11150}, {10100,16100}, //vga-intra-frames + {16000, 25600}, {27600,35800}, {30100,63100}, //hd-intra-frames + {14400,30000}, {60000,75100}, {65400,126600}, //full_hd-intra-frames + {65400,126600}, //full_hd-intra-frames + }; + + //heuristics to predict a decent inter-frame size + static struct BitrateBounds bitrate_bounds_inter [] = { + {800, 1170}, {1700, 2200}, {3000, 5000}, //qvga-inter-frames + {900, 1200}, {1800, 2200}, {3600, 4500}, //vga-inter-frames + {3000, 4500}, {7100, 8400}, {14700,17500}, //hd-inter-frames + {3100,8500}, {14100,16500}, {30000,35600}, //full_hd-inter-frames + {30000,35600}, //full_hd-inter-frames + }; + + //heuristics to predict a decent key/intra-frame size for SVC + static struct SvcBitrateBounds svc_bitrate_bounds_intra [] = { + { + .layer_bitrate_lower = { + {5957, 5957, 0}, + {8007, 8007, 0}, + {17520, 17520, 0}, + }, + .layer_bitrate_upper = { + {9884, 9884, 0}, + {17241, 17241, 0}, + {19084, 19084, 0}, + } + }, + }; + + //heuristics to predict a decent inter-frame size for SVC + static struct SvcBitrateBounds svc_bitrate_bounds_inter [] = { + { + .layer_bitrate_lower = { + {4520, 4520, 0}, + {4876, 4876, 0}, + {4327, 4327, 0}, + }, + .layer_bitrate_upper = { + {5700, 5700, 0}, + {5670, 5670, 0}, + {5689, 5689, 0}, + } + }, + }; + + int layered_bitrates[MaxSpatialLayers][MaxTemporalLayers]; + int layered_frame_rate[MaxTemporalLayers]; + int layered_stream_size[MaxSpatialLayers][MaxTemporalLayers]; + int layered_frame_count[MaxSpatialLayers][MaxTemporalLayers]; + + #define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl)) + + unsigned int dynamic_size[2] = {0, 0}; + unsigned int dynamic_bitrates[2] = {0, 0}; + + static int verbose = 0; + + static char* + get_codec_id_string (CodecID id) + { + switch (id) { + case VP8_ID: + return "VP8"; + case VP9_ID: + return "VP9"; + case AV1_ID: + return "AV1"; + default: + return "Unknown"; + } + } + + static void show_help() + { + printf("Usage: \n" + " fake-enc [--codec=VP8|VP9|AV1] [--framecount=frame count] " + "[--preset= 0 to 13] \n\n" + " Preset0: QVGA_256kbps_30fps \n" + " Preset1: QVGA_512kbps_30fps \n" + " Preset2: QVGA_1024kbps_30fps \n" + " Preset3: VGA_256kbps_30fps \n" + " Preset4: VGA_512kbps_30fps \n" + " Preset5: VGA_1024kbps_30fps \n" + " Preset6: HD_1024kbps_30fps \n" + " Preset7: HD_2048kbps_30fps \n" + " Preset8: HD_4096kbps_30fps \n" + " Preset9: FULLHD_1024kbps_30fps \n" + " Preset10: FULLHD_4096kbps_30fps \n" + " Preset11: FULLHD_8192kbps_30fps \n" + //Please add any non-SVC, non-dynamirc-rate-change + // presets here and increment the SVC_PRESET_START_INDEX + // and DYNAMIC_RATE_CHAGE_PRESET_START_INDEX + " Preset12: FULLHD_8192kbps_30fps_DynamicRateChange \n" + //Please add any non-SVC presets here and + //increment the SVC_PRESET_START_INDEX + " Preset13: SVC_HD_4096kbps_30fps_S3T2 \n" + "\n"); + } + + #define DYNAMIC_RATE_CHAGE_PRESET_START_INDEX 12 + #define SVC_PRESET_START_INDEX 13 + + static void + parse_args(int argc, char **argv) + { + int c,option_index; + + static const struct option long_options[] = { + {"help", no_argument, 0, 0}, + {"codec", required_argument, 0, 1}, + {"preset", required_argument, 0, 2}, + {"framecount", required_argument, 0, 3}, + {"temporal-layers", required_argument, 0, 4}, + {"spatial-layers", required_argument, 0, 5}, + {"dynamic-rate-change", required_argument, 0, 6}, + {"verbose", required_argument, 0, 7}, + { NULL, 0, NULL, 0 } + }; + + while (1) { + c = getopt_long_only (argc, argv, + "hcb:?", + long_options, + &option_index); + if (c == -1) + break; + + switch(c) { + case 1: + if (!strcmp (optarg, "VP8")) + enc_params.id = VP8_ID; + else if (!strcmp (optarg, "VP9")) + enc_params.id = VP9_ID; + else + enc_params.id = AV1_ID; + break; + case 2: { + int preset = atoi(optarg); + CodecID id = static_cast (enc_params.id); + if (preset < 0 || preset > SVC_PRESET_START_INDEX) { + printf ("Unknown preset, Failed \n"); + exit(0); + } + enc_params = preset_list[preset]; + enc_params.id = id; + } + break; + case 3: + enc_params.framecount = atoi(optarg); + break; + case 7: + verbose = atoi(optarg); + break; + default: + break; + } + } + } + + static void display_encode_status (unsigned int bitstream_size) { + + printf ("======= Encoder Input Configuration ======= \n"); + printf ( "Codec = %s \n" + "bitrate = %d kbps \n" + "framerate = %d \n" + "width = %d \n" + "height = %d \n" + "framecount = %d \n", + get_codec_id_string (static_cast (enc_params.id)), + enc_params.bitrate, + enc_params.framerate, + enc_params.width, + enc_params.height, + enc_params.framecount); + if (enc_params.num_sl > 1 || enc_params.num_tl > 1) { + printf ( "Target bitrates in kbps:\n"); + for (unsigned int sl = 0; sl 1 || enc_params.num_tl > 1) { + int total_bitrate = 0; + for (unsigned int sl = 0; sl < enc_params.num_sl; sl++) { + for (unsigned int tl = 0; tl < enc_params.num_tl; tl++) { + int bitrate = 0; + bitrate = (((layered_stream_size [sl][tl] / layered_frame_count[sl][tl]) * + layered_frame_rate[tl]) * 8) / 1000; + total_bitrate += bitrate; + printf ("SpatialLayer[%d]TemporlLayer[%d]: \n" + " Bitrate (with out including any other layers) = %d kbps \n" + " Bitrate (accumulated the lower layer targets) = %d kbps \n", + sl, tl, bitrate, total_bitrate); + } + } + } + + //Dynamic Rate Chaange + if (enc_params.dynamic_rate_change) { + int frames_count = enc_params.framecount/2; + printf ("Bitrate used for the streams with %d target bitrate = %d kbps\n\n", + dynamic_bitrates[0], + (((dynamic_size[0] / frames_count) * + enc_params.framerate) * 8 ) / 1000); + printf ("Bitrate used for the streams with %d target bitrate = %d kbps\n\n", + dynamic_bitrates[1], + (((dynamic_size[1] / frames_count) * + enc_params.framerate) * 8 ) / 1000); + } + printf ("Bitrate of the Compressed stream = %d kbps\n\n", + (((bitstream_size / enc_params.framecount) * + enc_params.framerate) * 8 ) / 1000); + printf ("\n"); + } + + static int _prev_temporal_id = 0; + + static void + get_layer_ids (int frame_count, int num_sl, int num_tl, + int *spatial_id, int *temporal_id) + { + int s_id =0, t_id = 0; + + //spatial id + s_id = frame_count % num_sl; + + //Increment the temporal_id only when all the spatial + //variants are encoded for a particualr frame id + if (!(frame_count % num_sl)) { + //temporal id + if (num_tl > 1) { + switch (num_tl) { + case 2: + if (frame_count % 2 == 0) + t_id = 0; + else + t_id = 1; + break; + case 3: + if (frame_count % 4 == 0) + t_id = 0; + else if (frame_count % 2 == 0) + t_id = 1; + else + t_id = 2; + break; + default: + printf ("Exit: Not supporting more than 3 temporal layers \n"); + exit(0); + } + } else { + t_id = 0; + } + } else { + t_id = _prev_temporal_id; + } + + *spatial_id = s_id; + *temporal_id = t_id; + _prev_temporal_id = t_id; + } + + static void + start_virtual_encode (std::unique_ptr &brc, LibMeboRateController *rc, LibMeboRateControllerConfig rc_config) + { + int i, qp = 0; + int key_frame_period = 30; + uint32_t buf_size = 1024; + uint32_t total_size = 0; + int prev_qp = 0; + uint32_t predicted_size = 0; + uint32_t lower =0, upper=0; + LibMeboFrameType libmebo_frame_type; + LibMeboRCFrameParams rc_frame_params; + unsigned int preset = enc_params.preset; + unsigned int svc_preset = 0; + int frame_count = 0; + unsigned int prev_is_key = 0; + + assert(brc != nullptr); + if (verbose) + printf ("=======Fake Encode starts ==============\n"); + + if (enc_params.num_sl > 1 || enc_params.num_tl >1) + svc_preset = preset - SVC_PRESET_START_INDEX; + + key_frame_period *= enc_params.num_sl; + + //Account spatial svc in frame_count + frame_count = enc_params.framecount * enc_params.num_sl; + + srand(time(NULL)); + for (i = 0; i < frame_count; i++) { + LibMeboStatus status; + int spatial_id; + int temporal_id; + int update_rate = 0; + unsigned int *dyn_size; + predicted_size = 0; + lower =0; + upper=0; + + get_layer_ids (i, + enc_params.num_sl, enc_params.num_tl, + &spatial_id, &temporal_id); + + //Dynamic rate reset: Reduce the framerate by 1/8 th + if (enc_params.dynamic_rate_change && + i >= frame_count/2){ + preset = 9;//bitrate change from 4096 to 1024 + dyn_size = &dynamic_size[1]; + update_rate = (i == frame_count/2) ? 1 : 0; + } else { + dyn_size = &dynamic_size[0]; + } + + if (i % key_frame_period == 0) { + libmebo_frame_type = LIBMEBO_KEY_FRAME; + if (preset < SVC_PRESET_START_INDEX) { + lower = bitrate_bounds_intra [preset].lower; + upper = bitrate_bounds_intra [preset].upper; + } else { + //SVC + lower = + svc_bitrate_bounds_intra[svc_preset]. + layer_bitrate_lower[spatial_id][temporal_id]; + upper = + svc_bitrate_bounds_intra[svc_preset]. + layer_bitrate_upper[spatial_id][temporal_id]; + } + } + else { + libmebo_frame_type = LIBMEBO_INTER_FRAME; + if (preset < SVC_PRESET_START_INDEX) { + lower = bitrate_bounds_inter [preset].lower; + upper = bitrate_bounds_inter [preset].upper; + } else { + //SVC + lower = + svc_bitrate_bounds_inter[svc_preset]. + layer_bitrate_lower[spatial_id][temporal_id]; + upper = + svc_bitrate_bounds_inter[svc_preset]. + layer_bitrate_upper[spatial_id][temporal_id]; + } + } + predicted_size = (rand() % (upper - lower)) + lower; + + //Update libmebo rate control config + if (update_rate) { + dynamic_bitrates[0] = libmebo_rc_config.target_bandwidth; + libmebo_rc_config.target_bandwidth /= 8; + dynamic_bitrates[1] = libmebo_rc_config.target_bandwidth; + status = brc->update_config(rc, &libmebo_rc_config); + assert (status == LIBMEBO_STATUS_SUCCESS); + } + + rc_frame_params.frame_type = libmebo_frame_type; + + //Set spatial layer id + rc_frame_params.spatial_layer_id = spatial_id; + rc_frame_params.temporal_layer_id = temporal_id; + status = brc->compute_qp(rc, &rc_frame_params); + assert (status == LIBMEBO_STATUS_SUCCESS); + status = brc->get_qp(rc, &qp); + assert (status == LIBMEBO_STATUS_SUCCESS); + if (verbose) + printf ("QP = %d \n", qp); + + buf_size = predicted_size; + + //Heuristics to calculate a reasonable value of the + //compressed frame size + if (i != 0 && !prev_is_key) { + int qp_val = (qp == 0) ? 1 : qp; + int size_range = upper - lower; + int qp_range_length = size_range / 256; + int suggested_size = lower + (qp_val * qp_range_length); + int new_predicted_size = 0; + + if ((qp) < prev_qp) + new_predicted_size = (rand() % (upper - suggested_size)) + suggested_size; + else + new_predicted_size = (rand() % (suggested_size - lower)) + lower; + + buf_size = new_predicted_size; + } + + prev_qp = qp; + + if (verbose) + printf ("PostEncodeBufferSize = %d \n",buf_size); + status = brc->post_encode_update(rc, buf_size); + assert (status == LIBMEBO_STATUS_SUCCESS); + + // Calculate per layer stream size + if (enc_params.num_tl > 1 || enc_params.num_sl > 1) { + layered_stream_size[spatial_id][temporal_id] += + buf_size; + layered_frame_count[spatial_id][temporal_id] += 1; + if (verbose) { + printf ("PostEncodeBufferSize of " + "spatial_layer[%d],temporal_layer[%d] = %d \n", + 0, rc_frame_params.temporal_layer_id, + buf_size); + } + } + total_size = total_size + buf_size; + *dyn_size += buf_size; + + prev_is_key = !(i % key_frame_period); + + } + + if (verbose) + printf ("=======Encode Finished==============\n"); + + display_encode_status (total_size); + } + + static void + ValidateInput () + { + if (enc_params.num_sl > 3) { + printf ("Fixme: fake-enc only supports upto 3 spatail layers, exiting\n"); + exit (0); + } + if (enc_params.num_tl > 3) { + printf ("Fixme: fake-enc only supports upto 3 temporal layers, exiting\n"); + exit (0); + } + } + + class Libmebo_brc_factory + { + public: + static std::unique_ptr create(unsigned int id ) + { + LibMeboCodecType codecType; + switch(static_cast(id)) + { + case LIBMEBO_CODEC_VP8: + codecType = LIBMEBO_CODEC_VP8; + break; + case LIBMEBO_CODEC_VP9: + codecType = LIBMEBO_CODEC_VP9; + break; + case LIBMEBO_CODEC_AV1: + codecType = LIBMEBO_CODEC_AV1; + break; + } + + switch(codecType) + { + case LIBMEBO_CODEC_VP8: + return std::make_unique(static_cast(id));//this is calling construcotr. + case LIBMEBO_CODEC_VP9: + return std::make_unique(static_cast(id)); + case LIBMEBO_CODEC_AV1: + + return std::make_unique(static_cast(id)); + case LIBMEBO_CODEC_UNKNOWN: + std::cout<<"pass correct codec. AV1, VP9, VP8:\n"; + break; + } + + } + }; + + + int main (int argc,char **argv) + { + int codec_type, algo_id; + if (argc < 3) { + show_help(); + return -1; + } + parse_args(argc, (char **)argv); + + ValidateInput (); + printf("started in fake test main\n"); + + std::unique_ptr brc = Libmebo_brc_factory::create(static_cast(enc_params. id)); + + if (brc !=nullptr) + { + LibMeboStatus status = LIBMEBO_STATUS_SUCCESS; + libmebo_rc = (LibMeboRateController *) malloc (sizeof(LibMeboRateController)); + if (!libmebo_rc) { + fprintf(stderr, "Failed allocation for LibMeboRateController \n"); + return NULL; + } + brc->init(libmebo_rc, &libmebo_rc_config); + start_virtual_encode (brc, libmebo_rc, libmebo_rc_config); + } + + return 0; + } diff --git a/test/meson.build b/test/meson.build index 01147c0..f5e10c5 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,4 +1,4 @@ -executable('fake-enc', 'fake-enc-test.c', +executable('fake-enc', 'fake-enc-test.cpp', include_directories: libmebo_inc, - dependencies: libmebo_dep_internal, + dependencies: [libmebo_dep_internal, libbrc_controller_dep], install: false)