当前位置: 首页 > news >正文

H264--5--H264解码[8]

原文:http://blog.csdn.net/yangzhongxuan/article/details/8003547

 

解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码。

 nal_unit( NumBytesInNALunit ) {  /* NumBytesInNALunit为统计出来的数据长度 */
       forbidden_zero_bit    // forbidden_zero_bit  等于 0表示网络传输没有出错 
    nal_ref_idc //   指示当前 NAL 的优先级。取值范围为 0-3,  值越高,表示当前 NAL 越重要,需要优先受到保护。H.264 规定如果当前 NAL 是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的数据单位时,本句法元素必须大于 0。    
    nal_unit_type // NAL类型 指明当前 NAL unit 的类型 
    NumBytesInRBSP = 0  
    /* rbsp_byte[i]    RBSP 的第 i 个字节。 RBSP 指原始字节载荷,它是 NAL 单元的数据部分的封装格式,封装的数据来自 SODB(原始数据比特流)。SODB 是编码后的原始数据,SODB 经封装为 RBSP 后放入 NAL 的数据部分。下面介绍一个 RBSP 的生成顺序。 
        从 SODB 到 RBSP 的生成过程: 
        -      如果 SODB 内容是空的,生成的 RBSP 也是空的 
        -      否则,RBSP 由如下的方式生成: 
       1) RBSP 的第一个字节直接取自 SODB 的第 1 到 8 个比特,(RBSP 字节内的比特按照从左到右对应为从高到低的顺序排列,most  significant),以此类推,RBSP 其余的每个字节都直接取自 SODB的相应比特。RBSP  的最后一个字节包含 SODB  的最后几个比特,及如下的 rbsp_trailing_bits() 
       2) rbsp_trailing_bits()的第一个比特是 1,接下来填充 0,直到字节对齐。(填充 0 的目的也是为了字节对齐) 
       3) 最后添加若干个 cabac_zero_word(其值等于 0x0000)            
    */
 
    for( i = 1; i <</span> NumBytesInNALunit; i++ ) {           
        if( i + 2 <</span> NumBytesInNALunit && next_bits( 24 )    = =    0x000003 ) {   
/* 0x000003伪起始码,需要删除0x03这个字节 */       
            rbsp_byte[ NumBytesInRBSP++ ]   
            rbsp_byte[ NumBytesInRBSP++ ]   
            i += 2    /* 取出前两个0x00后,跳过0x03 */          
            //emulation_prevention_three_byte      NAL 内部为防止与起始码竞争而引入的填充字节  ,值为 0x03。 
            emulation_prevention_three_byte    
        } else           
            rbsp_byte[ NumBytesInRBSP++ ] /* 继续读取后面的字节 */   


    }          
}

 

序列参数集(SPS)

 

句法

C

Desc

