多媒体开发之---h264 取流解码分析

1.

nalu_unit_type = *((unsigned char *)pEmptyBuf->bufVirtAddr+4);
nalu_unit_type = nalu_unit_type&0x1F;
if(nalu_unit_type<= 5 && nalu_unit_type>=1)
{
slice_sum ++;
printf("%s:nalu_unit_type = %d ,frame_size = %d, frame_id = %d,slice_sum = %d\n",__func__,nalu_unit_type,pEmptyBuf->filledBufSize,frame_id,slice_sum);
}
else
{
frame_flag++;
if(nalu_unit_type==6)printf("sei ...\n");
else if(nalu_unit_type==7)printf("sps ...\n");
else if(nalu_unit_type==8)printf("pps ...\n");
else if(nalu_unit_type == 9)printf("cut fp ...\n");
else if(nalu_unit_type == 10)printf("sps end ...\n");
else if(nalu_unit_type == 11)printf("stream end ...\n");
else printf("unknow frame !\n");
printf("nalu_unit_type = %d, frame_flag = %d, slice_sum = %d,frame_id =%d\n",nalu_unit_type,frame_flag,slice_sum,frame_id);
}
first_mb_in_slice = *((unsigned char *)pEmptyBuf->bufVirtAddr+5);
if((first_mb_in_slice&0x80)==0x80)
printf("%s:first_mb_in_slice = %d frame_id = %d\n\n\n",__func__,first_mb_in_slice,frame_id);//per frame all is iframe

for (wordCount = 4; wordCount < bufferLen; wordCount++)
{
loopCount = wordCount;

if ((stream[loopCount++] == 0 && stream[loopCount++] == 0 &&
stream[loopCount++] == 0 && stream[loopCount++] == 0x01) ||
(stream[loopCount++] == 0 && stream[loopCount++] == 0 &&
stream[loopCount++] == 1))
{
NewNalType = stream[loopCount++] & 0x1f;
firstMbInSliceFlag = stream[loopCount++] & 0x80;//reuser header nal
vcl_nal_flag = ((NewNalType <=5) && (NewNalType > 0));

if(vcl_nal_flag && prev_vcl_nal_flag)//是两帧之间的新帧,且又是第片块,i帧或p帧,新一帧的开始,上一帧的结束
{
prev_nal_type = NewNalType;
prev_vcl_nal_flag = vcl_nal_flag;

if( (firstMbInSliceFlag))
break;
}

if ((prev_vcl_nal_flag && !vcl_nal_flag))//非slice ,但是可能是sps pps sei idr,没宏块,也做为一帧
{
prev_nal_type = NewNalType;
prev_vcl_nal_flag = vcl_nal_flag;

break;
}

prev_nal_type = NewNalType;
prev_vcl_nal_flag = vcl_nal_flag;
}

nalLength++;
}

2.

以sps开头的*(addr+5)&0x1f 的之为07(67) 后续pps 08(68),sei 06 ,idr 05(65) 为解码第一帧

3.

后续就是i,和p帧 i帧 05(65) ,p帧 01(41)

一个sps 包括sps pps sei idr为第一次帧以first_mb_slice为基本帧分界线

mw3 9 个idr frame

每个0001 都是一个slice mb

http://www.cnitblog.com/vcommon/archive/2007/05/31/27842.html 哥伦布编码!!!

http://70565912.blog.51cto.com/1358202/533736/

  1. // 判断是否帧结束
  2. for (uint32_t i = 3; i < nal_length; i++)
  3. {
  4. if (p_nal[i] & 0x80)
  5. {
  6. // 找到frame_begin!!!!上一帧frame的结束,下一帧frame的开始
  7. }
  8. }

解析到位于帧结束位置的NALU,就可以判断出每一帧(slice)的开始和结尾。解析slice的slice_type,根据slice_type,可以判断出这个slice的IPB类型。

  1. // 根据slice类型判断帧类型
  2. switch(slice.i_slice_type)
  3. {
  4. case 2: case 7:
  5. case 4: case 9:
  6. *p_flags = 0x0002/*BLOCK_FLAG_TYPE_I*/;
  7. break;
  8. case 0: case 5:
  9. case 3: case 8:
  10. *p_flags = 0x0004/*BLOCK_FLAG_TYPE_P*/;
  11. break;
  12. case 1:
  13. case 6:
  14. *p_flags = 0x0008/*BLOCK_FLAG_TYPE_B*/;
  15. break;
  16. default:
  17. *p_flags = 0;
  18. break;
  19. }

