前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >H264码流分析导读

H264码流分析导读

作者头像
deep_sadness
发布2018-08-30 10:55:59
1.9K0
发布2018-08-30 10:55:59
举报
文章被收录于专栏:Flutter入门Flutter入门

导读

H.264码流结构解析

H.264编码格式

H.264的功能分为两层:视频编码层(VCL, Video Coding Layer)和网络提取层(NAL, Network Abstraction Layer) VCL数据即编码处理的输出,它表示被压缩编码后的视频数据序列。在VCL数据传输或存储之前,这些编码的VCL数据,先被映射或封装进NAL单元中。每个NAL单元包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组对应于视频编码的NAL头信息。RBSP的基本结构是:在原始编码数据的后面填加了结尾比特。一个bit“1”若干比特“0”,以便字节对齐。

image.png

H.264传输

H.264的编码视频序列包括一系列的NAL单元,每个NAL单元包含一个RBSP,见表1。编码片(包括数据分割片IDR片)和序列RBSP结束符被定义为VCL NAL单元,其余为NAL单元。典型的RBSP单元序列如图2所示。每个单元都按独立的NAL单元传送。单元的信息头(一个字节)定义了RBSP单元的类型,NAL单元的其余部分为RBSP数据。

image.png

image.png

  1. H.264码流结构图

image.png

起始码:如果NALU对应的Slice为一帧的开始,则用4字节表示,即0x00000001;否则用3字节表示,0x000001。 NAL Header:forbidden_bit,nal_reference_bit(优先级),nal_unit_type(类型)。 脱壳操作:为了使NALU主体不包括起始码,在编码时每遇到两个字节(连续)的0,就插入一字节0x03,以和起始码相区别。解码时,则将相应的0x03删除掉。

image.png

  1. H.264解码 NAL头信息的nal_referrence_idc(NRI)用于在重建过程中标记一个NAL单元的重要性,值为0表示这个NAL单元没有用预测,因此可以被解码器抛弃而不会有错误扩散;值高于0表示NAL单元要用于无漂移重构,且值越高,对此NAL单元丢失的影响越大。 NAL头信息的隐藏比特位,在H.264编码器中默认为0,当网络识别到单元中存在比特错误时,可将其置为1。隐藏比特位主要用于适应不同种类的网络环境(比如有线无线相结合的环境)。

image.png

NAL单元解码的流程为:首先从NAL单元中提取出RBSP语法结构,然后按照如图4所示的流程处理RBSP语法结构。输入的是NAL单元,输出结果是经过解码的当前图像的样值点。 NAL单元中分别包含了序列参数集和图像参数集。图像参数集和序列参数集在其他NAL单元传输过程中作为参考使用,在这些数据NAL单元的片头中,通过语法元素pic_parameter_set_id设置它们所使用的图像参数集编号;而相应的每个图像参数集中,通过语法元素seq_paramter_set_id设置他们使用的序列参数集编号。

示例分析

结合laifeng_Android中的AnnexbHelper来简单的看看,如果进行解析。 Android硬编码得到的H264是Annexb这种格式的。

  • 如何获取NAUL单元 其实就是找开头为 0x0001或者0x000001的字节段
代码语言:javascript
复制
  /**
     * 从硬编出来的byteBuffer中查找nal
     * @param as
     * @param bb
     * @param bi
     */
    private void avcStartWithAnnexb(AnnexbSearch as, ByteBuffer bb, MediaCodec.BufferInfo bi) {
        as.match = false;
        as.startCode = 0;
        int pos = bb.position();
        while (pos < bi.offset + bi.size - 3) {
            // not match.
            if (bb.get(pos) != 0x00 || bb.get(pos + 1) != 0x00) {
                break;
            }

            // match N[00] 00 00 01, where N>=0
            if (bb.get(pos + 2) == 0x01) {
                as.match = true;
                as.startCode = pos + 3 - bb.position();
                break;
            }
            pos++;
        }
    }
  • 根据NAL Header内的nal_unit_type判断当前帧的类型 根据上面的类型分析,我们知道NAUL里面前8位中的后5位,表示这个NAUL的类型。 根据这些可以判断类型。 而剩下的就是NAUL内的数据了。
代码语言:javascript
复制
private boolean isSps(byte[] frame) {
        if (frame.length < 1) {
            return false;
        }
        // 5bits, 7.3.1 NAL unit syntax,
        // H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
        //  7: SPS, 8: PPS, 5: I Frame, 1: P Frame
        int nal_unit_type = (frame[0] & 0x1f);
        return nal_unit_type == SPS;
    }

    private boolean isPps(byte[] frame) {
        if (frame.length < 1) {
            return false;
        }
        // 5bits, 7.3.1 NAL unit syntax,
        // H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
        //  7: SPS, 8: PPS, 5: I Frame, 1: P Frame
        int nal_unit_type = (frame[0] & 0x1f);
        return nal_unit_type == PPS;
    }

    private boolean isKeyFrame(byte[] frame) {
        if (frame.length < 1) {
            return false;
        }
        // 5bits, 7.3.1 NAL unit syntax,
        // H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
        //  7: SPS, 8: PPS, 5: I Frame, 1: P Frame
        int nal_unit_type = (frame[0] & 0x1f);
        return nal_unit_type == IDR;
    }

    private static boolean isAccessUnitDelimiter(byte[] frame) {
        if (frame.length < 1) {
            return false;
        }
        // 5bits, 7.3.1 NAL unit syntax,
        // H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
        //  7: SPS, 8: PPS, 5: I Frame, 1: P Frame
        int nal_unit_type = (frame[0] & 0x1f);
        return nal_unit_type == AccessUnitDelimiter;
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.05.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
    • H.264编码格式
      • H.264传输
      • 示例分析
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档