Add ability in stream to modify video codec bitrate on the fly (#3556)

This commit is contained in:
sauwming 2023-05-16 13:12:53 +08:00 committed by GitHub
parent 022ce68be9
commit e8f58dd6d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 198 additions and 16 deletions

View File

@ -713,14 +713,15 @@ PJ_INLINE(pj_status_t) pjmedia_vid_codec_close( pjmedia_vid_codec *codec )
/**
* Modify the codec parameter after the codec is open.
* Note that not all codec parameters can be modified during run-time.
* When the parameter cannot be changed, this function will return
* non-PJ_SUCCESS, and the original parameters will not be changed.
* Modify the codec parameter after the codec is opened.
* Note that not all codec backends support modifying parameters during
* runtime and only certain parameters can be changed.
*
* Currently, only Video Toolbox and OpenH264 backends support runtime
* adjustment of encoding bitrate (avg_bps and max_bps).
*
* @param codec The codec instance.
* @param param The new codec parameter. Note that encoding video
* codec resolution must be even numbers.
* @param param The new codec parameter.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/

View File

@ -390,6 +390,24 @@ PJ_DECL(pj_status_t) pjmedia_vid_stream_get_info(
PJ_DECL(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream);
/**
* Modify the video stream's codec parameter after the codec is opened.
* Note that not all codec backends support modifying parameters during
* runtime and only certain parameters can be changed.
*
* Currently, only Video Toolbox and OpenH264 backends support runtime
* adjustment of encoding bitrate (avg_bps and max_bps).
*
* @param stream The video stream.
* @param param The new codec parameter.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_stream_modify_codec_param(pjmedia_vid_stream *stream,
const pjmedia_vid_codec_param *param);
/**
* Query if the stream is started on the specified direction.
*

View File

@ -631,10 +631,41 @@ static pj_status_t oh264_codec_close(pjmedia_vid_codec *codec)
static pj_status_t oh264_codec_modify(pjmedia_vid_codec *codec,
const pjmedia_vid_codec_param *param)
{
struct oh264_codec_data *oh264_data;
int rc;
SBitrateInfo bitrate;
PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
PJ_UNUSED_ARG(codec);
PJ_UNUSED_ARG(param);
return PJ_EINVALIDOP;
oh264_data = (oh264_codec_data*) codec->codec_data;
bitrate.iLayer = SPATIAL_LAYER_ALL;
bitrate.iBitrate = param->enc_fmt.det.vid.avg_bps;
rc = oh264_data->enc->SetOption (ENCODER_OPTION_BITRATE, &bitrate);
if (rc != cmResultSuccess) {
PJ_LOG(4,(THIS_FILE, "OpenH264 encoder SetOption bitrate failed, "
"rc=%d", rc));
return PJMEDIA_CODEC_EUNSUP;
}
oh264_data->prm->enc_fmt.det.vid.avg_bps = param->enc_fmt.det.vid.avg_bps;
bitrate.iBitrate = param->enc_fmt.det.vid.max_bps;
rc = oh264_data->enc->SetOption (ENCODER_OPTION_MAX_BITRATE, &bitrate);
if (rc != cmResultSuccess) {
PJ_LOG(4,(THIS_FILE, "OpenH264 encoder SetOption max bitrate failed, "
"rc=%d", rc));
} else {
oh264_data->prm->enc_fmt.det.vid.max_bps =
param->enc_fmt.det.vid.max_bps;
PJ_LOG(4, (THIS_FILE, "OpenH264 encoder bitrate is modified to "
"%d avg bps and %d max bps",
param->enc_fmt.det.vid.avg_bps,
param->enc_fmt.det.vid.max_bps));
}
return PJ_SUCCESS;
}
static pj_status_t oh264_codec_get_param(pjmedia_vid_codec *codec,
@ -985,7 +1016,7 @@ static pj_status_t oh264_codec_decode(pjmedia_vid_codec *codec,
pj_bool_t has_frame = PJ_FALSE;
pj_bool_t kf_requested = PJ_FALSE;
unsigned buf_pos, whole_len = 0;
unsigned i, frm_cnt;
unsigned i;
pj_status_t status = PJ_SUCCESS;
DECODING_STATE ret;
@ -1051,7 +1082,7 @@ static pj_status_t oh264_codec_decode(pjmedia_vid_codec *codec,
* Step 2: parse the individual NAL and give to decoder
*/
buf_pos = 0;
for ( frm_cnt=0; ; ++frm_cnt) {
while (1) {
unsigned frm_size;
unsigned char *start;

View File

@ -573,6 +573,11 @@ static OSStatus create_encoder(vtool_codec_data *vtool_data)
VTCompressionSessionPrepareToEncodeFrames(vtool_data->enc);
PJ_LOG(4, (THIS_FILE, "Video Toolbox encoder bitrate initialized to "
"%d avg bps and %d max bps",
param->enc_fmt.det.vid.avg_bps,
param->enc_fmt.det.vid.max_bps));
return ret;
}
@ -737,10 +742,36 @@ static pj_status_t vtool_codec_close(pjmedia_vid_codec *codec)
static pj_status_t vtool_codec_modify(pjmedia_vid_codec *codec,
const pjmedia_vid_codec_param *param)
{
struct vtool_codec_data *vtool_data;
OSStatus ret;
PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
PJ_UNUSED_ARG(codec);
PJ_UNUSED_ARG(param);
return PJ_EINVALIDOP;
vtool_data = (vtool_codec_data*) codec->codec_data;
SET_PROPERTY(vtool_data->enc,
kVTCompressionPropertyKey_AverageBitRate,
(__bridge CFTypeRef)@(param->enc_fmt.det.vid.avg_bps));
if (ret != noErr)
return PJMEDIA_CODEC_EUNSUP;
vtool_data->prm->enc_fmt.det.vid.avg_bps = param->enc_fmt.det.vid.avg_bps;
SET_PROPERTY(vtool_data->enc,
kVTCompressionPropertyKey_DataRateLimits,
((__bridge CFArrayRef) // [Bytes, second]
@[@(param->enc_fmt.det.vid.max_bps >> 3), @(1)]));
if (ret == noErr) {
vtool_data->prm->enc_fmt.det.vid.max_bps =
param->enc_fmt.det.vid.max_bps;
PJ_LOG(4, (THIS_FILE, "Video Toolbox encoder bitrate is modified to "
"%d avg bps and %d max bps",
param->enc_fmt.det.vid.avg_bps,
param->enc_fmt.det.vid.max_bps));
}
return PJ_SUCCESS;
}
static pj_status_t vtool_codec_get_param(pjmedia_vid_codec *codec,
@ -1127,7 +1158,7 @@ static pj_status_t vtool_codec_decode(pjmedia_vid_codec *codec,
const int code_size = PJ_ARRAY_SIZE(start_code);
pj_bool_t has_frame = PJ_FALSE;
unsigned buf_pos, whole_len = 0;
unsigned i, frm_cnt;
unsigned i;
pj_status_t status = PJ_SUCCESS;
pj_bool_t decode_whole = DECODE_WHOLE;
OSStatus ret;
@ -1198,7 +1229,7 @@ static pj_status_t vtool_codec_decode(pjmedia_vid_codec *codec,
* Step 2: parse the individual NAL and give to decoder
*/
buf_pos = 0;
for ( frm_cnt=0; ; ++frm_cnt) {
while (1) {
uint32_t frm_size, nalu_type, data_length;
unsigned char *start;

View File

@ -2363,6 +2363,19 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
}
/*
* Modify codec parameter.
*/
PJ_DEF(pj_status_t)
pjmedia_vid_stream_modify_codec_param(pjmedia_vid_stream *stream,
const pjmedia_vid_codec_param *param)
{
PJ_ASSERT_RETURN(stream && param, PJ_EINVAL);
return pjmedia_vid_codec_modify(stream->codec, param);
}
/*
* Check status.
*/

View File

@ -6146,6 +6146,27 @@ PJ_DECL(pj_status_t) pjsua_call_set_vid_strm (
pjsua_call_vid_strm_op op,
const pjsua_call_vid_strm_op_param *param);
/**
* Modify the video stream's codec parameter after the codec is opened.
* Note that not all codec backends support modifying parameters during
* runtime and only certain parameters can be changed.
*
* Currently, only Video Toolbox and OpenH264 backends support runtime
* adjustment of encoding bitrate (avg_bps and max_bps).
*
* @param call_id Call identification.
* @param med_idx Video stream index.
* @param param The new codec parameter.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjsua_call_vid_stream_modify_codec_param(pjsua_call_id call_id,
int med_idx,
const pjmedia_vid_codec_param *param);
/**
* Modify the audio stream's codec parameter after the codec is opened.
* Note that not all codec parameters can be modified during run-time.

View File

@ -1774,6 +1774,22 @@ public:
void vidSetStream(pjsua_call_vid_strm_op op,
const CallVidSetStreamParam &param) PJSUA2_THROW(Error);
/**
* Modify the video stream's codec parameter after the codec is opened.
* Note that not all codec backends support modifying parameters during
* runtime and only certain parameters can be changed.
*
* Currently, only Video Toolbox and OpenH264 backends support runtime
* adjustment of encoding bitrate (avg_bps and max_bps).
*
* @param med_idx Video stream index.
* @param param The new codec parameter.
*
* @return PJ_SUCCESS on success.
*/
void vidStreamModifyCodecParam(int med_idx, const VidCodecParam &param)
PJSUA2_THROW(Error);
/**
* Modify the audio stream's codec parameter after the codec is opened.
* Note that not all codec parameters can be modified during run-time.

View File

@ -2718,6 +2718,43 @@ on_return:
}
/*
* Modify video stream's codec parameters.
*/
PJ_DEF(pj_status_t)
pjsua_call_vid_stream_modify_codec_param(pjsua_call_id call_id,
int med_idx,
const pjmedia_vid_codec_param *param)
{
pjsua_call *call;
pjsua_call_media *call_med;
pj_status_t status;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls &&
med_idx>=0 &&
med_idx<(int)pjsua_var.calls[call_id].med_cnt && param,
PJ_EINVAL);
PJSUA_LOCK();
/* Verify media index */
call = &pjsua_var.calls[call_id];
/* Verify if the media is audio */
call_med = &call->media[med_idx];
if (call_med->type != PJMEDIA_TYPE_VIDEO || !call_med->strm.v.stream) {
PJSUA_UNLOCK();
return PJ_EINVALIDOP;
}
status = pjmedia_vid_stream_modify_codec_param(call_med->strm.v.stream,
param);
PJSUA_UNLOCK();
return status;
}
/*
* Get the media stream index of the default video stream in the call.
*/

View File

@ -879,6 +879,20 @@ void Call::vidSetStream(pjsua_call_vid_strm_op op,
#endif
}
void Call::vidStreamModifyCodecParam(int med_idx, const VidCodecParam &param)
PJSUA2_THROW(Error)
{
#if PJSUA_HAS_VIDEO
pjmedia_vid_codec_param prm = param.toPj();
PJSUA2_CHECK_EXPR( pjsua_call_vid_stream_modify_codec_param(id, med_idx,
&prm) );
#else
PJ_UNUSED_ARG(med_idx);
PJ_UNUSED_ARG(param);
PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
#endif
}
void Call::audStreamModifyCodecParam(int med_idx, const CodecParam &param)
PJSUA2_THROW(Error)
{