http://bbs.csdn.net/topics/380262907

typedef struct
{
        /*分层结构最大的不同时取消了序列层和图像层,并将原本属于序列和头部的大部分句法元素游离出来形成
                序列和图像两级参数集。  其余部分则放入片层*/
    x264_sps_t *sps;          /*序列参数集*/ 
    x264_pps_t *pps;          /*图像参数集*/

/*slice_type
        指明片的类型*/
    int i_type;             
        //first_mb_in_slice
        /*片中第一个宏块的地址,片通过这个句法元素来标定它自己的地址。
        在帧场自适应模式下,宏块都是成对出现的,这是本句法元素表示的是第几个宏块对,
        对应第一个宏块的真实地址应该是 2*first_mb_in_slice*/
    int i_first_mb;          
    int i_last_mb;

int i_pps_id;         /*图像参数集的序号*/

//frame_num
    /*每个参考帧都有一个一次连续的frame_num作为他们的标识,这指明了各图像的解码顺序。
        但事实上我们在表中看到,frame_num的出现没有if语句限定条件,这表明非参考帧的片头也会出现frame_num
        指示当该个图像是参考帧时候,它携带的这个句法元素在解码时候才有意义*/
        int i_frame_num;

int b_mbaff;
        //field_pic_flag
        /*在片层表示图像编码模式的唯一一个句法元素,所谓的编码模式是指帧编码,场编码 ,帧场自适应编码
    这个句法元素取1的时候属于场编码,0时为非场编码*/
    int b_field_pic;
        /*等于1的时候说明当前图像是属于底场,等于0时候说明当前图像是属于顶场*/
    int b_bottom_field;

/*IDR图像标示,不同的IDR图像有不同的idr_pic_id值,IDR图像不等同于I图像*/
    int i_idr_pic_id;   /* -1 if nal_type != 5 */

/*POC 的第一种算法中用本句法元素来计算POC值,在POC的第一种算法中是显式的传递POC值*/
    int i_poc_lsb;
    int i_delta_poc_bottom;

/*POC的第二种和第三种算法是从frame_num映射得来的,这两个句法元素用于映射算法。
        delta_pic_order_cnt[0]用于帧场编码方式下的底场和场编码方式的场,
        delta_pic_order_cnt[1]用于帧编码方式下的顶场。*/
    int i_delta_poc[2];
        //redundant_pic_cnt
        /*冗余片的id号*/
    int i_redundant_pic_cnt;

//direct_spatial_mv_pred_flag
        /*指明B图像的直接预测的模式下, 用时间预测还是空间预测 值为1空间预测 值为0时间预测*/
    int b_direct_spatial_mv_pred;

//num_ref_idx_active_override_flag
        /*图像参数集中我们看到已经出现句法元素num_ref_idx_10_active_minus1 和 num_ref_idx_11_active_minus1
        制定当前参考帧队列中实际可用的参考帧的数目。在片头重载这对句法元素,以给某特定图像更大的灵活度。
        这句法元素就是指明片头是否会重载,如果等于1,下面会出现新的num_ref_idx_10_active_minus1*/
    int b_num_ref_idx_override;
    int i_num_ref_idx_l0_active;
    int i_num_ref_idx_l1_active;

/*参考图像重新排列的语义*/

/*指明是否进行重排序操作,这个句法等于1时,表明紧跟着会有一系列句法元素用于参考帧队列的重排序*/
    int b_ref_pic_list_reordering_l0;
    int b_ref_pic_list_reordering_l1;
    struct {
        int idc;
        int arg;
    } ref_pic_list_order[2][16];

//cabac_init_idc
        /*给出cabac初始化时表格的选择 范围为0~2*/
    int i_cabac_init_idc;

int i_qp;
        /*指出用于当前片的所有宏块的量化参数的初始值QP*/
    int i_qp_delta;
        /*sp帧中的p宏块的解码方式是否是switching方式*/
    int b_sp_for_swidth;
        /*和i_qp_delta语义相似*/
    int i_qs_delta;

/* deblocking filter */
        /*指明一些滤波的设置*/
    int i_disable_deblocking_filter_idc;
    int i_alpha_c0_offset;
    int i_beta_offset;

} x264_slice_header_t;

http://linfengdu.blog.163.com/blog/static/117710732009111861540971/

