Something about Exp-Golomb codes in H.264 sps

 When I was parsing the sps information of H264, I found some special symbol like u(1),  ue(v), se(v), it's an Exp-Golomb codes, so what is Exp-Golomb codes? You can refer to this link:http://en.wikipedia.org/wiki/Exponential-Golomb_coding, and now I'm going to tell you how to parse the codes.

   In the H.264 Standerd documentation, it says that Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. Syntax elements coded as te(v) are truncated Exp-Golomb-coded. The parsing process for these syntax elements begins with reading the bits starting at the current location in the bitstream up to and including the first non-zero bit, and counting the number of leading bits that are equal to 0. The process is specified as follows:           

leadingZeroBits = -1; 
for(b = 0; !b; leadingZeroBits ++) 
    b = read_bits(1);

The variable codeNum is then assigned as follows:

codeNum = 2^leadingZeroBits - 1 + read_bits(leadingZeroBits);

So we can get the codeNum like this:

   All these information comes from ITU-T Rec.H.264(03/2005), up is a sample used as ue(v). And now I'm telling you how to use this code to parse the sps information by java code.

   We can see the sps struct is like this:

   

   Here is the parse function:

 

// Parameters:
	// data - pointer to NAL unit
	// len - NAL unit length
	// frmDimension - LOW WORD: frame width; HIGH WORD: frame height
	// Note: the NAL unit type should be NALU_TYPE_SEQUENCE_PARAMETER_SET(7)
	public boolean NAL_retrieveFrameDimension(byte data[], int offset, int len) {

		//byte pData[] = data;
		//int dataLen = len;
		
		byte [] pData = new byte[len];
		System.arraycopy(data, offset, pData, 0, len );
		int dataLen = len;		
		
		// filter RBSP for slice_header:slice_type parsing
		//byte rbspBuf[] = new byte[SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH];
		byte [] rbspBuf = new byte[SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH];
		int rbspByteNum = 0;
		// let's extract first SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH(768) bytes
		// in RBSP
		// for slice_type determination
		for (int i = 1; i < dataLen; i++) // index i start from 1: we should
											// skip the NAL heade byte
		{
			// Don't take emulation_prevention_three_byte(0x03) into account
			if ((i + 2) < dataLen
					&& ((pData[i + 0] == 0) && (pData[i + 1] == 0) && (pData[i + 2] == 3))) {
				if (rbspByteNum < SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH)
					rbspBuf[rbspByteNum++] = pData[i];
				if (rbspByteNum < SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH)
					rbspBuf[rbspByteNum++] = pData[i + 1];

				i += 2;
			} else {
				if (rbspByteNum < SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH)
					rbspBuf[rbspByteNum++] = pData[i];
			}

			if (rbspByteNum >= SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH)
				break;
		}

		currentOperatedOffset = 0;
		int leadingZeroBits = 0;
		int val = 0;
		// get profile id
		m_profileID = (short) nextBits(rbspBuf, currentOperatedOffset, 8,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		// skip constraint flags and reserved zero bites
		System.out.println("profile_idc====>" + m_profileID);
		currentOperatedOffset += 8;
		// get level id
		m_levelID = (short) nextBits(rbspBuf, currentOperatedOffset, 8,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		System.out.println("leved_idc====>" + m_levelID);
		// retrieve seq_parameter_set_id
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 32)
			leadingZeroBits++;
		m_seqParamSetID = (short) ((1 << leadingZeroBits) - 1 + nextBits(
				rbspBuf, currentOperatedOffset, leadingZeroBits,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH));
		System.out.println("seq_parameter_set_id====>" + m_seqParamSetID);
		// skip extra bits in case that the profile id is 100/110/122/144
		if ((m_profileID == H264_PROFILE_ID_HIGH)
				|| (m_profileID == H264_PROFILE_ID_HIGH10)
				|| (m_profileID == H264_PROFILE_ID_HIGH422)
				|| (m_profileID == H264_PROFILE_ID_HIGH444)) {
			// skip chroma_format_idc
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			val = (1 << leadingZeroBits)
					- 1
					+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
							SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			if (val == 3)
				currentOperatedOffset++; // skip residual_colour_transform_flag
			// skip bit_depth_luma_minus8
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			// skip bit_depth_chroma_minus8
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			// skip qpprime_y_zero_transform_bypass_flag
			currentOperatedOffset++;
			// get seq_scaling_matrix_present_flag
			boolean seq_scaling_matrix_present_flag = nextBits(rbspBuf,
					currentOperatedOffset, 1, SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) != 0;
			if (seq_scaling_matrix_present_flag) {
				for (int i = 0; i < 8; i++) {
					boolean seq_scaling_list_present_flag = nextBits(rbspBuf,
							currentOperatedOffset, 1,
							SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) != 0;
					if (seq_scaling_list_present_flag) {
						if (i < 6)
							SkipScalingList(16, rbspBuf, currentOperatedOffset);
						else
							SkipScalingList(64, rbspBuf, currentOperatedOffset);
					}
				}
			}
		}
		// retrieve m_log2_max_frame_num_minus4
		leadingZeroBits = 0;
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 32)
			leadingZeroBits++;
		m_log2_max_frame_num_minus4 = (1 << leadingZeroBits)
				- 1
				+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		// skip pic_order_cnt_type and associated data
		leadingZeroBits = 0;
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 32)
			leadingZeroBits++;
		val = (1 << leadingZeroBits)
				- 1
				+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		if (val == 0) {
			// skip log2_max_pic_order_cnt_lsb_minus4
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		} else if (val == 1) {
			// skip delta_pic_always_zero_flag
			currentOperatedOffset++;
			// skip offset_for_non_ref_pic
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			// skip offset_for_top_to_bottom_field
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			// retrieve num_ref_frames_in_pic_order_cnt_cycle
			leadingZeroBits = 0;
			while (nextBits(rbspBuf, currentOperatedOffset, 1,
					SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
					&& leadingZeroBits < 32)
				leadingZeroBits++;
			int num_ref_frames_in_pic_order_cnt_cycle = (1 << leadingZeroBits)
					- 1
					+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
							SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			// skip offset_for_ref_frame[i]
			for (int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
				leadingZeroBits = 0;
				while (nextBits(rbspBuf, currentOperatedOffset, 1,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
						&& leadingZeroBits < 32)
					leadingZeroBits++;
				nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
			}
		}
		// skip num_ref_frames
		leadingZeroBits = 0;
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 32)
			leadingZeroBits++;
		nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		// skip gaps_in_frame_num_value_allowed_flag
		currentOperatedOffset++;
		// retrieve pic_width_in_mbs_minus1
		leadingZeroBits = 0;
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 128)
			leadingZeroBits++;
		val = (((int)(1L << leadingZeroBits)) & 0xFFFFFFFF)
				- 1
				+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		m_picWidthSampleLuma = (short) ((val + 1) << 4); // PicWidthInSampleLuma
															// =
															// PicWidthInMbs*16
		// retrieve pic_height_in_map_units_minus1
		leadingZeroBits = 0;
		while (nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
				&& leadingZeroBits < 128)
			leadingZeroBits++;
		val = ((int)(1L << leadingZeroBits) & 0xFFFFFFFF)
				- 1
				+ nextBits(rbspBuf, currentOperatedOffset, leadingZeroBits,
						SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH);
		// retrieve frame_mbs_only_flag
		m_bFrameMbsOnlyFlag = nextBits(rbspBuf, currentOperatedOffset, 1,
				SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) != 0;
		if (m_bFrameMbsOnlyFlag) {
			val = (2 - 1) * (val + 1); // FrameHeightInMbs =
										// (2-frame_mbs_only_flag)*(pic_height_in_map_units_minus1+1)
			m_frameHeightInMbs = (short) val;
			val = val / (1 + 0); // PicHeightInMbs =
									// FrameHeightInMbs/(1+field_pic_flag)
			m_picHeightSampleLuma = (short) (val << 4); // PicHeightInSampleLuma
														// = PicHeightInMbs*16
			if (m_picHeightSampleLuma == 128)
				m_picHeightSampleLuma = 120;
			m_dimensionPixel = (m_picWidthSampleLuma << 16)
					| m_picHeightSampleLuma;
		} else {
			val = (2 - 0) * (val + 1); // FrameHeightInMbs =
										// (2-frame_mbs_only_flag)*(pic_height_in_map_units_minus1+1)
			m_frameHeightInMbs = (short) val;
			// val = val/(1+m_bFieldPicFlag ? 1: 0); // PicHeightInMbs =
			// FrameHeightInMbs/(1+field_pic_flag)
			// m_picHeightSampleLuma = val<<4; // PicHeightInSampleLuma =
			// PicHeightInMbs*16
			if (m_picHeightSampleLuma == 128)
				m_picHeightSampleLuma = 120;
			m_dimensionPixel = (m_picWidthSampleLuma << 16)
					| m_picHeightSampleLuma;
		}

		return true;
	}

   Function nextBits():

