android MediaCodec 如何快速seek获取帧

android MediaCodec 如何快速seek获取帧

解说正常思路seek到一个时间戳的的前一个I帧,然后进行解码到该时间戳进行显示、或者抽帧需求。
假如你实现上面步骤后,正常是可以在优化的

只说明一种格式

1、h264视频
2、MediaExtractor或者ffmpeg进行读取视频包

优化原理丢弃解码到该seek时间戳之前的非IDR帧:

在H.264视频编码标准中,I帧、P帧和B帧是用于描述视频帧类型和帧间关系的术语。下面是对它们的介绍:

  1. I帧(Intra-coded frame):

    • I帧也被称为关键帧或独立帧。
    • 一个I帧是一个完整的、自包含的视频帧,不依赖于其他帧的信息。
    • I帧通常出现在视频序列开头、场景切换或错误恢复时。
    • 每个GOP(Group of Pictures,一组连续的帧)的第一个帧都是I帧。
  2. P帧(Predictive-coded frame):

    • P帧是通过前向预测编码生成的帧。
    • P帧需要参考先前的一个或多个I帧或P帧进行解码。
    • P帧存储了与之相关的参考帧之间的差异信息,以减小数据量。
    • P帧相对于I帧来说,具有更高的压缩效率。
  3. 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帧进行介绍:

  1. IDR帧:

    • IDR帧也被称为关键刷新帧。
    • IDR帧与普通的I帧类似,是一个完整的、自包含的视频帧,不依赖于其他帧的信息。
    • 与普通的I帧不同,IDR帧的作用是在解码过程中进行即时解码的刷新点。
    • IDR帧常用于场景切换或错误恢复时,可以重新建立解码器的参考帧缓冲区,从而保证后续帧的正确解码。
  2. 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等)

  • 15
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoyu45585

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值