http://www.baidu.com/s?ie=utf-8&f=8&tn=baidu&wd=first_mb_in_slice&rsv_bp=1&rsv_enter=1&rsv_n=2&rsv_sug3=1&rsv_sug4=385&rsv_sug2=0&inputT=842

时间: 2024-10-29 11:49:10

多媒体开发之---h264 取流解码分析的相关文章

多媒体开发之---h264 取流解码实现

解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码. nal_unit( NumBytesInNALunit ) {  /* NumBytesInNALunit为统计出来的数据长度 */       forbidden_zero_bit    // forbidden_zero_bit  等于 0表示网络传输没有出错     nal_ref_idc //   指示当前 NAL 的优先级.取值范围为 0-3,  值越高,表示当前 NAL 越重要,需要优先受到保护.H.2

多媒体开发之---h264格式详解

http://blog.csdn.net/bluebirdssh/article/details/6533501 http://blog.csdn.net/d_l_u_f/article/details/7260772 http://blog.csdn.net/sunnylgz/article/details/7680262 http://blog.csdn.net/heanyu/article/details/6204414 多媒体开发之---h264格式详解,布布扣,bubuko.com

多媒体开发之---h264 高度和宽度获取

( School of Computer Science & Technology, Soochow University,SuZhou 215006:) Abstract: H.264 is the newest video coding standard, and it will be widely used. In this article, the problem of the structure of coding streaming in H.264 is discussed. Fi

多媒体开发之---h264 NALU 语法结构

补充笔记: 关于VCL:VCL层是指视频编码层,VCL NAL 单元是指那些nal_unit_type 值等于 1 到 5(包括 1 和 5)的 NAL 单元,这些单元都包含了视频数据.所有其他的 NAL 单元都称作非 VCL NAL 单元,PPS和SPS都是非VCLNAL单元.关于字节流NAL单元的格式:(起始码中0的长度)除了流开头的字节流NAL单元,大多字节流NAL单元的开头没有leading_zero_8bits (一个字节的0); nal_unit_type等于7(SPS)或8(PPS

多媒体开发之---h264格式slice_header

从Slice_Header学习H.264 写在前面: $     H.264我是结合标准和毕厚杰的书一块学的.看句法语义时最是头疼,一大堆的元素,很需要耐心.标准中在介绍某个元素的语义时,经常会突然冒出与之相关的另一个变量,这个变量一般都在前文中讲过,但那么多变量怎么可能看一遍就记住?这时我只能去前面重新找这个变量再看一遍.没办法,H.264这个庞大的结构内部肯定是环环相扣的,各个部分联系紧密,所以刚开始看时要搞明白H.264的主要细节以及相互间的关系不是特别容易,尤其看到一大堆不认识的变量时,

多媒体开发之---h264 图像参数级语义

(四)图像参数集语义 pic_parameter_set_rbsp( ) {       // pic_parameter_set_id 用以指定本参数集的序号,该序号在各片的片头被引用.    pic_parameter_set_id       // seq_parameter_set_id  指明本图像参数集所引用的序列参数集的序号.     seq_parameter_set_id      // entropy_coding_mode_flag  指明熵编码的选择,本句法元素为0时,表

多媒体开发之--- h264 图像、帧、片、NALU

图像.帧.片.NALU 是学习 H.264的人常常感到困惑的一些概念,我在这里对自己的理解做一些阐述,欢迎大家讨论: H.264 是一次概念的革新,它打破常规,完全没有 I 帧.P帧.B 帧的概念,也没有 IDR帧的概念.对于 H.264中出现的一些概念从大到小排序依次是:序列.图像.片组.片.NALU.宏块.亚宏块.块.像素.这里有几点值得说明:(1).在 H.264协议中图像是个集合概念,顶场.底场.帧都可以称为图像(本文图像概念时都是集合概念).因此我们可以知道,对于H.264 协议来说,

多媒体开发之---h264中 的RTP PAYLOAD 格式

H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+      |0|1|2|3|4|5|6|7|      +-+-+-+-+-+-+-+-+      |F|NRI|  Type   |      +---------------+ F: 1 个比特.  forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0. NRI: 2 个比特.  nal_ref_idc

多媒体开发之---H264 RTSP交互过程

OPTIONS rtsp://192.168.1.154:8557/h264 RTSP/1.0 CSeq: 1 User-Agent: VLC media player (LIVE555 Streaming Media v2010.05.28)  RTSP/1.0 200 OK CSeq: 1 Date: Sat, Jan 01 2000 00:05:11 GMT Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE  DESCRIBE