UNPKG

h264-pps-parser

Version:
201 lines (183 loc) 6.54 kB
import { Bitstream, SPSInfo } from 'h264-sps-parser'; export { SPSInfo }; export type PPSInfo = { pps_id: number; sps_id: number; entropy_coding_mode_flag: 0|1; bottom_field_pic_order_in_frame_present_flag: 0|1; num_slice_groups: number; slice_group_map_type: number; run_length: number[]; top_left: number[]; bottom_right: number[]; slice_group_change_direction_flag: 0|1; slice_group_change_rate: number; pic_size_in_map_units: number; slice_group_id: number[]; num_refs_idx_10_default_active: number; num_refs_idx_11_default_active: number; weighted_pred_flag: 0|1; weighted_bipred_idc: number; pic_init_qp: number; pic_init_qs: number; chroma_qp_index_offset: number; deblocking_filter_control_present_flag: number; constrained_intra_pred_flag: 0|1; redundant_pic_cnt_present_flag: 0|1; transform_8x8_mode_flag: 0|1; pic_scaling_matrix_present_flag: 0|1; pic_scaling_list_present_flag: (0|1)[]; scaling_list_4x4: number[][]; scaling_list_8x8: number[][]; use_default_scaling_matrix_4x4_flag: (0|1)[]; use_default_scaling_matrix_8x8_flag: (0|1)[]; second_chroma_qp_index_offset: number; }; function scaling_list(stream: Bitstream, sizeOfScalingList: number, use_default: number[], i: number): number[] { let lastScale = 8; let nextScale = 8; const scalingList = []; for (let j = 0; j < sizeOfScalingList; j++) { if (nextScale !== 0) { const deltaScale = stream.SignedExpGolomb(); nextScale = (lastScale + deltaScale + 256) % 256; use_default[i] = +(j === 0 && nextScale === 0); } if (nextScale) { lastScale = nextScale; } scalingList[j] = lastScale; } return scalingList; } export function parse(nalu: Uint8Array, spss: Map<number, SPSInfo>): PPSInfo { if ((nalu[0] & 0x1F) !== 8) throw new Error("Not a PPS unit"); const stream = new Bitstream(new DataView(nalu.buffer, nalu.byteOffset + 1)); const pps_id = stream.ExpGolomb(); const sps_id = stream.ExpGolomb(); const entropy_coding_mode_flag: 0|1 = stream.readBit(); const bottom_field_pic_order_in_frame_present_flag: 0|1 = stream.readBit(); const num_slice_groups = stream.ExpGolomb() + 1; let slice_group_map_type = 0; let slice_group_change_direction_flag: 0|1 = 0; let slice_group_change_rate = 0; let pic_size_in_map_units = 0; const run_length: number[] = []; const top_left: number[] = []; const bottom_right: number[] = []; const slice_group_id: number[] = []; if (num_slice_groups > 1) { slice_group_map_type = stream.ExpGolomb(); switch (slice_group_map_type) { case 0: { for (let i = 0; i < num_slice_groups; i++) { run_length[i] = stream.ExpGolomb() + 1; } break; } case 2: { for (let i = 0; i < num_slice_groups; i++) { top_left[i] = stream.ExpGolomb(); bottom_right[i] = stream.ExpGolomb(); } break; } case 3: case 4: case 5: { slice_group_change_direction_flag = stream.readBit(); slice_group_change_rate = stream.ExpGolomb() + 1; break; } case 6: { pic_size_in_map_units = stream.ExpGolomb() + 1; for (let i = 0; i < pic_size_in_map_units; i++) { slice_group_id[i] = stream.ExpGolomb(); } } } } const num_refs_idx_10_default_active = stream.ExpGolomb(); const num_refs_idx_11_default_active = stream.ExpGolomb(); const weighted_pred_flag: 0|1 = stream.readBit(); const weighted_bipred_idc = (stream.readBit() << 1) | stream.readBit(); const pic_init_qp = stream.SignedExpGolomb() + 26; const pic_init_qs = stream.SignedExpGolomb() + 26; const chroma_qp_index_offset = stream.SignedExpGolomb(); const deblocking_filter_control_present_flag: 0|1 = stream.readBit(); const constrained_intra_pred_flag: 0|1 = stream.readBit(); const redundant_pic_cnt_present_flag: 0|1 = stream.readBit(); let transform_8x8_mode_flag: 0|1 = 0; let pic_scaling_matrix_present_flag: 0|1 = 0; let second_chroma_qp_index_offset = 0; const pic_scaling_list_present_flag: (0|1)[] = []; const scaling_list_4x4: number[][] = []; const scaling_list_8x8: number[][] = []; const use_default_scaling_matrix_4x4_flag: (0|1)[] = []; const use_default_scaling_matrix_8x8_flag: (0|1)[] = []; if (stream.more_rbsp_data()) { transform_8x8_mode_flag = stream.readBit(); pic_scaling_matrix_present_flag = stream.readBit(); if (pic_scaling_matrix_present_flag) { for (let i = 0; i < 6; i++) { const f: 0|1 = stream.readBit(); pic_scaling_list_present_flag[i] = f; if (f) { scaling_list_4x4.push( scaling_list( stream, 16, use_default_scaling_matrix_4x4_flag, i, ) ); } } if (transform_8x8_mode_flag) { const { chroma_format_idc } = spss.get(sps_id) as SPSInfo; const limit = chroma_format_idc === 3 ? 6 : 2; for (let i = 0; i < limit; i++) { const f: 0|1 = stream.readBit(); pic_scaling_list_present_flag[i + 6] = f; if (f) { scaling_list_8x8.push( scaling_list( stream, 64, use_default_scaling_matrix_8x8_flag, i, ) ); } } } } second_chroma_qp_index_offset = stream.SignedExpGolomb(); } return { pps_id, sps_id, entropy_coding_mode_flag, bottom_field_pic_order_in_frame_present_flag, num_slice_groups, slice_group_map_type, run_length, top_left, bottom_right, slice_group_change_direction_flag, slice_group_change_rate, pic_size_in_map_units, slice_group_id, num_refs_idx_10_default_active, num_refs_idx_11_default_active, weighted_pred_flag, weighted_bipred_idc, pic_init_qp, pic_init_qs, chroma_qp_index_offset, deblocking_filter_control_present_flag, constrained_intra_pred_flag, redundant_pic_cnt_present_flag, transform_8x8_mode_flag, pic_scaling_matrix_present_flag, pic_scaling_list_present_flag, scaling_list_4x4, scaling_list_8x8, use_default_scaling_matrix_4x4_flag, use_default_scaling_matrix_8x8_flag, second_chroma_qp_index_offset, }; }