zoukankan      html  css  js  c++  java
  • H.264简介

    H.264原始码流由NALU组成。

    功能分为两层:VCL(video coding layer)、NAL(network abstraction layer)

    其中每个NALU之间通过startcode(起始码)进行分隔,起始码分成两种:0x000001或者0x00000001。

    如果NALU对应的Slice为一帧的开始就用0x00000001,否则就用0x000001

    NALU = NALU Header + BRSP(Raw Byte Squence Payload)

    1、NALU Header(1Byte)

    2、RBSP

    SODB与RBSP
    SODB 数据比特串 -> 是编码后的原始数据.
    RBSP 原始字节序列载荷 -> 在原始编码数据的后面添加了 结尾比特。一个 bit“1”若干比特“0”,以便字节对齐。

    H.264全面观

    1 frame = n slice;1 slice = n Macroblock;1 Macroblock= 16 * 16yuv。

    3、Slice

    Slice = Slice Header + Slice Data

    片是H.264提出的新概念,通过编码图片后切分通过高效的方式整合出来的概念。一张图片有一个或者多个片,而片由NALU装载并进行网络传输的。

    但是NALU不一定是切片,这是充分不必要条件,因为 NALU 还有可能装载着其他用作描述视频的信息.

    那么为什么要设置片呢?
    设置片的目的是为了限制误码的扩散和传输,应使编码片相互间是独立的。某片的预测不能以其他片中的宏块为参考图像,这样某一片中的预测误差才不会传播到其他片中。

    可以看到上图中,每个图像中,若干宏块(Macroblock)被排列成片。一个视频图像可编程一个或更多个片,每片包含整数个宏块 (MB),每片至少包含一个宏块。
    片有一下五种类型:

    4、Macroblock

     1 macroblock = 16*16Y + 8*8 Cb + 8*8 Cr

    链接:https://blog.csdn.net/andywang201001/article/details/80274886

    typedef enum {
        NALU_TYPE_SLICE = 1,
        NALU_TYPE_DPA = 2,
        NALU_TYPE_DPB = 3,8
        NALU_TYPE_DPC = 4,
        NALU_TYPE_IDR = 5,
        NALU_TYPE_SEI = 6,
        NALU_TYPE_SPS = 7,
        NALU_TYPE_PPS = 8,
        NALU_TYPE_AUD = 9,
        NALU_TYPE_EOSEQ = 10,
        NALU_TYPE_EOSTREAM = 11,
        NALU_TYPE_FILL = 12,
    } NaluType;
    
    typedef enum {
        NALU_PRIORITY_DISPOSABLE = 0,
        NALU_PRIRITY_LOW = 1,
        NALU_PRIORITY_HIGH = 2,
        NALU_PRIORITY_HIGHEST = 3
    } NaluPriority;
    
    
    typedef struct
    {
        int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
        unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
        unsigned max_size;            //! Nal Unit Buffer size
        int forbidden_bit;            //! should be always FALSE
        int nal_reference_idc;        //! NALU_PRIORITY_xxxx
        int nal_unit_type;            //! NALU_TYPE_xxxx    
        char *buf;                    //! contains the first byte followed by the RBSP
    } NALU_t;
    
    FILE *h264bitstream = NULL;                //!< the bit stream file
    
    int info2 = 0, info3 = 0;
    
    static int FindStartCode2(unsigned char *Buf) {
        if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 1) return 0; //0x000001?
        else return 1;
    }
    
    static int FindStartCode3(unsigned char *Buf) {
        if (Buf[0] != 0 || Buf[1] != 0 || Buf[2] != 0 || Buf[3] != 1) return 0;//0x00000001?
        else return 1;
    }
    
    
    int GetAnnexbNALU(NALU_t *nalu) {
        int pos = 0;
        int StartCodeFound, rewind;
        unsigned char *Buf;
    
        if ((Buf = (unsigned char*)calloc(nalu->max_size, sizeof(char))) == NULL)
            printf("GetAnnexbNALU: Could not allocate Buf memory
    ");
    
        nalu->startcodeprefix_len = 3;
    
        if (3 != fread(Buf, 1, 3, h264bitstream)) {
            free(Buf);
            return 0;
        }
        info2 = FindStartCode2(Buf);
        if (info2 != 1) {
            if (1 != fread(Buf + 3, 1, 1, h264bitstream)) {
                free(Buf);
                return 0;
            }
            info3 = FindStartCode3(Buf);
            if (info3 != 1) {
                free(Buf);
                return -1;
            }
            else {
                pos = 4;
                nalu->startcodeprefix_len = 4;
            }
        }
        else {
            nalu->startcodeprefix_len = 3;
            pos = 3;
        }
        StartCodeFound = 0;
        info2 = 0;
        info3 = 0;
    
        while (!StartCodeFound) {
            if (feof(h264bitstream)) {
                nalu->len = (pos - 1) - nalu->startcodeprefix_len;
                memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);
                nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
                nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
                nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
                free(Buf);
                return pos - 1;
            }
            Buf[pos++] = fgetc(h264bitstream);
            info3 = FindStartCode3(&Buf[pos - 4]);
            if (info3 != 1)
                info2 = FindStartCode2(&Buf[pos - 3]);
            StartCodeFound = (info2 == 1 || info3 == 1);
        }
    
        // Here, we have found another start code (and read length of startcode bytes more than we should
        // have.  Hence, go back in the file
        rewind = (info3 == 1) ? -4 : -3;
    
        if (0 != fseek(h264bitstream, rewind, SEEK_CUR)) {
            free(Buf);
            printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
        }
    
        // Here the Start code, the complete NALU, and the next start code is in the Buf.  
        // The size of Buf is pos, pos+rewind are the number of bytes excluding the next
        // start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code
    
        nalu->len = (pos + rewind) - nalu->startcodeprefix_len;
        memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//
        nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
        nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
        nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
        free(Buf);
    
        return (pos + rewind);
    }
    
    /**
     * Analysis H.264 Bitstream
     * @param url    Location of input H.264 bitstream file.
     */
    int simplest_h264_parser(char *url) {
    
        NALU_t *n;
        int buffersize = 100000;
        FILE *myout = stdout;
    
        h264bitstream = fopen(url, "rb+");
        if (h264bitstream == NULL) {
            printf("Open file error
    ");
            return 0;
        }
    
        n = (NALU_t*)calloc(1, sizeof(NALU_t));
        if (n == NULL) {
            printf("Alloc NALU Error
    ");
            return 0;
        }
    
        n->max_size = buffersize;
        n->buf = (char*)calloc(buffersize, sizeof(char));
        if (n->buf == NULL) {
            free(n);
            printf("AllocNALU: n->buf");
            return 0;
        }
    
        int data_offset = 0;
        int nal_num = 0;
        printf("-----+-------- NALU Table ------+---------+
    ");
        printf(" NUM |    POS  |    IDC |  TYPE |   LEN   |
    ");
        printf("-----+---------+--------+-------+---------+
    ");
    
        while (!feof(h264bitstream))
        {
            int data_lenth;
            data_lenth = GetAnnexbNALU(n);
    
            char type_str[20] = { 0 };
            switch (n->nal_unit_type) {
            case NALU_TYPE_SLICE:sprintf(type_str, "SLICE"); break;
            case NALU_TYPE_DPA:sprintf(type_str, "DPA"); break;
            case NALU_TYPE_DPB:sprintf(type_str, "DPB"); break;
            case NALU_TYPE_DPC:sprintf(type_str, "DPC"); break;
            case NALU_TYPE_IDR:sprintf(type_str, "IDR"); break;
            case NALU_TYPE_SEI:sprintf(type_str, "SEI"); break;
            case NALU_TYPE_SPS:sprintf(type_str, "SPS"); break;
            case NALU_TYPE_PPS:sprintf(type_str, "PPS"); break;
            case NALU_TYPE_AUD:sprintf(type_str, "AUD"); break;
            case NALU_TYPE_EOSEQ:sprintf(type_str, "EOSEQ"); break;
            case NALU_TYPE_EOSTREAM:sprintf(type_str, "EOSTREAM"); break;
            case NALU_TYPE_FILL:sprintf(type_str, "FILL"); break;
            }
            char idc_str[20] = { 0 };
            switch (n->nal_reference_idc >> 5) {
            case NALU_PRIORITY_DISPOSABLE:sprintf(idc_str, "DISPOS"); break;
            case NALU_PRIRITY_LOW:sprintf(idc_str, "LOW"); break;
            case NALU_PRIORITY_HIGH:sprintf(idc_str, "HIGH"); break;
            case NALU_PRIORITY_HIGHEST:sprintf(idc_str, "HIGHEST"); break;
            }
    
            fprintf(myout, "%5d| %8d| %7s| %6s| %8d|
    ", nal_num, data_offset, idc_str, type_str, n->len);
    
            data_offset = data_offset + data_lenth;
    
            nal_num++;
        }
    
        //Free
        if (n) {
            if (n->buf) {
                free(n->buf);
                n->buf = NULL;
            }
            free(n);
        }
        return 0;
    }

    链接:https://blog.csdn.net/leixiaohua1020/article/details/50534369

  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/zebra-bin/p/12910301.html
Copyright © 2011-2022 走看看