diff --git a/src/plumbing/transcoding.c b/src/plumbing/transcoding.c index ed6f4e2e..271d16aa 100644 --- a/src/plumbing/transcoding.c +++ b/src/plumbing/transcoding.c @@ -1037,8 +1037,15 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt) octx->qmin = 1; octx->qmax = FF_LAMBDA_MAX; - octx->bit_rate = 2 * octx->width * octx->height; - octx->rc_max_rate = 4 * octx->bit_rate; + if (t->t_props.tp_vbitrate == 0) { + octx->bit_rate = 2 * octx->width * octx->height; + octx->rc_max_rate = 4 * octx->bit_rate; + + } else { + octx->bit_rate = t->t_props.tp_vbitrate * 1000; + octx->rc_max_rate = octx->bit_rate * 1.05; + } + octx->rc_buffer_size = 2 * octx->rc_max_rate; break; @@ -1046,14 +1053,17 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt) octx->codec_id = AV_CODEC_ID_VP8; octx->pix_fmt = PIX_FMT_YUV420P; - octx->qmin = 10; - octx->qmax = 20; - av_dict_set(&opts, "quality", "realtime", 0); - octx->bit_rate = 3 * octx->width * octx->height; + if (t->t_props.tp_vbitrate == 0) { + octx->qmin = 10; + octx->qmax = 20; + } else { + octx->bit_rate = t->t_props.tp_vbitrate * 1000; + octx->rc_max_rate = octx->bit_rate * 1.05; + } + octx->rc_buffer_size = 8 * 1024 * 224; - octx->rc_max_rate = 2 * octx->bit_rate; break; case SCT_H264: @@ -1072,18 +1082,25 @@ transcoder_stream_video(transcoder_t *t, transcoder_stream_t *ts, th_pkt_t *pkt) // Minimum quantizer. Doesn't need to be changed. // Recommended default: -qmin 10 - octx->qmin = 10; + // octx->qmin = 10; // Maximum quantizer. Doesn't need to be changed. // Recommended default: -qmax 51 - octx->qmax = 30; + // octx->qmax = 30; av_dict_set(&opts, "preset", "medium", 0); av_dict_set(&opts, "profile", "baseline", 0); + av_dict_set(&opts, "tune", "zerolatency", 0); + + if (t->t_props.tp_vbitrate == 0) { + octx->qmin = 10; + octx->qmax = 30; + } else { + octx->bit_rate = t->t_props.tp_vbitrate * 1000; + octx->rc_max_rate = octx->bit_rate * 1.05; + } - octx->bit_rate = 2 * octx->width * octx->height; octx->rc_buffer_size = 8 * 1024 * 224; - octx->rc_max_rate = 2 * octx->rc_buffer_size; break; default: @@ -1749,6 +1766,7 @@ transcoder_set_properties(streaming_target_t *st, strncpy(tp->tp_scodec, props->tp_scodec, sizeof(tp->tp_scodec)-1); tp->tp_channels = props->tp_channels; tp->tp_bandwidth = props->tp_bandwidth; + tp->tp_vbitrate = props->tp_vbitrate; tp->tp_resolution = props->tp_resolution; memcpy(tp->tp_language, props->tp_language, 4); diff --git a/src/plumbing/transcoding.h b/src/plumbing/transcoding.h index bbd028fa..81c04e8d 100644 --- a/src/plumbing/transcoding.h +++ b/src/plumbing/transcoding.h @@ -27,6 +27,7 @@ typedef struct transcoder_prop { int8_t tp_channels; int32_t tp_bandwidth; + int32_t tp_vbitrate; char tp_language[4]; int32_t tp_resolution; diff --git a/src/profile.c b/src/profile.c index 4795b244..52ed730b 100644 --- a/src/profile.c +++ b/src/profile.c @@ -1019,6 +1019,7 @@ typedef struct profile_transcode { uint32_t pro_resolution; uint32_t pro_channels; uint32_t pro_bandwidth; + uint32_t pro_vbitrate; char *pro_language; char *pro_vcodec; char *pro_acodec; @@ -1214,6 +1215,13 @@ const idclass_t profile_transcode_class = .def.s = "libx264", .list = profile_class_vcodec_list, }, + { + .type = PT_U32, + .id = "vbitrate", + .name = "Video Bitrate (kb/s) (0=Auto)", + .off = offsetof(profile_transcode_t, pro_vbitrate), + .def.u32 = 0, + }, { .type = PT_STR, .id = "acodec", @@ -1246,6 +1254,12 @@ profile_transcode_bandwidth(profile_transcode_t *pro) return pro->pro_bandwidth >= 64 ? pro->pro_bandwidth : 64; } +static int +profile_transcode_vbitrate(profile_transcode_t *pro) +{ + return pro->pro_vbitrate; +} + static int profile_transcode_can_share(profile_chain_t *prch, profile_chain_t *joiner) @@ -1270,6 +1284,8 @@ profile_transcode_can_share(profile_chain_t *prch, return 0; if (profile_transcode_bandwidth(pro1) != profile_transcode_bandwidth(pro2)) return 0; + if (profile_transcode_vbitrate(pro1) != profile_transcode_vbitrate(pro2)) + return 0; if (strcmp(pro1->pro_language ?: "", pro2->pro_language ?: "")) return 0; return 1; @@ -1297,6 +1313,7 @@ profile_transcode_work(profile_chain_t *prch, props.tp_resolution = profile_transcode_resolution(pro); props.tp_channels = pro->pro_channels; props.tp_bandwidth = profile_transcode_bandwidth(pro); + props.tp_vbitrate = profile_transcode_vbitrate(pro); strncpy(props.tp_language, pro->pro_language ?: "", 3); dst = prch->prch_gh = globalheaders_create(dst); @@ -1506,6 +1523,7 @@ profile_init(void) htsmsg_add_u32 (conf, "resolution", 384); htsmsg_add_u32 (conf, "channels", 2); htsmsg_add_str (conf, "vcodec", "libvpx"); + htsmsg_add_str (conf, "vbitrate", 0); htsmsg_add_str (conf, "acodec", "libvorbis"); htsmsg_add_bool(conf, "shield", 1); (void)profile_create(NULL, conf, 1); @@ -1525,6 +1543,7 @@ profile_init(void) htsmsg_add_u32 (conf, "resolution", 384); htsmsg_add_u32 (conf, "channels", 2); htsmsg_add_str (conf, "vcodec", "libx264"); + htsmsg_add_str (conf, "vbitrate", 0); htsmsg_add_str (conf, "acodec", "aac"); htsmsg_add_bool(conf, "shield", 1); (void)profile_create(NULL, conf, 1); @@ -1544,6 +1563,7 @@ profile_init(void) htsmsg_add_u32 (conf, "resolution", 384); htsmsg_add_u32 (conf, "channels", 2); htsmsg_add_str (conf, "vcodec", "libx264"); + htsmsg_add_str (conf, "vbitrate", 0); htsmsg_add_str (conf, "acodec", "aac"); htsmsg_add_bool(conf, "shield", 1); (void)profile_create(NULL, conf, 1);