diff --git a/src/mod/applications/mod_av/autoload_configs/av.conf.xml b/src/mod/applications/mod_av/autoload_configs/av.conf.xml new file mode 100644 index 0000000000..d9aaa0abcc --- /dev/null +++ b/src/mod/applications/mod_av/autoload_configs/av.conf.xml @@ -0,0 +1,144 @@ +<configuration name="avcodec.conf" description="AVCodec Config"> + <settings> + <!-- max bitrate the system support, truncate if over limit --> + <!-- <param name="max-bitrate" value="5mb"/> --> + + <!-- <param name="rtp-slice-size" value="1200"/> --> + + <!-- minimum time to generate a new key frame in ms /> --> + <!-- <param name="key-frame-min-freq" value="250"/> --> + + <!-- integer of cpus, or 'auto', or 'cpu/<divisor>/<max> --> + <param name="dec-threads" value="cpu/2/4"/> + <param name="enc-threads" value="cpu/2/4"/> + <param name="h263-profile" value="H263"/> + <param name="h263+-profile" value="H263+"/> + <param name="h264-profile" value="H264"/> + <param name="h265-profile" value="H265"/> + </settings> + + <profiles> + <profile name="H263"> + </profile> + + <profile name="H263+"> + </profile> + + <profile name="H264"> + <!-- <param name="dec-threads" value="cpu/2/4"/> --> + <!-- <param name="enc-threads" value="1"/> --> + + <!-- <param name="profile" value="2"/> --> + <!-- <param name="level" value="41"/> --> + <!-- <param name="timebase" value="1/90"/> --> + +<!-- + +#define AV_CODEC_FLAG_UNALIGNED (1 << 0) +#define AV_CODEC_FLAG_QSCALE (1 << 1) +#define AV_CODEC_FLAG_4MV (1 << 2) +#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) +#define AV_CODEC_FLAG_QPEL (1 << 4) +#define AV_CODEC_FLAG_PASS1 (1 << 9) +#define AV_CODEC_FLAG_PASS2 (1 << 10) +#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) +#define AV_CODEC_FLAG_GRAY (1 << 13) +#define AV_CODEC_FLAG_PSNR (1 << 15) +#define AV_CODEC_FLAG_TRUNCATED (1 << 16) +#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) +#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) +#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) +#define AV_CODEC_FLAG_BITEXACT (1 << 23) +#define AV_CODEC_FLAG_AC_PRED (1 << 24) +#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) +#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) + +--> + + <param name="flags" value="LOOP_FILTER|PSNR"/> + +<!-- +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_MEDIAN_SAD 15 +#define FF_CMP_CHROMA 256 +--> + + <!-- <param name="me-cmp" value="1"/> --> + <!-- <param name="me-range" value="16"/> --> + <!-- <param name="max-b-frames" value="3"/> --> + <!-- <param name="refs" value="3"/> --> + <!-- <param name="gop-size" value="250"/> --> + <!-- <param name="keyint-min" value="25"/> --> + <!-- <param name="i-quant-factor" value="0.71"/> --> + <!-- <param name="b-quant-factor" value="0.76923078"/> --> + <!-- <param name="qcompress" value="0.6"/> --> + <!-- <param name="qmin" value="10"/> --> + <!-- <param name="qmax" value="51"/> --> + <!-- <param name="max-qdiff" value="4"/> --> + +<!-- +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_NB ///< Not part of ABI +}; +--> + <param name="colorspace" value="0"/> + +<!-- +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB ///< Not part of ABI +}; +--> + <param name="color-range" value="2"/> + + <!-- x264 private --> + <param name="x264-preset" value="veryfast"/> + <param name="x264-intra-refresh" value="1"/> + <param name="x264-tune" value="animation+zerolatency"/> + <!-- <param name="x264-sc-threshold" value="40"/> --> + <!-- <param name="x264-b-strategy" value="1"/> --> + <!-- <param name="x264-crf" value="18"/> --> + + </profile> + + <profile name="H265"> + </profile> + </profiles> +</configuration> + +<configuration name="avformat.conf" description="AVFormat Config"> + <settings> + </settings> +</configuration> diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index d6bfca0167..593581825d 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -38,10 +38,12 @@ #include <libavutil/opt.h> #include <libavutil/imgutils.h> -#define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE +int SLICE_SIZE = SWITCH_DEFAULT_VIDEO_SIZE; + #define H264_NALU_BUFFER_SIZE 65536 -#define MAX_NALUS 128 +#define MAX_NALUS 256 #define H263_MODE_B // else Mode A only +#define KEY_FRAME_MIN_FREQ 250000 SWITCH_MODULE_LOAD_FUNCTION(mod_avcodec_load); @@ -194,6 +196,55 @@ typedef struct h264_codec_context_s { static uint8_t ff_input_buffer_padding[FF_INPUT_BUFFER_PADDING_SIZE] = { 0 }; +#define MAX_CODECS 4 + +typedef struct avcodec_profile_s { + char name[20]; + int decoder_thread_count; + AVCodecContext ctx; + struct { + char preset[20]; + char tune[64]; + int intra_refresh; + int sc_threshold; + int b_strategy; + int crf; + } x264; +} avcodec_profile_t; + +struct avcodec_globals { + int debug; + uint32_t max_bitrate; + uint32_t rtp_slice_size; + uint32_t key_frame_min_freq; + + avcodec_profile_t profiles[MAX_CODECS]; +}; + +struct avcodec_globals avcodec_globals = { 0 }; + +char *CODEC_MAPS[] = { + "H263", + "H263+", + "H264", + "H265", + NULL +}; + +static int get_codec_index(const char *cstr) +{ + int i; + + for (i = 0; ; i++) { + if (!strcasecmp(cstr, CODEC_MAPS[i])) { + return i; + } + } + + abort(); + return -1; +} + static switch_status_t buffer_h264_nalu(h264_codec_context_t *context, switch_frame_t *frame) { uint8_t nalu_type = 0; @@ -827,9 +878,8 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t width, uint32_t height) { - int sane = 0; - int threads = switch_core_cpu_count(); int fps = 15; + avcodec_profile_t *profile = NULL; #ifdef NVENC_SUPPORT if (!context->encoder) { @@ -860,6 +910,18 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt return SWITCH_STATUS_FALSE; } + if (context->av_codec_id == AV_CODEC_ID_H263) { + profile = &avcodec_globals.profiles[get_codec_index("H263")]; + } else if (context->av_codec_id == AV_CODEC_ID_H263P) { + profile = &avcodec_globals.profiles[get_codec_index("H263+")]; + } else if (context->av_codec_id == AV_CODEC_ID_H264) { + profile = &avcodec_globals.profiles[get_codec_index("H264")]; + } else if (context->av_codec_id == AV_CODEC_ID_H265) { + profile = &avcodec_globals.profiles[get_codec_index("H265")]; + } + + if (!profile) return SWITCH_STATUS_FALSE; + if (context->encoder_ctx) { if (avcodec_is_open(context->encoder_ctx)) { avcodec_close(context->encoder_ctx); @@ -896,15 +958,11 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, fps); } - sane = switch_calc_bitrate(1920, 1080, 3, 60); - - if (context->bandwidth > sane) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BITRATE TRUNCATED TO %d\n", sane); - context->bandwidth = sane; + if (context->bandwidth > avcodec_globals.max_bitrate) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BITRATE TRUNCATED TO %d\n", avcodec_globals.max_bitrate); + context->bandwidth = avcodec_globals.max_bitrate; } - if (threads > 4) threads = 4; - context->bandwidth *= 3; fps = context->codec_settings.video.fps; @@ -921,11 +979,10 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt context->encoder_ctx->width = context->codec_settings.video.width; context->encoder_ctx->height = context->codec_settings.video.height; - /* frames per second */ context->encoder_ctx->time_base = (AVRational){1, 90}; - context->encoder_ctx->max_b_frames = 0; + context->encoder_ctx->max_b_frames = profile->ctx.max_b_frames; context->encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - context->encoder_ctx->thread_count = threads; + context->encoder_ctx->thread_count = profile->ctx.thread_count; if (context->av_codec_id == AV_CODEC_ID_H263 || context->av_codec_id == AV_CODEC_ID_H263P) { #ifndef H263_MODE_B @@ -946,44 +1003,38 @@ FF_ENABLE_DEPRECATION_WARNINGS context->encoder_ctx->opaque = context; av_opt_set_int(context->encoder_ctx->priv_data, "mb_info", SLICE_SIZE - 8, 0); } else if (context->av_codec_id == AV_CODEC_ID_H264) { - context->encoder_ctx->profile = FF_PROFILE_H264_BASELINE; - context->encoder_ctx->level = 31; + context->encoder_ctx->profile = profile->ctx.profile; + context->encoder_ctx->level = profile->ctx.level; if (context->hw_encoder) { av_opt_set(context->encoder_ctx->priv_data, "preset", "llhp", 0); av_opt_set_int(context->encoder_ctx->priv_data, "2pass", 1, 0); } else { - av_opt_set_int(context->encoder_ctx->priv_data, "intra-refresh", 1, 0); - av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0); - av_opt_set(context->encoder_ctx->priv_data, "tune", "animation+zerolatency", 0); - av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0); + av_opt_set_int(context->encoder_ctx->priv_data, "intra-refresh", profile->x264.intra_refresh, 0); + av_opt_set(context->encoder_ctx->priv_data, "preset", profile->x264.preset, 0); + av_opt_set(context->encoder_ctx->priv_data, "tune", profile->x264.tune, 0); av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0); - - context->encoder_ctx->colorspace = AVCOL_SPC_RGB; - context->encoder_ctx->color_range = AVCOL_RANGE_JPEG; + context->encoder_ctx->colorspace = profile->ctx.colorspace; + context->encoder_ctx->color_range = profile->ctx.color_range; - /* - av_opt_set_int(context->encoder_ctx->priv_data, "sc_threshold", 40, 0); - av_opt_set_int(context->encoder_ctx->priv_data, "b_strategy", 1, 0); - av_opt_set_int(context->encoder_ctx->priv_data, "crf", 18, 0); + if (profile->x264.sc_threshold > 0) av_opt_set_int(context->encoder_ctx->priv_data, "sc_threshold", profile->x264.sc_threshold, 0); + if (profile->x264.b_strategy > 0)av_opt_set_int(context->encoder_ctx->priv_data, "b_strategy", profile->x264.b_strategy, 0); + if (profile->x264.crf > 0)av_opt_set_int(context->encoder_ctx->priv_data, "crf", profile->x264.crf, 0); - // libx264-medium.ffpreset preset - - context->encoder_ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop - context->encoder_ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1 - context->encoder_ctx->me_range = 21; // me_range=16 - context->encoder_ctx->max_b_frames = 3; // bf=3 - //context->encoder_ctx->refs = 3; // refs=3 - context->encoder_ctx->gop_size = 250; // g=250 - context->encoder_ctx->keyint_min = 25; // keyint_min=25 - context->encoder_ctx->i_quant_factor = 0.71; // i_qfactor=0.71 - context->encoder_ctx->b_quant_factor = 0.76923078; // Qscale difference between P-frames and B-frames. - context->encoder_ctx->qcompress = 0;//0.6; // qcomp=0.6 - context->encoder_ctx->qmin = 10; // qmin=10 - context->encoder_ctx->qmax = 51; // qmax=51 - context->encoder_ctx->max_qdiff = 4; // qdiff=4 - */ + context->encoder_ctx->flags |= profile->ctx.flags; // CODEC_FLAG_LOOP_FILTER; // flags=+loop + if (profile->ctx.me_cmp >= 0) context->encoder_ctx->me_cmp = profile->ctx.me_cmp; // cmp=+chroma, where CHROMA = 1 + if (profile->ctx.me_range >= 0) context->encoder_ctx->me_range = profile->ctx.me_range; + if (profile->ctx.max_b_frames >= 0) context->encoder_ctx->max_b_frames = profile->ctx.max_b_frames; + if (profile->ctx.refs >= 0) context->encoder_ctx->refs = profile->ctx.refs; + if (profile->ctx.gop_size >= 0) context->encoder_ctx->gop_size = profile->ctx.gop_size; + if (profile->ctx.keyint_min >= 0) context->encoder_ctx->keyint_min = profile->ctx.keyint_min; + if (profile->ctx.i_quant_factor >= 0) context->encoder_ctx->i_quant_factor = profile->ctx.i_quant_factor; + if (profile->ctx.b_quant_factor >= 0) context->encoder_ctx->b_quant_factor = profile->ctx.b_quant_factor; + if (profile->ctx.qcompress >= 0) context->encoder_ctx->qcompress = profile->ctx.qcompress; + if (profile->ctx.qmin >= 0) context->encoder_ctx->qmin = profile->ctx.qmin; + if (profile->ctx.qmax >= 0) context->encoder_ctx->qmax = profile->ctx.qmax; + if (profile->ctx.max_qdiff >= 0) context->encoder_ctx->max_qdiff = profile->ctx.max_qdiff; } } @@ -999,7 +1050,7 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag { int encoding, decoding; h264_codec_context_t *context = NULL; - int threads = switch_core_cpu_count(); + avcodec_profile_t *profile = NULL; encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); decoding = (flags & SWITCH_CODEC_FLAG_DECODE); @@ -1022,12 +1073,17 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag if (!strcmp(codec->implementation->iananame, "H263")) { context->av_codec_id = AV_CODEC_ID_H263; + profile = &avcodec_globals.profiles[get_codec_index("H263")]; } else if (!strcmp(codec->implementation->iananame, "H263-1998")) { context->av_codec_id = AV_CODEC_ID_H263P; + profile = &avcodec_globals.profiles[get_codec_index("H263+")]; } else { context->av_codec_id = AV_CODEC_ID_H264; + profile = &avcodec_globals.profiles[get_codec_index("H264")]; } + switch_assert(profile); + if (decoding) { context->decoder = avcodec_find_decoder(context->av_codec_id); @@ -1042,11 +1098,9 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "codec: id=%d %s\n", context->decoder->id, context->decoder->long_name); - - if (threads > 4) threads = 4; context->decoder_ctx = avcodec_alloc_context3(context->decoder); - //context->decoder_ctx->thread_count = threads; + context->decoder_ctx->thread_count = profile->decoder_thread_count; if (avcodec_open2(context->decoder_ctx, context->decoder, NULL) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error openning codec\n"); goto error; @@ -1247,6 +1301,10 @@ GCC_DIAG_ON(deprecated-declarations) while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */ context->nalus[i].start = p; context->nalus[i].eat = p; + + if (mod_av_globals.debug && (*p & 0x1f) == 7) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "KEY FRAME GENERATED\n"); + } } else { context->nalus[i].len = p - context->nalus[i].start; while (!(*p++)) ; /* eat the sync bytes, what ever 0 0 1 or 0 0 0 1 */ @@ -1558,10 +1616,302 @@ void show_codecs(switch_stream_handle_t *stream) av_free(codecs); } +#define UINTVAL(v) (v > 0 ? v : 0); + +static void load_config() +{ + switch_xml_t cfg = NULL, xml = NULL; + int i; + + switch_set_string(avcodec_globals.profiles[get_codec_index("H263")].name, "H263"); + switch_set_string(avcodec_globals.profiles[get_codec_index("H263+")].name, "H263+"); + switch_set_string(avcodec_globals.profiles[get_codec_index("H264")].name, "H264"); + switch_set_string(avcodec_globals.profiles[get_codec_index("H265")].name, "H265"); + + for (i = 0; i < MAX_CODECS; i++) { + avcodec_profile_t *profile = &avcodec_globals.profiles[i]; + + profile->ctx.colorspace = AVCOL_SPC_RGB; + profile->ctx.color_range = AVCOL_RANGE_JPEG; + profile->ctx.flags = 0; + profile->ctx.me_cmp = -1; + profile->ctx.me_range = -1; + profile->ctx.max_b_frames = -1; + profile->ctx.refs = -1; + profile->ctx.gop_size = -1; + profile->ctx.keyint_min = -1; + profile->ctx.i_quant_factor = -1; + profile->ctx.b_quant_factor = -1; + profile->ctx.qcompress = -1; + profile->ctx.qmin = -1; + profile->ctx.qmax = -1; + profile->ctx.max_qdiff = -1; + + profile->x264.sc_threshold = 0; + profile->x264.b_strategy = 0; + profile->x264.crf = 0; + + if (!strcasecmp(CODEC_MAPS[i], "H264")) { + profile->ctx.profile = FF_PROFILE_H264_BASELINE; + profile->ctx.level = 41; + } + } + + avcodec_globals.max_bitrate = 0; + + xml = switch_xml_open_cfg("avcodec.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")) { + avcodec_globals.max_bitrate = switch_parse_bandwidth_string(value); + } else if (!strcmp(name, "rtp-slice-size")) { + int val = atoi(value); + avcodec_globals.rtp_slice_size = UINTVAL(val); + } else if (!strcmp(name, "key-frame-min-freq")) { + int val = atoi(value); + avcodec_globals.key_frame_min_freq = UINTVAL(val); + avcodec_globals.key_frame_min_freq *= 1000; + } else if (!strcmp(name, "dec-threads")) { + int i; + uint threads = switch_parse_cpu_string(value); + + for (i = 0; i < MAX_CODECS; i++) { + avcodec_globals.profiles[i].decoder_thread_count = threads; + } + } else if (!strcmp(name, "enc-threads")) { + int i; + uint threads = switch_parse_cpu_string(value); + + for (i = 0; i < MAX_CODECS; i++) { + avcodec_globals.profiles[i].ctx.thread_count = threads; + } + } else if (!strcasecmp(name, "h263-profile")) { + switch_set_string(avcodec_globals.profiles[get_codec_index("H263")].name, value); + } else if (!strcasecmp(name, "h263+-profile")) { + switch_set_string(avcodec_globals.profiles[get_codec_index("H263+")].name, value); + } else if (!strcasecmp(name, "h264-profile")) { + switch_set_string(avcodec_globals.profiles[get_codec_index("H264")].name, value); + } else if (!strcasecmp(name, "h265-profile")) { + switch_set_string(avcodec_globals.profiles[get_codec_index("H265")].name, 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"); + avcodec_profile_t *aprofile = NULL; + AVCodecContext *ctx = NULL; + int i; + + if (zstr(profile_name)) continue; + + for (i = 0; i < MAX_CODECS; i++) { + if (!strcmp(profile_name, avcodec_globals.profiles[i].name)) { + aprofile = &avcodec_globals.profiles[i]; + ctx = &aprofile->ctx; + break; + } + } + + if (!ctx) continue; + + 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 (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")) { + aprofile->decoder_thread_count = switch_parse_cpu_string(value); + } else if (!strcmp(name, "enc-threads")) { + ctx->thread_count = switch_parse_cpu_string(value); + } else if (!strcmp(name, "profile")) { + ctx->profile = UINTVAL(val); + + if (ctx->profile == 0 && !strcasecmp(CODEC_MAPS[i], "H264")) { + if (!strcasecmp(value, "baseline")) { + ctx->profile = FF_PROFILE_H264_BASELINE; + } else if (!strcasecmp(value, "main")) { + ctx->profile = FF_PROFILE_H264_MAIN; + } else if (!strcasecmp(value, "high")) { + ctx->profile = FF_PROFILE_H264_HIGH; + } + } + } else if (!strcmp(name, "level")) { + ctx->level = UINTVAL(val); + } else if (!strcmp(name, "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) { + ctx->time_base.num = num; + ctx->time_base.den = den; + } + } else if (!strcmp(name, "preset")) { + switch_set_string(aprofile->x264.preset, value); + } else if (!strcmp(name, "flags")) { + char *s = strdup(value); + int flags = 0; + + if (s) { + int argc; + char *argv[20]; + int i; + + argc = switch_separate_string(s, '|', argv, (sizeof(argv) / sizeof(argv[0]))); + + for (i = 0; i < argc; i++) { + if (!strcasecmp(argv[i], "UNALIGNED")) { + flags |= AV_CODEC_FLAG_UNALIGNED; + } else if (!strcasecmp(argv[i], "QSCALE")) { + flags |= AV_CODEC_FLAG_QSCALE; + } else if (!strcasecmp(argv[i], "QSCALE")) { + flags |= AV_CODEC_FLAG_QSCALE; + } else if (!strcasecmp(argv[i], "4MV")) { + flags |= AV_CODEC_FLAG_4MV; + } else if (!strcasecmp(argv[i], "CORRUPT")) { + flags |= AV_CODEC_FLAG_OUTPUT_CORRUPT; + } else if (!strcasecmp(argv[i], "QPEL")) { + flags |= AV_CODEC_FLAG_QPEL; + } else if (!strcasecmp(argv[i], "PASS1")) { + flags |= AV_CODEC_FLAG_PASS1; + } else if (!strcasecmp(argv[i], "PASS2")) { + flags |= AV_CODEC_FLAG_PASS2; + } else if (!strcasecmp(argv[i], "FILTER")) { + flags |= AV_CODEC_FLAG_LOOP_FILTER; + } else if (!strcasecmp(argv[i], "GRAY")) { + flags |= AV_CODEC_FLAG_GRAY; + } else if (!strcasecmp(argv[i], "PSNR")) { + flags |= AV_CODEC_FLAG_PSNR; + } else if (!strcasecmp(argv[i], "TRUNCATED")) { + flags |= AV_CODEC_FLAG_TRUNCATED; + } else if (!strcasecmp(argv[i], "INTERLACED_DCT")) { + flags |= AV_CODEC_FLAG_INTERLACED_DCT; + } else if (!strcasecmp(argv[i], "LOW_DELAY")) { + flags |= AV_CODEC_FLAG_LOW_DELAY; + } else if (!strcasecmp(argv[i], "HEADER")) { + flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + } else if (!strcasecmp(argv[i], "BITEXACT")) { + flags |= AV_CODEC_FLAG_BITEXACT; + } else if (!strcasecmp(argv[i], "AC_PRED")) { + flags |= AV_CODEC_FLAG_AC_PRED; + } else if (!strcasecmp(argv[i], "INTERLACED_ME")) { + flags |= AV_CODEC_FLAG_INTERLACED_ME; + } else if (!strcasecmp(argv[i], "CLOSED_GOP")) { + flags |= AV_CODEC_FLAG_CLOSED_GOP; + } + } + + free(s); + ctx->flags = flags; + } + } else if (!strcmp(name, "me-cmp")) { + ctx->me_cmp = UINTVAL(val); + } else if (!strcmp(name, "me-range")) { + ctx->me_range = UINTVAL(val); + } else if (!strcmp(name, "max-b-frames")) { + ctx->max_b_frames = UINTVAL(val); + } else if (!strcmp(name, "refs")) { + ctx->refs = UINTVAL(val); + } else if (!strcmp(name, "gop-size")) { + ctx->gop_size = UINTVAL(val); + } else if (!strcmp(name, "keyint-min")) { + ctx->keyint_min = UINTVAL(val); + } else if (!strcmp(name, "i-quant-factor")) { + ctx->i_quant_factor = UINTVAL(val); + } else if (!strcmp(name, "b-quant-factor")) { + ctx->b_quant_factor = UINTVAL(val); + } else if (!strcmp(name, "qcompress")) { + ctx->qcompress = UINTVAL(val); + } else if (!strcmp(name, "qmin")) { + ctx->qmin = UINTVAL(val); + } else if (!strcmp(name, "qmax")) { + ctx->qmax = UINTVAL(val); + } else if (!strcmp(name, "max-qdiff")) { + ctx->max_qdiff = UINTVAL(val); + } else if (!strcmp(name, "colorspace")) { + ctx->colorspace = UINTVAL(val); + + if (ctx->colorspace > AVCOL_SPC_NB) { + ctx->colorspace = AVCOL_SPC_RGB; + } + } else if (!strcmp(name, "color-range")) { + ctx->color_range = UINTVAL(val); + + if (ctx->color_range > AVCOL_RANGE_NB) { + ctx->color_range = 0; + } + } else if (!strcmp(name, "x264-preset")) { + switch_set_string(aprofile->x264.preset, value); + } else if (!strcmp(name, "x264-tune")) { + switch_set_string(aprofile->x264.tune, value); + } else if (!strcmp(name, "x264-sc-threshold")) { + aprofile->x264.sc_threshold = UINTVAL(val); + } else if (!strcmp(name, "x264-b-strategy")) { + aprofile->x264.b_strategy = UINTVAL(val); + } else if (!strcmp(name, "x264-crf")) { + aprofile->x264.crf = UINTVAL(val); + } + } // for param + } // for profile + } // profiles + + switch_xml_free(xml); + } // xml + + if (avcodec_globals.max_bitrate <= 0) { + avcodec_globals.max_bitrate = switch_calc_bitrate(1920, 1080, 5, 60); + } + + if (avcodec_globals.rtp_slice_size < 500 || avcodec_globals.rtp_slice_size > 1500) { + avcodec_globals.rtp_slice_size = SWITCH_DEFAULT_VIDEO_SIZE; + } + + SLICE_SIZE = avcodec_globals.rtp_slice_size; + + if (avcodec_globals.key_frame_min_freq < 10000 || avcodec_globals.key_frame_min_freq > 3 * 1000000) { + avcodec_globals.key_frame_min_freq = KEY_FRAME_MIN_FREQ; + } +} + SWITCH_MODULE_LOAD_FUNCTION(mod_avcodec_load) { switch_codec_interface_t *codec_interface; + memset(&avcodec_globals, 0, sizeof(struct avcodec_globals)); + load_config(); + SWITCH_ADD_CODEC(codec_interface, "H264 Video"); switch_core_codec_add_video_implementation(pool, codec_interface, 99, "H264", NULL, switch_h264_init, switch_h264_encode, switch_h264_decode, switch_h264_control, switch_h264_destroy);