H264 帧边界识别简介



H.264 将构成一帧图像所有nalu 的集合称为一个AU,帧边界识别实际上就是识别AU。

因为H.264 取消帧级语法,所以无法简单地从码流中获取AU。解码器只有在解码的过

程中,通过某些语法元素的组合才能判断一帧图像是否结束。一般来说,解码器必须在

完成一帧新图像的第一个slice_header 语法解码之后,才能知道前一帧图像已经结束。

因此,最严谨的AU 识别步骤如下:

步骤 1 对码流实施“去03 处理”。

步骤 2 解析nalu 语法。

步骤 3 解析slice_header 语法。

步骤 4 综合判断前后两个nalu 以及对应的slice_header 中的若干个语法元素,看是否发生变化。

如果发生变化,则说明这两个nalu 属于不同的帧,否则说明这两个nalu 属于同一帧

----结束

显然,在解码前完成上述的AU 识别消耗许多CPU 资源,因此不推荐使用AU 方式解码

为了提供一种简单的AU 识别方案,H.264 规定一种类型为09 的nalu,即编码器在每次完成一个AU 编码后,在码流中插入一个类型为09 的nalu,在这个前提下,解码器只需要从码流中搜索类型为09 的nalu 即可获得一个AU。

H.264 并不强制要求编码器插入类型为09 的nalu,因此并非所有的码流都具备这种特征。对于

编码器和解码器协同工作的应用场景,建议让编码器插入类型为09 的nalu,这样可以降低解码

器识别AU 的代价。

为了降低解码器在解码前识别AU 的代价,本文提出一种高效的AU 识别方法,其主要

思路是利用一帧图像的第一个slice_header 中的语法元素first_mb_in_slice 一般等于0

个特征(对于包含ASO 或者FMO 特性的码流,这个条件不一定成立)。

typedef struct ParseContext{

    unsigned int FrameStartFound;

    unsigned int iFrameLength;

} ParseContext;

signed int DecLoadAU(unsigned char* pStream, unsigned int iStreamLen, ParseContext *pc)

    {

        unsigned int i;

        unsigned int state = 0xffffffff;

        if( NULL == pStream )

        {

            return -1;

        }

        for( i = 0; i < iStreamLen; i++)

        {

           

            if( (state & 0xFFFFFF1F) == 0x101 || (state & 0xFFFFFF1F) == 0x105 )

            {

                if (i >= iStreamLen)

                {

                    break;

                }if( pStream[i] & 0x80)

                {

                    if(pc->FrameStartFound)

                    {

                        pc->iFrameLength = i - 4;

                        pc->FrameStartFound = 0;

                        state = 0xffffffff;

                        return 0;

                    }

                    else

                    {

                        pc->FrameStartFound = 1;

                    }

                }

            }

            if (i < iStreamLen)

            {

                state = (state << 8) | pStream[i];

            }

        }

        pc->FrameStartFound = 0;

        return -1;

    }

解决了最关键的问题后, 下面就是将解码完的数据送去播放的问题了, 可以启动一个Timer, 定时去读取一帧的数据送去解码就可以。针对不同的帧率调整Timer的时间即可,当然最正规的做法是根据MP4或者AVI文件中的时间戳。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值