P帧 帧内刷新Intra refresh简介帧内刷新能够解决IDR过大带来的码流不平稳问题传统的视频码流通常是IPPPIPPP码流结构即每个GOP的第一帧为全Intra predicted(I 帧)当某个帧丢包会导致这个GOP内后续的帧解码错误等到下一个GOP视频才能恢复正常这种GOP结构码率不够平稳在I帧的时候码率会突然变的很高不利于网络传输。帧内刷新技术可以使码率平稳降低码流传输时延并且仍然可以在传输出错的情况下快速恢复。帧内刷新原理传统的 H.264 编码是周期性插入IDR 帧关键帧IDR帧全部以 I slice编码后续P帧参考IDR帧以及前一个P帧以无B帧的场景为例P帧会根据前后场景变化决定内部某个宏块编码I slice还是p slice但大部分宏块还是会编码成p slice。P帧帧内刷新则是设置超长的GOP然后在一个刷新周期内非GOP长度把所有宏块都以I slice刷新一遍像一条“刷新带”逐渐扫描整个画面比如图像有1024行刷新周期是16则第一个P帧会把前64行编码成I slice第二个P帧会把65到128行编码成I slice以此类推最终在连续的16个P帧里完成完整画面的刷新。在每一帧中只将图像中的一部分行/列/区域编码为 I 宏块其余部分仍为 P 宏块。经过若干帧后所有区域都被轮换刷新过一次整幅图像完成一个刷新周期。如图所示假设刷新周期为第一帧的第一个条带编码为I宏块第二帧的第二个条带编码为I宏块直到第四帧的第四个条带此时完成一轮刷新。当然这些帧都是帧。帧内刷新的优点、码率稳定。所有的帧由于都有一条区域使用帧内预测模式其他区域运行率失真优化选择最优模式因此每个帧的大小波动不会太大。、降低时延。时延降低主要体现在没有帧上帧通常较大在网络传输的时候需要将一帧分成很多个包来传输而在解码端必须等所有的包都到达后才能开始解码所以帧是造成视频码流传输时延大的主要原因也就是说瓶颈在帧这里。在帧内刷新技术上虽然帧比传统结构的帧要大一些但总体趋于平稳并且比帧要小很多因此可以快速传完一帧并解码。根本上来讲其实就是类似传输一个大文件耗时较长而小文件较快。、关于错误恢复这一点想了很久才明白。我们先考虑一种恢复较快的情况即运动向量是的情况每一帧中的区块都是参考其前一帧的相应位置的块。假设第一帧丢失那么第二帧只有第二条区域可以正常解码第三帧的第二条参考第二帧的第二条那么第三帧的第二条和第三条可以正常解码同理第四帧的二、三、四条可以正常解码到第五帧时整个帧都可以正常解码至此视频恢复正常播放只需要一个刷新周期就恢复了。再来考虑极端情况还是从第二帧开始第二帧只有第二条正常解码加入第三帧的除第三条外的其他区域都是参考的第二帧的非第二条区域那么第三帧就只有第三条可以正常解码同理第四帧只有第四条正常这样是永远也无法恢复的。但是现实是不可能这样的总有参考到前一帧的帧内刷新条上的块这样正常的块就会越来越多从而慢慢恢复正常。注意事项1、参数 KEY_INTRA_REFRESH_PERIOD 需要配合 CBR使用在恒定码率CBR下它可以有效消除 I 帧的巨量峰值使得网络传输更友好。但解码端若要完全恢复画面需等待一个完整刷新周期相比 IDR 瞬时刷新随机访问延迟会增加。2、因为不再有 IDR 帧解码器不能从任意点开始解码。大多数实时通信方案会在码流中插入恢复点 SEIRecovery Point SEI告诉解码器“从这一帧开始解码将在 N 帧后得到正确图像”。这也是刷新周期的重要依据。3、帧内刷新常常与GOP 无限长、无 B 帧配合使每一帧的编码参考仅限于最近的几帧以达到毫秒级延迟参考代码/*---# P帧帧内刷新降低 I 帧过大带来的网络冲击------------------------------------------------------------*/VENC_INTRA_REFRESH_S pstIntraRefresh;ret HI_MPI_VENC_GetIntraRefresh(encChn,pstIntraRefresh);if (HI_SUCCESS ! ret){ERROR_LOG(HI_MPI_VENC_GetIntraRefresh (%d) fail: %#x!\n, encChn, ret);return HLE_RET_ERROR;}pstIntraRefresh.bRefreshEnable HI_TRUE;pstIntraRefresh.enIntraRefreshMode INTRA_REFRESH_ROW; //按行刷新/*满足条件u32RefreshNum * MaxRefreshFrameInGop (u32PicHeight15)/16;其中无高级跳帧参考时MaxRefreshFrameInGop Gop(30),则u32RefreshNum (u32PicHeight15)/(16*MaxRefreshFrameInGop)1920*1080: (u32PicHeight15)/(16*MaxRefreshFrameInGop) (108015)/(16*30) 2.281960*544: (u32PicHeight15)/(16*MaxRefreshFrameInGop) (54415)/(16*30) 1.164所以主码流通道,u32RefreshNum 取 3次码流通道,u32RefreshNum 取 2*/pstIntraRefresh.u32RefreshNum (0 stream_index)? 3 : 2;pstIntraRefresh.u32ReqIQp 40;ret HI_MPI_VENC_SetIntraRefresh(encChn,pstIntraRefresh);if (HI_SUCCESS ! ret){ERROR_LOG(HI_MPI_VENC_SetIntraRefresh (%d) fail: %#x!\n, encChn, ret);return HLE_RET_ERROR;}