seq_parameter_set_rbsp(){

 

 

    profile_idc/*指明所用的Profile */

0

u(8)

    constraint_set0_flag

0

u(1)

    constraint_set1_flag

0

u(1)

    constraint_set1_flag

0

u(1)

    reserved_zero_5bits /* equal to 0 */

0

u(5)

    level_idc /* 指明所用的Level */

0

u(8)

    seq_parameter_set_id /* 指明本序列参数集的id号,0-31,被图像集引用,编码需要产生新的序列集时,使用新的id,而不是改变原来参数集的内容 */

0

ue(v)

    log2_max_frame_num_minus4/*为读取元素frame_num服务,frame_num标识图像的解码顺序,frame_num的解码函数是ue(v),其中v=log2_max_frame_num_minus4+4,该元素同时指明frame_num的最大值MaxFrameNum=2( log2_max_frame_num_minus4+4)*/

0

ue(v)

    pic_order_cnt_type /* 指明poc的编码方法,poc标识图像的播放顺序,poc可以由frame_num计算,也可以显示传送。poc共三种计算方式 */

0

ue(v)

    if(pic_order_cnt_type==0)

 

 

        log2_max_pic_order_cnt_lsb_minus4 /* 指明变量MaxPicOrderCntLsb的值, MaxPicOrderCntLsb=2(log2_max_pic_order_cnt_lsb_minus4+4) */

0

ue(v)

    else if(pic_order_cnt_type==1){

 

 

        delta_pic_order_always_zero_flag /* 等于1时,元素delta_pic_order_cnt[0]和delta_pic_order_cnt[1]不在片头中出现,并且它们的默认值是0,等于0时,上述两元素出现的片头中 */

0

u(1)

        offset_for_non_ref_pic /* 用来计算非参考帧或场的poc,[-231,231-1] */

0

se(v)

        offset_for_top_to_bottom_field/*计算帧的底场的poc */

0

se(v)

        num_ref_frames_inpic_order_cnt_cycle /* 用来解码poc,[0.255] */

0

ue(v)

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

 

 

            offset_for_ref_frame[i]/*用来解码poc,对于循环中的每个元素指定一个偏移 */

0

se(v)

    }

 

 

    num_ref_frames /* 参考帧队列可达到的最大长度,[0,16] */

0

ue(v)

    gaps_in_frame_num_value_allowed_flag /* 为1,允许slice header中的frame_num不连续 */

0

u(1)

    pic_width_inmbs_minus1 /*本元素加1,指明以宏块为单位的图像宽度 PicWidthInMbs=pic_width_in_mbs_minus1+1 */

0

ue(v)

    pic_height_in_map_units_minus1 /* 本元素加1,指明以宏块为单位的图像高宽度 PicHeightInMapUnitsMbs=pic_height_in_map_units_minus1+1 */

0

ue(v)

    frame_mbs_only_flag /* 等于0表示本序列中所有图像均为帧编码;等于1,表示可能是帧,也可能场或帧场自适应,具体编码方式由其它元素决定。结合前一元素:FrameHeightInMbs=(2-frame_mbs_only_flag)*PicHeightInMapUnits */

0

ue(v)

    if(frame_mbs_only_flag)

 

 

      mb_adaptiv_frame_field_flag /* 指明本序列是否是帧场自适应模式:

frame_mbs_only_flag=1,全部是帧

frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=0,帧场共存

frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=1,帧场自适应和场共存*/

0

u(1)

    direct_8x8_inference_flag /* 用于指明B片的直接和skip模式下的运动矢量的计算方式 */

0

u(1)

    frame_cropping_flag /*解码器是否要将图像裁剪后输出,如果是,后面为裁剪的左右上下的宽度 */

0

u(1)

    if(frame_cropping_flag){

 

 

        frame_crop_left_offset

0

ue(1)

        frame_crop_right_offset

0

ue(1)

        frame_crop_top_offset

0

ue(1)

        frame_crop_bottom_offset

0

ue(1)

    }

 

 

    vui_parameters_present_flag /* 指明vui子结构是否出现在码流中,vui子结构在附录中指明,用于表征视频格式的信息 */

0

u(1)

    if(vui_parameters_present_flag)

 

 

        vui_parameters()

0

 

    rbsp_trailing_bits()

0

 

}

 

 

转载于:https://www.cnblogs.com/Ph-one/p/6369986.html

相关文章:

  • 静态编译与动态编译的区别
  • Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析
  • 蓝牙驱动分析 linux
  • 位域
  • OTN / SONET / SDH
  • 波分复用技术
  • ATM网络
  • 教你如何认识各种光纤接口类型
  • 网线与光纤接口几条线介绍
  • CPU上电时序详细分析
  • 下载模式
  • 以太网接口TCP/IP协议介绍,说的很容易懂了
  • 基于嵌入式Linux的千兆以太网卡驱动程序设计及测试
  • 数据结构基础知识(1)
  • 数据结构之队列
  • [译]Python中的类属性与实例属性的区别
  • ➹使用webpack配置多页面应用(MPA)
  • avalon2.2的VM生成过程
  • Docker容器管理
  • EventListener原理
  • Javascript基础之Array数组API
  • maven工程打包jar以及java jar命令的classpath使用
  • php ci框架整合银盛支付
  • select2 取值 遍历 设置默认值
  • spark本地环境的搭建到运行第一个spark程序
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 检测对象或数组
  • 一些关于Rust在2019年的思考
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​如何防止网络攻击?
  • # Panda3d 碰撞检测系统介绍
  • #stm32整理(一)flash读写
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • $.ajax()方法详解
  • $.each()与$(selector).each()
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (k8s中)docker netty OOM问题记录
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • ***原理与防范
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)
  • []串口通信 零星笔记
  • [1181]linux两台服务器之间传输文件和文件夹
  • [20171106]配置客户端连接注意.txt
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)
  • [C#基础知识]专题十三:全面解析对象集合初始化器、匿名类型和隐式类型
  • [CISCN2019 华东北赛区]Web2