语法解析

u(n)

n代表读取的bit数
含义:读取n位无符号整数

ue(v)

v代表可变长的含义
含义:一直向后读取,直到读取到1结束,记录0的个数leadingZeroBits,然后向后读取leadingZeroBits位,作为一个无符号整数value
最后返回值为(1 << leadingZeroBits - 1 + value)
例子:
原始序列(二进制) 0 0 1 0 1
读取leadingZeroBits为2
向后再读2位,value为1
最后返回值 1 << 2 - 1 + 1 = 4

语法结构

注意点

为了防止NAL Unit内部出现与起始码 0x000001 或 0x00000001 相同的字节序列,H.265规定,在生成NAL Unit负载时,如果出现 0x000003 这样的序列(即两个连续的0x00字节后跟着一个0x01, 0x02 或 0x03),就必须在第三个字节前插入一个 0x03

具体规则:
0x000000 -> 0x00000300
0x000001 -> 0x00000301
0x000002 -> 0x00000302
0x000003 -> 0x00000303

H265

SPS语法结构


示例

JS读取哥伦布指数的代码

 // 实现代码
class BitReader {
    constructor(data) {
        this.data = data;
        this.bitPosition = 0;
        this.bytePosition = 0;
        this.currentByte = 0;
    }

    skipSplitByte() {
        if(this.bytePosition < 3){
            return;
        }
        if(this.data[this.bytePosition - 2] === 0x00 && this.data[this.bytePosition - 1] === 0x00 && this.data[this.bytePosition] === 0x03){
            this.bytePosition++;
            this.bitPosition = 0;
        }
    }
    
    readU(n) {
        let value = 0;
        for (let i = 0; i < n; i++) {
            if (this.bitPosition === 0) {
                this.skipSplitByte();
                this.currentByte = this.data[this.bytePosition++] || 0;
            }
            value = (value << 1) | ((this.currentByte >> (7 - this.bitPosition)) & 1);
            this.bitPosition = (this.bitPosition + 1) % 8;
        }
        return value;
    }
    
    readUE() {
        let leadingZeroBits = 0;
        while (this.readU(1) === 0) {
            leadingZeroBits++;
        }
        
        if (leadingZeroBits === 0) {
            return 0;
        }
        
        const value = this.readU(leadingZeroBits);
        return (1 << leadingZeroBits) - 1 + value;
    }
    
    readSE() {
        const value = this.readUE();
        if (value === 0) {
            return 0;
        }
        
        return (value % 2 === 1) ? (value + 1) / 2 : -(value / 2);
    }
    
    getPosition() {
        console.log("bytePosition:", this.bytePosition, 'bitPosition:', this.bitPosition);
        return this.bytePosition - (this.bitPosition > 0 ? 1 : 0);
    }
    
    isEnd() {
        return this.bytePosition >= this.data.length && this.bitPosition === 0;
    }
}