大部分解析原理與 SPS 幀相同,但需要注意的是,PSP 幀加入了使用 “有符號的指數哥倫布編碼” ( 就是包含正數與負數的意思 )。
C # :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PPSDecoder : MonoBehaviour
{
unsafe void Start ()
{
byte[] strArray = GetPPS_ReadFile ("C:/B.h264");
int bytePosition = 0, bitPosition = 0;
int pic_parameter_set_id = get_uev_code_num (strArray, &bytePosition, &bitPosition);
int seq_parameter_set_id = get_uev_code_num (strArray, &bytePosition, &bitPosition);
int entropy_coding_mode_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
int pic_order_present_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
int num_slice_groups_minus1 = get_uev_code_num (strArray, &bytePosition, &bitPosition);
if(num_slice_groups_minus1 > 0){
throw new UnityException ("不支援此格式的檔案");
}
int num_ref_idx_l0_active_minus1 = get_uev_code_num (strArray, &bytePosition, &bitPosition);
int num_ref_idx_l1_active_minus1 = get_uev_code_num (strArray, &bytePosition, &bitPosition);
int weighted_pred_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
int weighted_bipred_idc = get_bit_at_position(strArray, &bytePosition, &bitPosition) << 1 + get_bit_at_position(strArray, &bytePosition, &bitPosition);
int pic_init_qp_minus26 = get_sev_code_num (strArray, &bytePosition, &bitPosition);
int pic_init_qs_minus26 = get_sev_code_num (strArray, &bytePosition, &bitPosition);
int chroma_qp_index_offset = get_sev_code_num (strArray, &bytePosition, &bitPosition);
int deblocking_filter_control_present_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
int constrained_intra_pred_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
int redundant_pic_cnt_present_flag = get_bit_at_position(strArray, &bytePosition, &bitPosition);
print ("pic_parameter_set_id = " + pic_parameter_set_id);
print ("seq_parameter_set_id = " + seq_parameter_set_id);
print ("entropy_coding_mode_flag = " + entropy_coding_mode_flag);
print ("pic_order_present_flag = " + pic_order_present_flag);
print ("num_slice_groups_minus1 = " + num_slice_groups_minus1);
print ("num_ref_idx_l0_active_minus1 = " + num_ref_idx_l0_active_minus1);
print ("num_ref_idx_l1_active_minus1 = " + num_ref_idx_l1_active_minus1);
print ("weighted_pred_flag = " + weighted_pred_flag);
print ("weighted_bipred_idc = " + weighted_bipred_idc);
print ("pic_init_qp_minus26 = " + pic_init_qp_minus26);
print ("pic_init_qs_minus26 = " + pic_init_qs_minus26);
print ("chroma_qp_index_offset = " + chroma_qp_index_offset);
print ("deblocking_filter_control_present_flag = " + deblocking_filter_control_present_flag);
print ("constrained_intra_pred_flag = " + constrained_intra_pred_flag);
print ("redundant_pic_cnt_present_flag = " + redundant_pic_cnt_present_flag);
}
unsafe int get_bit_at_position (byte[] buf, int*bytePotion, int*bitPosition)
{
int mask = 0, val = 0;
mask = 1 << (7 - *bitPosition);
val = ((buf [*bytePotion] & mask) != 0) ? 1 : 0;
if (++*bitPosition > 7) {
*bytePotion = *bytePotion + 1;
*bitPosition = 0;
}
return val;
}
// 無符號指數哥倫布編碼 (只有正數)
unsafe int get_uev_code_num (byte[] buf, int*bytePotion, int*bitPosition)
{
int val = 0, prefixZeroCount = 0;
int prefix = 0, surfix = 0;
while (true) {
val = get_bit_at_position (buf, bytePotion, bitPosition);
if (val == 0) {
prefixZeroCount++;
} else {
break;
}
}
prefix = (1 << prefixZeroCount) - 1;
for (int i = 0; i < prefixZeroCount; i++) {
val = get_bit_at_position (buf, bytePotion, bitPosition);
surfix += val * (1 << (prefixZeroCount - i - 1));
}
prefix += surfix;
return prefix;
}
// 有符號指數哥倫布編碼 ( 就是包含正數與負數的意思 )
unsafe int get_sev_code_num (byte[] buf, int*bytePotion, int*bitPosition)
{
int uev = get_uev_code_num (buf, bytePotion, bitPosition);
int sign = uev % 2 == 0 ? -1 : 1;
int sev = sign * ((uev + 1) >> 1);
return sev;
}
byte [] GetPPS_ReadFile (string H264_File_Path)
{
List<byte[]> NALU_List = GetNALU_ReadFile (H264_File_Path);
foreach (byte[] bArray in NALU_List) {
if (bArray [0] == 0x68) {
byte[] b = new byte[bArray.Length - 1];
for (int i = 0, k = 1; i < b.Length; i++, k++) {
b [i] = bArray [k];
}
return b;
}
}
return null;
}
List<byte []> GetNALU_ReadFile (string H264_File_Path)
{
byte[] b = System.IO.File.ReadAllBytes (H264_File_Path);
List<int> index = new List<int> ();
for (int i = 0; i < b.Length - 3; i++) {
if (b [i] == 0x00 && b [i + 1] == 0x00 && b [i + 2] == 0x01) {
index.Add (i + 3);
}
}
List<byte[]> NALU_List = new List<byte[]> ();
for (int i = 0; i < index.Count - 1; i++) {
int start = index [i];
int end = index [i + 1];
int size = end - start;
byte[] nalu = new byte[size - 3];
for (int x = 0, k = start; k < end - 3; x++, k++) {
nalu [x] = b [k];
}
NALU_List.Add (nalu);
}
return NALU_List;
}
}