关键帧是自带全部解码信息的独立视频帧,解码时无需参考其他图像,只需要本帧数据就可以完成。关键帧的设置会影响视频编解码效率和数据空间占用。
发送端在调用 agora_rtc_send_video_data
(C API)或 sendVideoData
(Java API)方法发送视频帧时通过 video_frame_info_t.type
或 VideoFrameInfo.type
参数告知 SDK 该视频帧是否为关键帧。
示例代码如下:
C 示例代码
// C
static connection_id_t g_conn_id;
video_frame_info_t info;
info.type = frame.u.video.is_key_frame ? VIDEO_FRAME_KEY : VIDEO_FRAME_DELTA;
info.frames_per_sec = config->send_video_frame_rate;
info.data_type = config->video_data_type;
int ret = mRtcService.sendVideoData(CONN_ID, videoBuffer, videoFrameInfo);
Java 示例代码
// Java
int streamId = 0;
VideoFrameInfo videoFrameInfo = new VideoFrameInfo();
videoFrameInfo.video_data_type = VideoDataType.VIDEO_DATA_TYPE_H264;
videoFrameInfo.type = VideoFrameType.VIDEO_FRAME_KEY;
videoFrameInfo.frameRate = VideoFrameRate.VIDEO_FRAME_RATE_FPS_15;
int ret = mRtcService.sendVideoData(mChannelName, streamId, videoBuffer, videoFrameInfo);
一帧视频数据被分成数包发送后,在弱网条件下很可能发生数据包丢失,导致接收端无法还原视频帧,从而发生丢帧。如果不加以处理则通常接收端将无法解码该 GOP 内的后续 P 帧,使得视频画面停滞,或解码失败出现花屏、绿屏等问题。
发送端长时间没有发送关键帧、关键帧丢失或损坏时,SDK 会通过 on_key_frame_gen_req
回调告知发送端为指定的视频流编码一个新的关键帧。
示例代码如下:
C 示例代码
// C
static void __on_key_frame_gen_req(connection_id_t conn_id, uint32_t uid, video_stream_type_e stream_type)
{
// 发送端为指定的视频流编码一个新的关键帧
printf("[conn-%u] Frame loss detected. Please notify the encoder to generate key frame immediately\n", conn_id);
}
Java 示例代码
// Java
@Override
public void onKeyFrameGenReq(int connId, int requestedUid, int streamType) {
// 发送端为指定的视频流编码一个新的关键帧
}
接收端解码出错时,可主动调用 agora_rtc_request_video_key_frame
方法请求关键帧。
示例代码如下,仅供参考:
C 示例代码
// C
agora_rtc_request_video_key_frame(conn_id, uid, stream_type);
Java 示例代码
// Java
mRtcService.requestVideoKeyFrame(connId, uid, stream_id);
参考以下语言的接口文档。
为了提升用户体验,我们建议视频编码器定期主动编码关键帧。