/** 
     * Description: read in next bitNum bits and return its value. After 
     * reading, the bit offset value is advanced bitNum bits. 
     *  
     * @param data 
     *            pointer to the data to be read 
     * @param bitOffset 
     *            the data offset from which the next bitNum bits inclusive will 
     *            be read 
     * @param bitNum 
     *            the number of bits to be read. The maximum number is 32. 
     * @param limitInBytes 
     *            maximum reachable offset in byte 
     * @return 
     */
    private int nextBits(byte data[], int bitOffset, int bitNum, 
            int limitInBytes) { 
        int limitBit = limitInBytes << 3; 
        int result = 0; 
        
        if (bitNum == 0 || bitNum < 0) 
            return result; 
        if (bitNum > 32) 
            return result; 
        if (bitOffset > limitBit) 
            return result; 
        if ((bitOffset + bitNum) > limitBit) 
            return result; 
        int skipByteNum = bitOffset >>> 3; 
        int skipBits = bitOffset % 8; 
        long src = (data[skipByteNum] << skipBits); 
        int leftBits = 8 - skipBits; 
        for (int i = 0; i < bitNum; i++) { 
            result = result << 1; 
            if ((src & 0x80) != 0) 
                result |= 0x01; 
            src = (src << 1); 
            leftBits--; 
            if (leftBits == 0) { 
                src = data[++skipByteNum]; 
                leftBits = 8; 
            } 
        } 
        bitOffset += bitNum; 
        currentOperatedOffset += bitNum; 
        return result; 
    }

   Function SkipScalingList():

