c原文路径 :https://blog.csdn.net/caoshangpa/article/details/53083410
调用方式
//数据不含H264的头0x000001 let testArr = new Uint8Array( [103, 66, 192, 41, 218, 3, 32, 77, 249, 102, 160, 33, 160, 40, 0, 0, 0, 8, 0, 0, 0, 244, 120, 193, 149, 149, 149]); console.log(testArr,h264_decode_sps(testArr,testArr.length)); //{fps: 15, width: 800, height: 608}
结果展示,取值成功返回 {fps,width,height} 取值失败返回null
以下为修改的js版本:
function Ue(pBuff, nLen, nStartBit) { //计算0bit的个数 let nZeroNum = 0; while (nStartBit.StartBit < nLen * 8) { if (pBuff[Math.floor(nStartBit.StartBit / 8)] & (0x80 >> (nStartBit.StartBit % 8))) //&:按位与,%取余 { break; } nZeroNum++; nStartBit.StartBit++; } nStartBit.StartBit++; //计算结果 let dwRet = 0; for (let i = 0; i < nZeroNum; i++) { dwRet <<= 1; if (pBuff[Math.floor(nStartBit.StartBit / 8)] & (0x80 >> (nStartBit.StartBit % 8))) { dwRet += 1; } nStartBit.StartBit++; } return (1 << nZeroNum) - 1 + dwRet; } function Se(pBuff, nLen, nStartBit) { let UeVal = Ue(pBuff, nLen, nStartBit); let k = UeVal; let nValue = Math.ceil(k / 2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00 if (UeVal % 2 == 0) nValue = -nValue; return nValue; } function u(BitCount, buf, nStartBit) { let dwRet = 0; for (let i = 0; i < BitCount; i++) { dwRet <<= 1; if (buf[Math.floor(nStartBit.StartBit / 8)] & (0x80 >> (nStartBit.StartBit % 8))) { dwRet += 1; } nStartBit.StartBit++; } return dwRet; } /** * H264的NAL起始码防竞争机制 * * @param buf SPS数据内容 * * @无返回值 */ function de_emulation_prevention(buf, buf_size) { let i = 0, j = 0; let tmp_ptr = null; let tmp_buf_size = 0; let val = 0; tmp_ptr = buf; tmp_buf_size = buf_size; for (i = 0; i < (tmp_buf_size - 2); i++) { //check for 0x000003 val = (tmp_ptr[i] ^ 0x00) + (tmp_ptr[i + 1] ^ 0x00) + (tmp_ptr[i + 2] ^ 0x03); if (val == 0) { //kick out 0x03 for (j = i + 2; j < tmp_buf_size - 1; j++) tmp_ptr[j] = tmp_ptr[j + 1]; //and so we should devrease bufsize buf_size--; } } return buf_size; } /** * 解码SPS,获取视频图像宽、高和帧率信息 * * @param {Uint8Array} buf SPS数据内容 * @param {Number} nLen SPS数据的长度 * @returns {Object|null} 取值成功返回 {fps,width,height} 取值失败返回null */ function h264_decode_sps(buf, nLen) { let width = 0, height = 0, fps = 0; let StartBit = { StartBit: 0 }; nLen = de_emulation_prevention(buf, nLen); let forbidden_zero_bit = u(1, buf, StartBit); let nal_ref_idc = u(2, buf, StartBit); let nal_unit_type = u(5, buf, StartBit); if (nal_unit_type == 7) { let profile_idc = u(8, buf, StartBit); let constraint_set0_flag = u(1, buf, StartBit);//(buf[1] & 0x80)>>7; let constraint_set1_flag = u(1, buf, StartBit);//(buf[1] & 0x40)>>6; let constraint_set2_flag = u(1, buf, StartBit);//(buf[1] & 0x20)>>5; let constraint_set3_flag = u(1, buf, StartBit);//(buf[1] & 0x10)>>4; let reserved_zero_4bits = u(4, buf, StartBit); let level_idc = u(8, buf, StartBit); let seq_parameter_set_id = Ue(buf, nLen, StartBit); if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) { let chroma_format_idc = Ue(buf, nLen, StartBit); if (chroma_format_idc == 3) { let residual_colour_transform_flag = u(1, buf, StartBit); } let bit_depth_luma_minus8 = Ue(buf, nLen, StartBit); let bit_depth_chroma_minus8 = Ue(buf, nLen, StartBit); let qpprime_y_zero_transform_bypass_flag = u(1, buf, StartBit); let seq_scaling_matrix_present_flag = u(1, buf, StartBit); let seq_scaling_list_present_flag = new Array(8); if (seq_scaling_matrix_present_flag) { for (let i = 0; i < 8; i++) { seq_scaling_list_present_flag[i] = u(1, buf, StartBit); } } } let log2_max_frame_num_minus4 = Ue(buf, nLen, StartBit); let pic_order_cnt_type = Ue(buf, nLen, StartBit); if (pic_order_cnt_type == 0) { let log2_max_pic_order_cnt_lsb_minus4 = Ue(buf, nLen, StartBit); } else if (pic_order_cnt_type == 1) { let delta_pic_order_always_zero_flag = u(1, buf, StartBit); let offset_for_non_ref_pic = Se(buf, nLen, StartBit); let offset_for_top_to_bottom_field = Se(buf, nLen, StartBit); let num_ref_frames_in_pic_order_cnt_cycle = Ue(buf, nLen, StartBit); let offset_for_ref_frame = new Array(num_ref_frames_in_pic_order_cnt_cycle); for (let i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) offset_for_ref_frame[i] = Se(buf, nLen, StartBit); offset_for_ref_frame = null; } let num_ref_frames = Ue(buf, nLen, StartBit); let gaps_in_frame_num_value_allowed_flag = u(1, buf, StartBit); let pic_width_in_mbs_minus1 = Ue(buf, nLen, StartBit); let pic_height_in_map_units_minus1 = Ue(buf, nLen, StartBit); width = (pic_width_in_mbs_minus1 + 1) * 16; height = (pic_height_in_map_units_minus1 + 1) * 16; let frame_mbs_only_flag = u(1, buf, StartBit); if (!frame_mbs_only_flag) { let mb_adaptive_frame_field_flag = u(1, buf, StartBit); } let direct_8x8_inference_flag = u(1, buf, StartBit); let frame_cropping_flag = u(1, buf, StartBit); if (frame_cropping_flag) { let frame_crop_left_offset = Ue(buf, nLen, StartBit); let frame_crop_right_offset = Ue(buf, nLen, StartBit); let frame_crop_top_offset = Ue(buf, nLen, StartBit); let frame_crop_bottom_offset = Ue(buf, nLen, StartBit); } let vui_parameter_present_flag = u(1, buf, StartBit); if (vui_parameter_present_flag) { let aspect_ratio_info_present_flag = u(1, buf, StartBit); if (aspect_ratio_info_present_flag) { let aspect_ratio_idc = u(8, buf, StartBit); if (aspect_ratio_idc == 255) { let sar_width = u(16, buf, StartBit); let sar_height = u(16, buf, StartBit); } } let overscan_info_present_flag = u(1, buf, StartBit); if (overscan_info_present_flag) { let overscan_appropriate_flagu = u(1, buf, StartBit); } let video_signal_type_present_flag = u(1, buf, StartBit); if (video_signal_type_present_flag) { let video_format = u(3, buf, StartBit); let video_full_range_flag = u(1, buf, StartBit); let colour_description_present_flag = u(1, buf, StartBit); if (colour_description_present_flag) { let colour_primaries = u(8, buf, StartBit); let transfer_characteristics = u(8, buf, StartBit); let matrix_coefficients = u(8, buf, StartBit); } } let chroma_loc_info_present_flag = u(1, buf, StartBit); if (chroma_loc_info_present_flag) { let chroma_sample_loc_type_top_field = Ue(buf, nLen, StartBit); let chroma_sample_loc_type_bottom_field = Ue(buf, nLen, StartBit); } let timing_info_present_flag = u(1, buf, StartBit); if (timing_info_present_flag) { let num_units_in_tick = u(32, buf, StartBit); let time_scale = u(32, buf, StartBit); fps = time_scale / num_units_in_tick; let fixed_frame_rate_flag = u(1, buf, StartBit); if (fixed_frame_rate_flag) { fps = fps / 2; } } } return { fps, width, height }; } else return null; } export { h264_decode_sps }
补充说明
timing_info_present_flag等于1表示num_units_in_tick,time_scale和fixed_frame_rate_flag在比特流中存在。
timing_info_present_flag等于0表示num_units_in_tick,time_scale和fixed_frame_rate_flag在比特流中不存在。
因此,当timing_info_present_flag等于0时,无法得到码率, h264_decode_sps(buf,nLen)的返回值不为null并且fps返回值为0时,可据此设置一个默认帧率。