android MediaCodec 如何快速seek获取帧
解说正常思路seek到一个时间戳的的前一个I帧,然后进行解码到该时间戳进行显示、或者抽帧需求。
假如你实现上面步骤后,正常是可以在优化的
只说明一种格式
1、h264视频
2、MediaExtractor或者ffmpeg进行读取视频包
优化原理丢弃解码到该seek时间戳之前的非IDR帧:
在H.264视频编码标准中,I帧、P帧和B帧是用于描述视频帧类型和帧间关系的术语。下面是对它们的介绍:
-
I帧(Intra-coded frame):
- I帧也被称为关键帧或独立帧。
- 一个I帧是一个完整的、自包含的视频帧,不依赖于其他帧的信息。
- I帧通常出现在视频序列开头、场景切换或错误恢复时。
- 每个GOP(Group of Pictures,一组连续的帧)的第一个帧都是I帧。
-
P帧(Predictive-coded frame):
- P帧是通过前向预测编码生成的帧。
- P帧需要参考先前的一个或多个I帧或P帧进行解码。
- P帧存储了与之相关的参考帧之间的差异信息,以减小数据量。
- P帧相对于I帧来说,具有更高的压缩效率。
-
B帧(Bi-directional predictive-coded frame):
- B帧是通过双向预测编码生成的帧。
- B帧既参考先前的帧(I帧或P帧),又参考后续的帧(P帧或B帧)。
- B帧存储了与之相关的前后参考帧之间的差异信息,以进一步提高压缩效率。
- B帧相对于P帧来说,具有更高的压缩效率,但也需要更多的计算资源进行解码。
I帧、P帧和B帧共同组成了一个视频序列。通过合理地使用这些帧类型,H.264编码器可以在保持较高质量的同时实现较高的压缩率。在解码时,视频解码器根据帧间关系和参考帧的信息来还原完整的视频序列。
在H.264视频编码标准中,IDR帧(Instantaneous Decoding Refresh)是一种特殊的I帧。下面对IDR帧进行介绍:
-
IDR帧:
- IDR帧也被称为关键刷新帧。
- IDR帧与普通的I帧类似,是一个完整的、自包含的视频帧,不依赖于其他帧的信息。
- 与普通的I帧不同,IDR帧的作用是在解码过程中进行即时解码的刷新点。
- IDR帧常用于场景切换或错误恢复时,可以重新建立解码器的参考帧缓冲区,从而保证后续帧的正确解码。
-
IDR帧和解码过程:
- 当IDR帧出现在视频序列中,解码器会清空其参考帧缓冲区并开始新的GOP(Group of Pictures)。
- IDR帧之后的P帧和B帧将参考该IDR帧进行解码,而不再依赖于之前的帧。
- 这样做可以防止错误传播,并使解码器能够更快地从错误中恢复。
总结来说,IDR帧是一种关键刷新帧,用于在解码过程中重新建立参考帧缓冲区,以确保后续帧的正确解码。它类似于普通的I帧,但具有额外的刷新作用,对于场景切换和错误恢复非常重要。
实现方式:
获取的AVpacket或者MediaExtractor读取的视频包数据进行下面方法检测是否丢包nal_ref_idc==0就是非idr帧进行丢包
方法利用的h264的Nalu解析原理可以去看h264的Nalu解析参数介绍
int getNaluStartCodeLen(const uint8_t* buffer,int buffer_len)
{
if(buffer_len<3){
return 0 ;
}
//0x00、0x00、0x01
if(buffer[0]==0&&buffer[1]==0&&buffer[2]==1){0x000001?
return 3;
}
if(buffer[0]==0&&buffer[1]==0&&buffer[2]==0&&buffer[3]==1){//0x00000001?
return 4;
}
return 0 ;
}
int get_h264_nal_ref_idc(const uint8_t* buffer,int buffer_len)
{
GetBitContext gb;
int slice_type = 0;
int pict_type = FF_MEDIA_PICTURE_NONE ;
int naluStartLen = getNaluStartCodeLen(buffer,buffer_len);
//LOGE("naluStartLen %d",naluStartLen);
if(naluStartLen<=0){
return FF_MEDIA_PICTURE_NONE;
}
int nal_ref_idc = (buffer[naluStartLen] >> 5) & 0x03; // nal_ref_idc 2bit
if (nal_ref_idc==0){
pict_type = FF_MEDIA_PICTURE_TYPE_B;
}
LOGE("=======nal_ref_idc====== [%d]==pict_type== [%d]==",nal_ref_idc,pict_type);
return pict_type;
}
留下思考其他格式怎么丢包?(比如h265等)