Unity 3D : C# 解析 H.264 PPS 幀

大部分解析原理與 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;
    }
}

執行結果:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_38884324/article/details/80145110