FS-11189: add vpx settings
load time: first load config default settings merge any settings in XML run time: merge any dynamic settings
This commit is contained in:
parent
e1e8ebc0ab
commit
7fe031a9f5
478
src/switch_vpx.c
478
src/switch_vpx.c
|
@ -276,7 +276,7 @@ struct vpx_context {
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
switch_codec_settings_t codec_settings;
|
switch_codec_settings_t codec_settings;
|
||||||
unsigned int bandwidth;
|
unsigned int bandwidth;
|
||||||
vpx_codec_enc_cfg_t config;
|
vpx_codec_enc_cfg_t config;
|
||||||
switch_time_t last_key_frame;
|
switch_time_t last_key_frame;
|
||||||
|
|
||||||
vpx_codec_ctx_t encoder;
|
vpx_codec_ctx_t encoder;
|
||||||
|
@ -314,6 +314,21 @@ struct vpx_context {
|
||||||
};
|
};
|
||||||
typedef struct vpx_context vpx_context_t;
|
typedef struct vpx_context vpx_context_t;
|
||||||
|
|
||||||
|
struct vpx_globals {
|
||||||
|
int debug;
|
||||||
|
uint32_t max_bitrate;
|
||||||
|
char vp8_profile[20];
|
||||||
|
char vp9_profile[20];
|
||||||
|
char vp10_profile[20];
|
||||||
|
vpx_codec_enc_cfg_t vp8_enc_cfg;
|
||||||
|
vpx_codec_dec_cfg_t vp8_dec_cfg;
|
||||||
|
vpx_codec_enc_cfg_t vp9_enc_cfg;
|
||||||
|
vpx_codec_dec_cfg_t vp9_dec_cfg;
|
||||||
|
vpx_codec_enc_cfg_t vp10_enc_cfg;
|
||||||
|
vpx_codec_dec_cfg_t vp10_dec_cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vpx_globals vpx_globals = { 0 };
|
||||||
|
|
||||||
static switch_status_t init_decoder(switch_codec_t *codec)
|
static switch_status_t init_decoder(switch_codec_t *codec)
|
||||||
{
|
{
|
||||||
|
@ -329,14 +344,11 @@ static switch_status_t init_decoder(switch_codec_t *codec)
|
||||||
// context->decoder_init = 0;
|
// context->decoder_init = 0;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//cfg.threads = 1;//(switch_core_cpu_count() > 1) ? 2 : 1;
|
if (context->is_vp9) {
|
||||||
|
cfg.threads = vpx_globals.vp9_dec_cfg.threads;
|
||||||
cfg.threads = switch_core_cpu_count() / 2;
|
} else {
|
||||||
if (cfg.threads > 4) cfg.threads = 4;
|
|
||||||
if (cfg.threads < 1) cfg.threads = 1;
|
|
||||||
|
|
||||||
if (!context->is_vp9) { // vp8 only
|
|
||||||
// dec_flags = VPX_CODEC_USE_POSTPROC;
|
// dec_flags = VPX_CODEC_USE_POSTPROC;
|
||||||
|
cfg.threads = vpx_globals.vp8_dec_cfg.threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags) != VPX_CODEC_OK) {
|
if (vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags) != VPX_CODEC_OK) {
|
||||||
|
@ -377,7 +389,14 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||||
vpx_codec_enc_cfg_t *config = &context->config;
|
vpx_codec_enc_cfg_t *config = &context->config;
|
||||||
int token_parts = 1;
|
int token_parts = 1;
|
||||||
int cpus = switch_core_cpu_count();
|
int cpus = switch_core_cpu_count();
|
||||||
int sane, threads = 1;
|
vpx_codec_enc_cfg_t *vp8_enc_cfg = &vpx_globals.vp8_enc_cfg;
|
||||||
|
vpx_codec_enc_cfg_t *vp9_enc_cfg = &vpx_globals.vp9_enc_cfg;
|
||||||
|
|
||||||
|
if (context->is_vp9) {
|
||||||
|
*config = *vp9_enc_cfg;
|
||||||
|
} else {
|
||||||
|
*config = *vp8_enc_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
if (!context->codec_settings.video.width) {
|
if (!context->codec_settings.video.width) {
|
||||||
context->codec_settings.video.width = 1280;
|
context->codec_settings.video.width = 1280;
|
||||||
|
@ -395,14 +414,11 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||||
context->bandwidth = context->codec_settings.video.bandwidth;
|
context->bandwidth = context->codec_settings.video.bandwidth;
|
||||||
} else {
|
} else {
|
||||||
context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 15);
|
context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 15);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sane = switch_calc_bitrate(1920, 1080, 5, 60);
|
if (context->bandwidth > vpx_globals.max_bitrate) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "BITRATE TRUNCATED FROM %d TO %d\n", context->bandwidth, vpx_globals.max_bitrate);
|
||||||
if (context->bandwidth > sane) {
|
context->bandwidth = vpx_globals.max_bitrate;
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "BITRATE TRUNCATED FROM %d TO %d\n", context->bandwidth, sane);
|
|
||||||
context->bandwidth = sane;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context->pkt = NULL;
|
context->pkt = NULL;
|
||||||
|
@ -413,29 +429,16 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||||
|
|
||||||
context->start_time = switch_micro_time_now();
|
context->start_time = switch_micro_time_now();
|
||||||
|
|
||||||
config->g_timebase.num = 1;
|
|
||||||
config->g_timebase.den = 90000;
|
|
||||||
config->g_pass = VPX_RC_ONE_PASS;
|
|
||||||
config->g_w = context->codec_settings.video.width;
|
config->g_w = context->codec_settings.video.width;
|
||||||
config->g_h = context->codec_settings.video.height;
|
config->g_h = context->codec_settings.video.height;
|
||||||
config->rc_target_bitrate = context->bandwidth;
|
config->rc_target_bitrate = context->bandwidth;
|
||||||
config->g_lag_in_frames = 0;
|
|
||||||
config->kf_max_dist = 360;//2000;
|
|
||||||
threads = cpus / 2;
|
|
||||||
if (threads > 4) threads = 4;
|
|
||||||
if (threads < 1) threads = 1;
|
|
||||||
config->g_threads = threads;
|
|
||||||
|
|
||||||
if (context->is_vp9) {
|
if (context->is_vp9) {
|
||||||
//config->rc_dropframe_thresh = 2;
|
|
||||||
token_parts = (cpus > 1) ? 3 : 0;
|
token_parts = (cpus > 1) ? 3 : 0;
|
||||||
|
|
||||||
if (context->lossless) {
|
if (context->lossless) {
|
||||||
config->rc_min_quantizer = 0;
|
config->rc_min_quantizer = 0;
|
||||||
config->rc_max_quantizer = 0;
|
config->rc_max_quantizer = 0;
|
||||||
} else {
|
|
||||||
config->rc_min_quantizer = 0;
|
|
||||||
config->rc_max_quantizer = 63;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING;
|
config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING;
|
||||||
|
@ -444,63 +447,7 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||||
config->ts_periodicity = 1;
|
config->ts_periodicity = 1;
|
||||||
config->ts_layer_id[0] = 0;
|
config->ts_layer_id[0] = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// settings
|
|
||||||
config->g_profile = 2;
|
|
||||||
config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
|
|
||||||
token_parts = (cpus > 1) ? 3 : 0;
|
token_parts = (cpus > 1) ? 3 : 0;
|
||||||
|
|
||||||
// rate control settings
|
|
||||||
config->rc_dropframe_thresh = 0;
|
|
||||||
config->rc_end_usage = VPX_CBR;
|
|
||||||
//config->g_pass = VPX_RC_ONE_PASS;
|
|
||||||
config->kf_mode = VPX_KF_AUTO;
|
|
||||||
config->kf_max_dist = 360;//1000;
|
|
||||||
|
|
||||||
//config->kf_mode = VPX_KF_DISABLED;
|
|
||||||
config->rc_resize_allowed = 1;
|
|
||||||
//config->rc_min_quantizer = 0;
|
|
||||||
//config->rc_max_quantizer = 63;
|
|
||||||
config->rc_min_quantizer = 0;
|
|
||||||
config->rc_max_quantizer = 63;
|
|
||||||
//Rate control adaptation undershoot control.
|
|
||||||
// This value, expressed as a percentage of the target bitrate,
|
|
||||||
// controls the maximum allowed adaptation speed of the codec.
|
|
||||||
// This factor controls the maximum amount of bits that can be
|
|
||||||
// subtracted from the target bitrate in order to compensate for
|
|
||||||
// prior overshoot.
|
|
||||||
// Valid values in the range 0-1000.
|
|
||||||
config->rc_undershoot_pct = 100;
|
|
||||||
//Rate control adaptation overshoot control.
|
|
||||||
// This value, expressed as a percentage of the target bitrate,
|
|
||||||
// controls the maximum allowed adaptation speed of the codec.
|
|
||||||
// This factor controls the maximum amount of bits that can be
|
|
||||||
// added to the target bitrate in order to compensate for prior
|
|
||||||
// undershoot.
|
|
||||||
// Valid values in the range 0-1000.
|
|
||||||
config->rc_overshoot_pct = 15;
|
|
||||||
//Decoder Buffer Size.
|
|
||||||
// This value indicates the amount of data that may be buffered
|
|
||||||
// by the decoding application. Note that this value is expressed
|
|
||||||
// in units of time (milliseconds). For example, a value of 5000
|
|
||||||
// indicates that the client will buffer (at least) 5000ms worth
|
|
||||||
// of encoded data. Use the target bitrate (rc_target_bitrate) to
|
|
||||||
// convert to bits/bytes, if necessary.
|
|
||||||
config->rc_buf_sz = 5000;
|
|
||||||
//Decoder Buffer Initial Size.
|
|
||||||
// This value indicates the amount of data that will be buffered
|
|
||||||
// by the decoding application prior to beginning playback.
|
|
||||||
// This value is expressed in units of time (milliseconds).
|
|
||||||
// Use the target bitrate (rc_target_bitrate) to convert to
|
|
||||||
// bits/bytes, if necessary.
|
|
||||||
config->rc_buf_initial_sz = 1000;
|
|
||||||
//Decoder Buffer Optimal Size.
|
|
||||||
// This value indicates the amount of data that the encoder should
|
|
||||||
// try to maintain in the decoder's buffer. This value is expressed
|
|
||||||
// in units of time (milliseconds).
|
|
||||||
// Use the target bitrate (rc_target_bitrate) to convert to
|
|
||||||
// bits/bytes, if necessary.
|
|
||||||
config->rc_buf_optimal_sz = 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->encoder_init) {
|
if (context->encoder_init) {
|
||||||
|
@ -510,45 +457,45 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||||
}
|
}
|
||||||
} else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) {
|
} else if (context->flags & SWITCH_CODEC_FLAG_ENCODE) {
|
||||||
|
|
||||||
// #define SHOW(field) fprintf(stderr, " %-28s = %d\n", #field, config->field);
|
if (vpx_globals.debug) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec: %s\n", vpx_codec_iface_name(context->encoder_interface));
|
||||||
|
|
||||||
#ifdef SHOW
|
#define SHOW(field) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " %-28s = %d\n", #field, config->field);
|
||||||
fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(context->encoder_interface));
|
|
||||||
|
|
||||||
SHOW(g_usage);
|
SHOW(g_usage);
|
||||||
SHOW(g_threads);
|
SHOW(g_threads);
|
||||||
SHOW(g_profile);
|
SHOW(g_profile);
|
||||||
SHOW(g_w);
|
SHOW(g_w);
|
||||||
SHOW(g_h);
|
SHOW(g_h);
|
||||||
SHOW(g_bit_depth);
|
SHOW(g_bit_depth);
|
||||||
SHOW(g_input_bit_depth);
|
SHOW(g_input_bit_depth);
|
||||||
SHOW(g_timebase.num);
|
SHOW(g_timebase.num);
|
||||||
SHOW(g_timebase.den);
|
SHOW(g_timebase.den);
|
||||||
SHOW(g_error_resilient);
|
SHOW(g_error_resilient);
|
||||||
SHOW(g_pass);
|
SHOW(g_pass);
|
||||||
SHOW(g_lag_in_frames);
|
SHOW(g_lag_in_frames);
|
||||||
SHOW(rc_dropframe_thresh);
|
SHOW(rc_dropframe_thresh);
|
||||||
SHOW(rc_resize_allowed);
|
SHOW(rc_resize_allowed);
|
||||||
SHOW(rc_scaled_width);
|
SHOW(rc_scaled_width);
|
||||||
SHOW(rc_scaled_height);
|
SHOW(rc_scaled_height);
|
||||||
SHOW(rc_resize_up_thresh);
|
SHOW(rc_resize_up_thresh);
|
||||||
SHOW(rc_resize_down_thresh);
|
SHOW(rc_resize_down_thresh);
|
||||||
SHOW(rc_end_usage);
|
SHOW(rc_end_usage);
|
||||||
SHOW(rc_target_bitrate);
|
SHOW(rc_target_bitrate);
|
||||||
SHOW(rc_min_quantizer);
|
SHOW(rc_min_quantizer);
|
||||||
SHOW(rc_max_quantizer);
|
SHOW(rc_max_quantizer);
|
||||||
SHOW(rc_undershoot_pct);
|
SHOW(rc_undershoot_pct);
|
||||||
SHOW(rc_overshoot_pct);
|
SHOW(rc_overshoot_pct);
|
||||||
SHOW(rc_buf_sz);
|
SHOW(rc_buf_sz);
|
||||||
SHOW(rc_buf_initial_sz);
|
SHOW(rc_buf_initial_sz);
|
||||||
SHOW(rc_buf_optimal_sz);
|
SHOW(rc_buf_optimal_sz);
|
||||||
SHOW(rc_2pass_vbr_bias_pct);
|
SHOW(rc_2pass_vbr_bias_pct);
|
||||||
SHOW(rc_2pass_vbr_minsection_pct);
|
SHOW(rc_2pass_vbr_minsection_pct);
|
||||||
SHOW(rc_2pass_vbr_maxsection_pct);
|
SHOW(rc_2pass_vbr_maxsection_pct);
|
||||||
SHOW(kf_mode);
|
SHOW(kf_mode);
|
||||||
SHOW(kf_min_dist);
|
SHOW(kf_min_dist);
|
||||||
SHOW(kf_max_dist);
|
SHOW(kf_max_dist);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
if (vpx_codec_enc_init(&context->encoder, context->encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION) != VPX_CODEC_OK) {
|
if (vpx_codec_enc_init(&context->encoder, context->encoder_interface, config, 0 & VPX_CODEC_USE_OUTPUT_PARTITION) != VPX_CODEC_OK) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s init error: [%d:%s]\n", vpx_codec_iface_name(context->encoder_interface), context->encoder.err, context->encoder.err_detail);
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s init error: [%d:%s]\n", vpx_codec_iface_name(context->encoder_interface), context->encoder.err, context->encoder.err_detail);
|
||||||
|
@ -625,11 +572,6 @@ static switch_status_t switch_vpx_init(switch_codec_t *codec, switch_codec_flag_
|
||||||
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vpx_codec_enc_config_default(context->encoder_interface, &context->config, 0) != VPX_CODEC_OK) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder config Error\n");
|
|
||||||
return SWITCH_STATUS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->codec_settings.video.width = 320;
|
context->codec_settings.video.width = 320;
|
||||||
context->codec_settings.video.height = 240;
|
context->codec_settings.video.height = 240;
|
||||||
|
|
||||||
|
@ -826,7 +768,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
|
||||||
height = frame->img->h;
|
height = frame->img->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->config.g_w != width || context->config.g_h != height) {
|
if (context->codec_settings.video.width != width || context->codec_settings.video.height != height) {
|
||||||
context->codec_settings.video.width = width;
|
context->codec_settings.video.width = width;
|
||||||
context->codec_settings.video.height = height;
|
context->codec_settings.video.height = height;
|
||||||
reset_codec_encoder(codec);
|
reset_codec_encoder(codec);
|
||||||
|
@ -834,7 +776,6 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
|
||||||
context->need_key_frame = 3;
|
context->need_key_frame = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!context->encoder_init) {
|
if (!context->encoder_init) {
|
||||||
if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
|
if (init_encoder(codec) != SWITCH_STATUS_SUCCESS) {
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
|
@ -1386,12 +1327,290 @@ static switch_status_t switch_vpx_destroy(switch_codec_t *codec)
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UINTVAL(v) (v > 0 ? v : 0);
|
||||||
|
|
||||||
|
static void load_config()
|
||||||
|
{
|
||||||
|
switch_xml_t cfg = NULL, xml = NULL;
|
||||||
|
|
||||||
|
vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &vpx_globals.vp8_enc_cfg, 0);
|
||||||
|
vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &vpx_globals.vp9_enc_cfg, 0);
|
||||||
|
|
||||||
|
switch_set_string(vpx_globals.vp8_profile, "vp8");
|
||||||
|
switch_set_string(vpx_globals.vp9_profile, "vp9");
|
||||||
|
switch_set_string(vpx_globals.vp10_profile, "vp10");
|
||||||
|
|
||||||
|
vpx_globals.max_bitrate = 0;
|
||||||
|
|
||||||
|
xml = switch_xml_open_cfg("vpx.conf", &cfg, NULL);
|
||||||
|
|
||||||
|
if (xml) {
|
||||||
|
switch_xml_t settings = switch_xml_child(cfg, "settings");
|
||||||
|
switch_xml_t profiles = switch_xml_child(cfg, "profiles");
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
switch_xml_t param;
|
||||||
|
|
||||||
|
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||||
|
const char *name = switch_xml_attr(param, "name");
|
||||||
|
const char *value = switch_xml_attr(param, "value");
|
||||||
|
|
||||||
|
if (zstr(name) || zstr(value)) continue;
|
||||||
|
|
||||||
|
if (!strcmp(name, "max-bitrate")) {
|
||||||
|
vpx_globals.max_bitrate = switch_parse_bandwidth_string(value);
|
||||||
|
} else if (!strcmp(name, "dec-threads")) {
|
||||||
|
vpx_globals.vp8_dec_cfg.threads = switch_parse_cpu_string(value);
|
||||||
|
vpx_globals.vp9_dec_cfg.threads = switch_parse_cpu_string(value);
|
||||||
|
vpx_globals.vp10_dec_cfg.threads = switch_parse_cpu_string(value);
|
||||||
|
} else if (!strcmp(name, "enc-threads")) {
|
||||||
|
vpx_globals.vp8_enc_cfg.g_threads = switch_parse_cpu_string(value);
|
||||||
|
vpx_globals.vp9_enc_cfg.g_threads = switch_parse_cpu_string(value);
|
||||||
|
vpx_globals.vp10_enc_cfg.g_threads = switch_parse_cpu_string(value);
|
||||||
|
} else if (!strcmp(name, "vp8-profile")) {
|
||||||
|
switch_set_string(vpx_globals.vp8_profile, value);
|
||||||
|
} else if (!strcmp(name, "vp9-profile")) {
|
||||||
|
switch_set_string(vpx_globals.vp9_profile, value);
|
||||||
|
} else if (!strcmp(name, "vp10-profile")) {
|
||||||
|
switch_set_string(vpx_globals.vp10_profile, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profiles) {
|
||||||
|
switch_xml_t profile = switch_xml_child(profiles, "profile");
|
||||||
|
|
||||||
|
for (; profile; profile = profile->next) {
|
||||||
|
switch_xml_t param = NULL;
|
||||||
|
const char *profile_name = switch_xml_attr(profile, "name");
|
||||||
|
vpx_codec_dec_cfg_t *dec_cfg = NULL;
|
||||||
|
vpx_codec_enc_cfg_t *enc_cfg = NULL;
|
||||||
|
|
||||||
|
if (zstr(profile_name)) continue;
|
||||||
|
|
||||||
|
if (!strcmp(profile_name, vpx_globals.vp8_profile)) {
|
||||||
|
dec_cfg = &vpx_globals.vp8_dec_cfg;
|
||||||
|
enc_cfg = &vpx_globals.vp8_enc_cfg;
|
||||||
|
} else if (!strcmp(profile_name, vpx_globals.vp9_profile)) {
|
||||||
|
dec_cfg = &vpx_globals.vp9_dec_cfg;
|
||||||
|
enc_cfg = &vpx_globals.vp9_enc_cfg;
|
||||||
|
} else if (!strcmp(profile_name, vpx_globals.vp10_profile)) {
|
||||||
|
dec_cfg = &vpx_globals.vp10_dec_cfg;
|
||||||
|
enc_cfg = &vpx_globals.vp10_enc_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (param = switch_xml_child(profile, "param"); param; param = param->next) {
|
||||||
|
const char *name = switch_xml_attr(param, "name");
|
||||||
|
const char *value = switch_xml_attr(param, "value");
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (!enc_cfg || !dec_cfg) break;
|
||||||
|
if (zstr(name) || zstr(value)) continue;
|
||||||
|
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: %s = %s\n", profile_name, name, value);
|
||||||
|
|
||||||
|
val = atoi(value);
|
||||||
|
|
||||||
|
if (!strcmp(name, "dec-threads")) {
|
||||||
|
dec_cfg->threads = switch_parse_cpu_string(value);
|
||||||
|
} else if (!strcmp(name, "enc-threads")) {
|
||||||
|
enc_cfg->g_threads = switch_parse_cpu_string(value);
|
||||||
|
} else if (!strcmp(name, "g-profile")) {
|
||||||
|
enc_cfg->g_profile = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "g-timebase")) {
|
||||||
|
int num = 0;
|
||||||
|
int den = 0;
|
||||||
|
char *slash = strchr(value, '/');
|
||||||
|
|
||||||
|
num = UINTVAL(val);
|
||||||
|
|
||||||
|
if (slash) {
|
||||||
|
slash++;
|
||||||
|
den = atoi(slash);
|
||||||
|
|
||||||
|
if (den < 0) den = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num && den) {
|
||||||
|
enc_cfg->g_timebase.num = num;
|
||||||
|
enc_cfg->g_timebase.den = den;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(name, "g-error-resilient")) {
|
||||||
|
char *s = strdup(value);
|
||||||
|
vpx_codec_er_flags_t res = 0;
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
int argc;
|
||||||
|
char *argv[10];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
argc = switch_separate_string(s, '|', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (!strcasecmp(argv[i], "DEFAULT")) {
|
||||||
|
res |= VPX_ERROR_RESILIENT_DEFAULT;
|
||||||
|
} else if (!strcasecmp(argv[i], "PARTITIONS")) {
|
||||||
|
res |= VPX_ERROR_RESILIENT_PARTITIONS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(s);
|
||||||
|
enc_cfg->g_error_resilient = res;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(name, "g-pass")) {
|
||||||
|
int pass = 0;
|
||||||
|
|
||||||
|
if (!strcasecmp(value, "ONE_PASS")) {
|
||||||
|
pass = VPX_RC_ONE_PASS;
|
||||||
|
} else if (!strcasecmp(value, "FIRST_PASS")) {
|
||||||
|
pass = VPX_RC_FIRST_PASS;
|
||||||
|
} else if (!strcasecmp(value, "LAST_PASS")) {
|
||||||
|
pass = VPX_RC_FIRST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_cfg->g_pass = pass;
|
||||||
|
} else if (!strcmp(name, "g-lag-in-frames")) {
|
||||||
|
enc_cfg->g_lag_in_frames = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc_dropframe_thresh")) {
|
||||||
|
enc_cfg->rc_dropframe_thresh = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-resize-allowed")) {
|
||||||
|
enc_cfg->rc_resize_allowed = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-scaled-width")) {
|
||||||
|
enc_cfg->rc_scaled_width = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-scaled-height")) {
|
||||||
|
enc_cfg->rc_scaled_height = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-resize-up-thresh")) {
|
||||||
|
enc_cfg->rc_resize_up_thresh = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-resize-down-thresh")) {
|
||||||
|
enc_cfg->rc_resize_down_thresh = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-end-usage")) {
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
if (!strcasecmp(value, "VBR")) {
|
||||||
|
mode = VPX_VBR;
|
||||||
|
} else if (!strcasecmp(value, "CBR")) {
|
||||||
|
mode = VPX_CBR;
|
||||||
|
} else if (!strcasecmp(value, "CQ")) {
|
||||||
|
mode = VPX_CQ;
|
||||||
|
} else if (!strcasecmp(value, "Q")) {
|
||||||
|
mode = VPX_Q;
|
||||||
|
}
|
||||||
|
enc_cfg->rc_end_usage = mode;
|
||||||
|
} else if (!strcmp(name, "rc-target-bitrate")) {
|
||||||
|
int br = switch_parse_bandwidth_string(value);
|
||||||
|
|
||||||
|
if (br > 0) {
|
||||||
|
enc_cfg->rc_target_bitrate = br;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(name, "rc-min-quantizer")) {
|
||||||
|
enc_cfg->rc_min_quantizer = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-max-quantizer")) {
|
||||||
|
enc_cfg->rc_max_quantizer = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-undershoot-pct")) {
|
||||||
|
enc_cfg->rc_undershoot_pct = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-overshoot-pct")) {
|
||||||
|
enc_cfg->rc_overshoot_pct = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-buf-sz")) {
|
||||||
|
enc_cfg->rc_buf_sz = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-buf-initial-sz")) {
|
||||||
|
enc_cfg->rc_buf_initial_sz = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-buf-optimal-sz")) {
|
||||||
|
enc_cfg->rc_buf_optimal_sz = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-2pass-vbr-bias-pct")) {
|
||||||
|
enc_cfg->rc_2pass_vbr_bias_pct = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-2pass-vbr-minsection-pct")) {
|
||||||
|
enc_cfg->rc_2pass_vbr_minsection_pct = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "rc-2pass-vbr-maxsection-pct")) {
|
||||||
|
enc_cfg->rc_2pass_vbr_maxsection_pct = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "kf-mode")) {
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
if (!strcasecmp(value, "AUTO")) {
|
||||||
|
mode = VPX_KF_AUTO;
|
||||||
|
} else if (!strcasecmp(value, "DISABLED")) {
|
||||||
|
mode = VPX_KF_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_cfg->kf_mode = mode;
|
||||||
|
} else if (!strcmp(name, "kf-min-dist")) {
|
||||||
|
enc_cfg->kf_min_dist = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "kf-max-dist")) {
|
||||||
|
enc_cfg->kf_max_dist = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "ss-number-layers")) {
|
||||||
|
enc_cfg->ss_number_layers = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "ts-number-layers")) {
|
||||||
|
enc_cfg->ts_number_layers = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "ts-periodicity")) {
|
||||||
|
enc_cfg->ts_periodicity = UINTVAL(val);
|
||||||
|
} else if (!strcmp(name, "temporal-layering-mode")) {
|
||||||
|
enc_cfg->temporal_layering_mode = UINTVAL(val);
|
||||||
|
}
|
||||||
|
} // for param
|
||||||
|
} // for profile
|
||||||
|
} // profiles
|
||||||
|
|
||||||
|
switch_xml_free(xml);
|
||||||
|
} // xml
|
||||||
|
|
||||||
|
if (vpx_globals.max_bitrate <= 0) {
|
||||||
|
vpx_globals.max_bitrate = switch_calc_bitrate(1920, 1080, 5, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vpx_globals.vp8_enc_cfg.g_threads) vpx_globals.vp8_enc_cfg.g_threads = 1;
|
||||||
|
if (!vpx_globals.vp8_dec_cfg.threads) vpx_globals.vp8_dec_cfg.threads = switch_parse_cpu_string("cpu/2/4");
|
||||||
|
if (!vpx_globals.vp9_enc_cfg.g_threads) vpx_globals.vp9_enc_cfg.g_threads = vpx_globals.vp8_enc_cfg.g_threads;
|
||||||
|
if (!vpx_globals.vp9_dec_cfg.threads) vpx_globals.vp9_dec_cfg.threads = vpx_globals.vp8_dec_cfg.threads;
|
||||||
|
if (!vpx_globals.vp10_enc_cfg.g_threads) vpx_globals.vp10_enc_cfg.g_threads = vpx_globals.vp8_enc_cfg.g_threads;
|
||||||
|
if (!vpx_globals.vp10_dec_cfg.threads) vpx_globals.vp10_dec_cfg.threads = vpx_globals.vp8_dec_cfg.threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VPX_API_SYNTAX "<reload|debug <on|off>>"
|
||||||
|
SWITCH_STANDARD_API(vpx_api_function)
|
||||||
|
{
|
||||||
|
if (session) {
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zstr(cmd)) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(cmd, "reload")) {
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
switch_xml_reload(&err);
|
||||||
|
stream->write_function(stream, "Reload XML [%s]\n", err);
|
||||||
|
|
||||||
|
load_config();
|
||||||
|
stream->write_function(stream, "+OK\n");
|
||||||
|
} else if (!strcasecmp(cmd, "debug")) {
|
||||||
|
stream->write_function(stream, "+OK debug %s\n", vpx_globals.debug ? "on" : "off");
|
||||||
|
} else if (!strcasecmp(cmd, "debug on")) {
|
||||||
|
vpx_globals.debug = 1;
|
||||||
|
stream->write_function(stream, "+OK debug on\n");
|
||||||
|
} else if (!strcasecmp(cmd, "debug off")) {
|
||||||
|
vpx_globals.debug = 0;
|
||||||
|
stream->write_function(stream, "+OK debug off\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
usage:
|
||||||
|
stream->write_function(stream, "USAGE: %s\n", VPX_API_SYNTAX);
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load)
|
SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load)
|
||||||
{
|
{
|
||||||
switch_codec_interface_t *codec_interface;
|
switch_codec_interface_t *codec_interface;
|
||||||
|
switch_api_interface_t *vpx_api_interface;
|
||||||
|
|
||||||
|
memset(&vpx_globals, 0, sizeof(struct vpx_globals));
|
||||||
|
load_config();
|
||||||
|
|
||||||
/* connect my internal structure to the blank pointer passed to me */
|
/* connect my internal structure to the blank pointer passed to me */
|
||||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||||
|
|
||||||
SWITCH_ADD_CODEC(codec_interface, "VP8 Video");
|
SWITCH_ADD_CODEC(codec_interface, "VP8 Video");
|
||||||
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP8", NULL,
|
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP8", NULL,
|
||||||
switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
|
switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
|
||||||
|
@ -1399,6 +1618,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load)
|
||||||
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP9", NULL,
|
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP9", NULL,
|
||||||
switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
|
switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
|
||||||
|
|
||||||
|
SWITCH_ADD_API(vpx_api_interface, "vpx",
|
||||||
|
"VPX API", vpx_api_function, VPX_API_SYNTAX);
|
||||||
|
|
||||||
/* indicate that the module should continue to be loaded */
|
/* indicate that the module should continue to be loaded */
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue