FS-11425 refactor to parse profiles dynamicly to possible to support more profiles

This commit is contained in:
Seven Du 2018-10-01 14:56:00 +08:00 committed by Andrey Volk
parent 807efbd0fa
commit 2a6fb572af
2 changed files with 97 additions and 106 deletions

View File

@ -11,10 +11,6 @@
<!-- integer of cpus, or 'auto', or 'cpu/<divisor>/<max> --> <!-- integer of cpus, or 'auto', or 'cpu/<divisor>/<max> -->
<param name="dec-threads" value="1"/> <param name="dec-threads" value="1"/>
<param name="enc-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> </settings>
<profiles> <profiles>
@ -28,7 +24,7 @@
<!-- <param name="dec-threads" value="cpu/2/4"/> --> <!-- <param name="dec-threads" value="cpu/2/4"/> -->
<!-- <param name="enc-threads" value="1"/> --> <!-- <param name="enc-threads" value="1"/> -->
<!-- <param name="profile" value="2"/> --> <!-- <param name="profile" value="baseline"/> -->
<!-- <param name="level" value="41"/> --> <!-- <param name="level" value="41"/> -->
<!-- <param name="timebase" value="1/90"/> --> <!-- <param name="timebase" value="1/90"/> -->

View File

@ -406,7 +406,7 @@ typedef struct h264_codec_context_s {
static uint8_t ff_input_buffer_padding[AV_INPUT_BUFFER_PADDING_SIZE] = { 0 }; static uint8_t ff_input_buffer_padding[AV_INPUT_BUFFER_PADDING_SIZE] = { 0 };
#define MAX_CODECS 4 #define MAX_PROFILES 100
typedef struct avcodec_profile_s { typedef struct avcodec_profile_s {
char name[20]; char name[20];
@ -420,32 +420,83 @@ struct avcodec_globals {
uint32_t max_bitrate; uint32_t max_bitrate;
uint32_t rtp_slice_size; uint32_t rtp_slice_size;
uint32_t key_frame_min_freq; uint32_t key_frame_min_freq;
uint32_t enc_threads;
uint32_t dec_threads;
avcodec_profile_t profiles[MAX_CODECS]; avcodec_profile_t *profiles[MAX_PROFILES];
}; };
struct avcodec_globals avcodec_globals = { 0 }; struct avcodec_globals avcodec_globals = { 0 };
char *CODEC_MAPS[] = { const char *get_profile_name(int codec_id)
"H263", {
"H263+", switch (codec_id) {
"H264", case AV_CODEC_ID_H263: return "H263";
"H265", case AV_CODEC_ID_H263P: return "H263+";
NULL case AV_CODEC_ID_H264: return "H264";
}; case AV_CODEC_ID_H265: return "H265";
}
static int get_codec_index(const char *cstr) return "NONE";
}
static void init_profile(avcodec_profile_t *aprofile, const char *name);
static avcodec_profile_t *find_profile(const char *name, switch_bool_t reconfig)
{ {
int i; int i;
for (i = 0; ; i++) { for (i = 0; i < MAX_PROFILES; i++) {
if (!strcasecmp(cstr, CODEC_MAPS[i])) { if (!avcodec_globals.profiles[i]) {
return i; avcodec_globals.profiles[i] = malloc(sizeof(avcodec_profile_t));
switch_assert(avcodec_globals.profiles[i]);
memset(avcodec_globals.profiles[i], 0, sizeof(avcodec_profile_t));
init_profile(avcodec_globals.profiles[i], name);
return avcodec_globals.profiles[i];
}
if (!strcmp(name, avcodec_globals.profiles[i]->name)) {
if (reconfig) init_profile(avcodec_globals.profiles[i], name);
return avcodec_globals.profiles[i];
} }
} }
abort(); return NULL;
return -1; }
#define UINTVAL(v) (v > 0 ? v : 0);
static void init_profile(avcodec_profile_t *aprofile, const char *name)
{
switch_set_string(aprofile->name, name);
aprofile->ctx.colorspace = AVCOL_SPC_RGB;
aprofile->ctx.color_range = AVCOL_RANGE_JPEG;
aprofile->ctx.flags = 0;
aprofile->ctx.me_cmp = -1;
aprofile->ctx.me_range = -1;
aprofile->ctx.max_b_frames = -1;
aprofile->ctx.refs = -1;
aprofile->ctx.gop_size = -1;
aprofile->ctx.keyint_min = -1;
aprofile->ctx.i_quant_factor = -1;
aprofile->ctx.b_quant_factor = -1;
aprofile->ctx.qcompress = -1;
aprofile->ctx.qmin = -1;
aprofile->ctx.qmax = -1;
aprofile->ctx.max_qdiff = -1;
aprofile->ctx.thread_count = avcodec_globals.enc_threads;
aprofile->decoder_thread_count = avcodec_globals.dec_threads;
if (!strcasecmp(name, "H264")) {
aprofile->ctx.profile = FF_PROFILE_H264_BASELINE;
aprofile->ctx.level = 41;
#ifdef AV_CODEC_FLAG_PSNR
aprofile->ctx.flags |= AV_CODEC_FLAG_PSNR;
#endif
#ifdef CODEC_FLAG_LOOP_FILTER
aprofile->ctx.flags |= CODEC_FLAG_LOOP_FILTER;
#endif
}
} }
static switch_status_t buffer_h264_nalu(h264_codec_context_t *context, switch_frame_t *frame) static switch_status_t buffer_h264_nalu(h264_codec_context_t *context, switch_frame_t *frame)
@ -1160,17 +1211,7 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
if (context->av_codec_id == AV_CODEC_ID_H263) { profile = find_profile(get_profile_name(context->av_codec_id), SWITCH_FALSE);
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")];
#ifdef AV_CODEC_ID_H265
} else if (context->av_codec_id == AV_CODEC_ID_H265) {
profile = &avcodec_globals.profiles[get_codec_index("H265")];
#endif
}
if (!profile) return SWITCH_STATUS_FALSE; if (!profile) return SWITCH_STATUS_FALSE;
@ -1320,16 +1361,17 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag
if (!strcmp(codec->implementation->iananame, "H263")) { if (!strcmp(codec->implementation->iananame, "H263")) {
context->av_codec_id = AV_CODEC_ID_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")) { } else if (!strcmp(codec->implementation->iananame, "H263-1998")) {
context->av_codec_id = AV_CODEC_ID_H263P; context->av_codec_id = AV_CODEC_ID_H263P;
profile = &avcodec_globals.profiles[get_codec_index("H263+")];
} else { } else {
context->av_codec_id = AV_CODEC_ID_H264; context->av_codec_id = AV_CODEC_ID_H264;
profile = &avcodec_globals.profiles[get_codec_index("H264")];
} }
switch_assert(profile); profile = find_profile(get_profile_name(context->av_codec_id), SWITCH_FALSE);
if (!profile) {
goto error;
}
if (decoding) { if (decoding) {
context->decoder = avcodec_find_decoder(context->av_codec_id); context->decoder = avcodec_find_decoder(context->av_codec_id);
@ -1869,8 +1911,6 @@ void show_codecs(switch_stream_handle_t *stream)
av_free(codecs); av_free(codecs);
} }
#define UINTVAL(v) (v > 0 ? v : 0);
static void parse_profile(switch_xml_t profile) static void parse_profile(switch_xml_t profile)
{ {
switch_xml_t options = switch_xml_child(profile, "options"); switch_xml_t options = switch_xml_child(profile, "options");
@ -1878,18 +1918,18 @@ static void parse_profile(switch_xml_t profile)
const char *profile_name = switch_xml_attr(profile, "name"); const char *profile_name = switch_xml_attr(profile, "name");
avcodec_profile_t *aprofile = NULL; avcodec_profile_t *aprofile = NULL;
AVCodecContext *ctx = NULL; AVCodecContext *ctx = NULL;
int i;
if (zstr(profile_name)) return; if (zstr(profile_name)) return;
for (i = 0; i < MAX_CODECS; i++) { aprofile = find_profile(profile_name, SWITCH_TRUE);
if (!strcmp(profile_name, avcodec_globals.profiles[i].name)) {
aprofile = &avcodec_globals.profiles[i]; if (!aprofile) {
ctx = &aprofile->ctx; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot find profile %s\n", profile_name);
break; return;
}
} }
ctx = &aprofile->ctx;
if (!ctx) return; if (!ctx) return;
for (param = switch_xml_child(profile, "param"); param; param = param->next) { for (param = switch_xml_child(profile, "param"); param; param = param->next) {
@ -1913,7 +1953,7 @@ static void parse_profile(switch_xml_t profile)
} else if (!strcmp(name, "profile")) { } else if (!strcmp(name, "profile")) {
ctx->profile = UINTVAL(val); ctx->profile = UINTVAL(val);
if (ctx->profile == 0 && !strcasecmp(CODEC_MAPS[i], "H264")) { if (ctx->profile == 0 && !strcasecmp(aprofile->name, "H264")) {
if (!strcasecmp(value, "baseline")) { if (!strcasecmp(value, "baseline")) {
ctx->profile = FF_PROFILE_H264_BASELINE; ctx->profile = FF_PROFILE_H264_BASELINE;
} else if (!strcasecmp(value, "main")) { } else if (!strcasecmp(value, "main")) {
@ -2097,47 +2137,10 @@ static void parse_profile(switch_xml_t profile)
static void load_config() static void load_config()
{ {
switch_xml_t cfg = NULL, xml = NULL; 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->ctx.thread_count = switch_parse_cpu_string("cpu/2/4");
profile->decoder_thread_count = switch_parse_cpu_string("cpu/2/4");
if (!strcasecmp(CODEC_MAPS[i], "H264")) {
profile->ctx.profile = FF_PROFILE_H264_BASELINE;
profile->ctx.level = 41;
#ifdef AV_CODEC_FLAG_PSNR
profile->ctx.flags |= AV_CODEC_FLAG_PSNR;
#endif
#ifdef CODEC_FLAG_LOOP_FILTER
profile->ctx.flags |= CODEC_FLAG_LOOP_FILTER;
#endif
}
}
avcodec_globals.max_bitrate = 0; avcodec_globals.max_bitrate = 0;
avcodec_globals.dec_threads = 1;
avcodec_globals.enc_threads = switch_parse_cpu_string("cpu/2/4");
xml = switch_xml_open_cfg("avcodec.conf", &cfg, NULL); xml = switch_xml_open_cfg("avcodec.conf", &cfg, NULL);
@ -2164,27 +2167,9 @@ static void load_config()
avcodec_globals.key_frame_min_freq = UINTVAL(val); avcodec_globals.key_frame_min_freq = UINTVAL(val);
avcodec_globals.key_frame_min_freq *= 1000; avcodec_globals.key_frame_min_freq *= 1000;
} else if (!strcmp(name, "dec-threads")) { } else if (!strcmp(name, "dec-threads")) {
int i; avcodec_globals.dec_threads = switch_parse_cpu_string(value);
unsigned int 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")) { } else if (!strcmp(name, "enc-threads")) {
int i; avcodec_globals.enc_threads = switch_parse_cpu_string(value);
unsigned int 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);
} }
} }
} }
@ -2213,6 +2198,12 @@ static void load_config()
if (avcodec_globals.key_frame_min_freq < 10000 || avcodec_globals.key_frame_min_freq > 3 * 1000000) { 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; avcodec_globals.key_frame_min_freq = KEY_FRAME_MIN_FREQ;
} }
// make sure profiles created
find_profile("H263", SWITCH_FALSE);
find_profile("H263+", SWITCH_FALSE);
find_profile("H264", SWITCH_FALSE);
find_profile("H265", SWITCH_FALSE);
} }
SWITCH_MODULE_LOAD_FUNCTION(mod_avcodec_load) SWITCH_MODULE_LOAD_FUNCTION(mod_avcodec_load)
@ -2242,12 +2233,16 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avcodec_shutdown)
{ {
int i; int i;
for (i = 0; i < MAX_CODECS; i++) { for (i = 0; i < MAX_PROFILES; i++) {
avcodec_profile_t *profile = &avcodec_globals.profiles[i]; avcodec_profile_t *profile = avcodec_globals.profiles[i];
if (!profile) break;
if (profile->options) { if (profile->options) {
switch_event_destroy(&profile->options); switch_event_destroy(&profile->options);
} }
free(profile);
} }
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;