private void SkipScalingList(int size, byte data[], int bitOffset) { 
        int lastScale = 8; 
        int nextScale = 8; 
        int deltaScale = 0; 
        for (int i = 0; i < size; i++) { 
            if (nextScale != 0) { 
                int leadingZeroBits = 0; 
                // skip first_mb_in_slice data 
                while (nextBits(data, currentOperatedOffset, 1, 
                        SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH) == 0
                        && leadingZeroBits < 32) 
                    leadingZeroBits++; 
                deltaScale = (1 << leadingZeroBits) 
                        - 1
                        + nextBits(data, currentOperatedOffset, leadingZeroBits, 
                                SEQUENCE_PARAMETER_SET_TEMP_BUF_LENGTH); 
                int multi = (deltaScale & 0x1) != 0 ? 1 : -1; 
                int left = deltaScale % 2; 
                if (left == 0) 
                    deltaScale = multi * (deltaScale >> 2); 
                else { 
                    deltaScale = deltaScale / 2 + 1; 
                    deltaScale = multi * deltaScale; 
                } 
                nextScale = (lastScale + deltaScale + 256) % 256; 
            } 
      
            int scalingList = nextScale != 0 ? lastScale : nextScale; 
            lastScale = scalingList; 
        } 
    }

  By using all these code, you can parse the sps information rightly.

posted @ 2013-01-03 14:19  轩Δ辕  阅读(1516)  评论(0编辑  收藏  举报