UNPKG

realview.js

Version:

RealView.js - High-performance video decoder for the browser

165 lines (164 loc) 5.43 kB
function ExpGolomInit(view, bitoffset) { let bit = 0; let byteoffset = bitoffset >> 3; let skip = bitoffset & 7; let zeros = -1; let byt = view.getUint8(byteoffset) << skip; do { bit = byt & 0x80; byt <<= 1; zeros++; skip++; if (skip === 8) { skip = 0; byteoffset++; byt = view.getUint8(byteoffset); } } while (!bit); return { zeros, skip, byt, byteoffset }; } class Bitstream { constructor(view) { this.view = view; this.bitoffset = 0; } ExpGolomb() { const { view } = this; let { zeros, skip, byt, byteoffset } = ExpGolomInit(view, this.bitoffset); let code = 1; while (zeros > 0) { code = (code << 1) | ((byt & 0x80) >>> 7); byt <<= 1; skip++; zeros--; if (skip === 8) { skip = 0; byteoffset++; byt = view.getUint8(byteoffset); } } this.bitoffset = (byteoffset << 3) | skip; return code - 1; } SkipExpGolomb() { const { zeros, skip, byteoffset } = ExpGolomInit(this.view, this.bitoffset); this.bitoffset = (byteoffset << 3) + skip + zeros; } SignedExpGolomb() { const code = this.ExpGolomb(); return code & 1 ? (code + 1) >>> 1 : -(code >>> 1); } readBit() { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >> 3; this.bitoffset++; return ((this.view.getUint8(byteoffset) >> (7 - skip)) & 1); } } function scaling_list(stream, sizeOfScalingList) { let lastScale = 8; let nextScale = 8; for (let j = 0; j < sizeOfScalingList; j++) { if (nextScale !== 0) { const deltaScale = stream.SignedExpGolomb(); nextScale = (lastScale + deltaScale + 256) % 256; } if (nextScale) { lastScale = nextScale; } } } export function parseSPS(nal) { const stream = new Bitstream(new DataView(nal.buffer, nal.byteOffset + 4)); const profile_idc = nal[1]; const profile_compatibility = nal[2]; const level_idc = nal[3]; stream.SkipExpGolomb(); // seq_parameter_set_id if (profile_idc === 100 || profile_idc === 110 || profile_idc === 122 || profile_idc === 244 || profile_idc === 44 || profile_idc === 83 || profile_idc === 86 || profile_idc === 118 || profile_idc === 128) { const chroma_format_idc = stream.ExpGolomb(); let limit = 8; if (chroma_format_idc === 3) { limit = 12; stream.bitoffset++; // separate color plane flag } stream.SkipExpGolomb(); // bit_depth_luma_minus8 stream.SkipExpGolomb(); // bit_depth_chroma_minus8 stream.bitoffset++; // qpprime_y_zero_transform_bypass_flag if (stream.readBit()) { //seq_scaling_matrix_present_flag let i = 0; for (; i < 6; i++) { if (stream.readBit()) { //seq_scaling_list_present_flag scaling_list(stream, 16); } } for (; i < limit; i++) { if (stream.readBit()) { //seq_scaling_list_present_flag scaling_list(stream, 64); } } } } stream.SkipExpGolomb(); // log2_max_frame_num_minus4 const pic_order_cnt_type = stream.ExpGolomb(); if (pic_order_cnt_type === 0) { stream.ExpGolomb(); // log2_max_pic_order_cnt_lsb_minus4 } else if (pic_order_cnt_type === 1) { stream.bitoffset++; // delta_pic_order_always_zero_flag stream.SkipExpGolomb(); // offset_for_non_ref_pic se(v) stream.SkipExpGolomb(); // offset_for_top_to_bottom_field se(v) const num_ref_frames_in_pic_order_cnt_cycle = stream.ExpGolomb(); for (let i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { stream.ExpGolomb(); // offset_for_ref_frame[i] se(v) } } stream.SkipExpGolomb(); // max_num_ref_frames stream.bitoffset++; // gaps_in_frame_num_value_allowed_flag const pic_width_in_mbs = stream.ExpGolomb() + 1; const pic_height_in_map_units = stream.ExpGolomb() + 1; const frame_mbs_only_flag = stream.readBit(); if (!frame_mbs_only_flag) { stream.bitoffset++; // mb_adaptive_frame_field_flag } stream.bitoffset++; // direct_8x8_inference_flag const frame_cropping_flag = stream.readBit(); let left_offset = 0; let right_offset = 0; let top_offset = 0; let bottom_offset = 0; if (frame_cropping_flag) { left_offset = stream.ExpGolomb(); right_offset = stream.ExpGolomb(); top_offset = stream.ExpGolomb(); bottom_offset = stream.ExpGolomb(); } /* vui_parameters_present_flag u(1) if(vui_parameters_present_flag) vui_parameters() */ return { profile_idc, level_idc, profile_compatibility, frame_mbs_only_flag, pic_width_in_mbs, pic_height_in_map_units, frame_cropping_flag, frame_cropping: { left: left_offset, right: right_offset, top: top_offset, bottom: bottom_offset, }, }; }