mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-16 12:08:52 +00:00
* script changes - no arguments * script changes with 2 arguments * script changes with > 2 arguments * script conversions with 1 argument - pt. 1 * script conversions with 1 argument - pt. 2 * script conversions with 1 argument - pt. 3 * script conversions with 1 argument - pt. 4 * script conversions with 1 argument - pt. 5 Pointer format hunting * Fixed pointer format * script conversions with 1 argument - final * fixed conversion in non utf-8 file * fixed conversion with capital letter * actually fixed conversion with capital letter * fixed another capital lettering issue * Added conversions with LR removed * removed LR from logs * Converted logs that previously contained LR * converted log that originally specified string length * fixed log with commas in main text * fixed multi-line log * Fixed more logs with commas in main text * Fixed unformatted pointer * added conversion with float value * converted lines with double parameters * converted missed line * corrected argument formatting Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com> * Fixed misspellings of "unhandled" unhandeled -> unhandled Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com> --------- Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com>
1076 lines
35 KiB
C++
1076 lines
35 KiB
C++
#include "Cafe/OS/libs/h264_avc/parser/H264Parser.h"
|
|
|
|
void parse_hrd_parameters(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)
|
|
{
|
|
uint32 cpb_cnt_minus1 = nalStream.readUV_E();
|
|
uint8 bit_rate_scale = nalStream.readBits<4>();
|
|
uint8 cpb_size_scale = nalStream.readBits<4>();
|
|
for (uint8 schedSelIdx = 0; schedSelIdx <= cpb_cnt_minus1; schedSelIdx++)
|
|
{
|
|
uint32 bit_rate_value_minus1 = nalStream.readUV_E();
|
|
uint32 cpb_size_value_minus1 = nalStream.readUV_E();
|
|
uint8 cbr_flag = nalStream.readBit();
|
|
}
|
|
uint8 initial_cpb_removal_delay_length_minus1 = nalStream.readBits<5>();
|
|
uint8 cpb_removal_delay_length_minus1 = nalStream.readBits<5>();
|
|
uint8 dpb_output_delay_length_minus1 = nalStream.readBits<5>();
|
|
uint8 time_offset_length = nalStream.readBits<5>();
|
|
}
|
|
|
|
void parseNAL_scaling_list4x4(RBSPInputBitstream& rbspStream, h264_scaling_matrix4x4_t& scalingMatrix4x4)
|
|
{
|
|
if (rbspStream.readBit() == 0)
|
|
{
|
|
scalingMatrix4x4.isPresent = 0;
|
|
return;
|
|
}
|
|
scalingMatrix4x4.isPresent = 1;
|
|
|
|
cemu_assert_debug(false); // needs testing
|
|
sint32 lastScale = 8;
|
|
sint32 nextScale = 8;
|
|
for (sint32 j = 0; j < 4 * 4; j++)
|
|
{
|
|
if (nextScale != 0)
|
|
{
|
|
sint32 delta_scale = rbspStream.readSV_E();
|
|
nextScale = (lastScale + delta_scale + 256) % 256;
|
|
scalingMatrix4x4.UseDefaultScalingMatrix = (j == 0 && nextScale == 0);
|
|
}
|
|
scalingMatrix4x4.list[j] = (nextScale == 0) ? lastScale : nextScale;
|
|
lastScale = scalingMatrix4x4.list[j];
|
|
}
|
|
}
|
|
|
|
void parseNAL_scaling_list8x8(RBSPInputBitstream& rbspStream, h264_scaling_matrix8x8_t& scalingMatrix8x8)
|
|
{
|
|
if (rbspStream.readBit() == 0)
|
|
{
|
|
scalingMatrix8x8.isPresent = 0;
|
|
return;
|
|
}
|
|
scalingMatrix8x8.isPresent = 1;
|
|
|
|
cemu_assert_debug(false); // needs testing
|
|
sint32 lastScale = 8;
|
|
sint32 nextScale = 8;
|
|
for (sint32 j = 0; j < 8 * 8; j++)
|
|
{
|
|
if (nextScale != 0)
|
|
{
|
|
sint32 delta_scale = rbspStream.readSV_E();
|
|
nextScale = (lastScale + delta_scale + 256) % 256;
|
|
scalingMatrix8x8.UseDefaultScalingMatrix = (j == 0 && nextScale == 0);
|
|
}
|
|
scalingMatrix8x8.list[j] = (nextScale == 0) ? lastScale : nextScale;
|
|
lastScale = scalingMatrix8x8.list[j];
|
|
}
|
|
}
|
|
|
|
void parseNAL_pps_scaling_lists(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)
|
|
{
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[0]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[1]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[2]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[3]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[4]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[5]);
|
|
|
|
if (h264ParserState->pps.transform_8x8_mode_flag)
|
|
{
|
|
parseNAL_scaling_list8x8(nalStream, h264ParserState->pps.ScalingList8x8[0]);
|
|
parseNAL_scaling_list8x8(nalStream, h264ParserState->pps.ScalingList8x8[1]);
|
|
|
|
if (h264ParserState->sps.chroma_format_idc == 3)
|
|
cemu_assert(false); // todo - more scaling lists to parse
|
|
}
|
|
}
|
|
|
|
void parseNAL_sps_scaling_lists(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)
|
|
{
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[0]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[1]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[2]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[3]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[4]);
|
|
parseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[5]);
|
|
|
|
parseNAL_scaling_list8x8(nalStream, h264ParserState->sps.ScalingList8x8[0]);
|
|
parseNAL_scaling_list8x8(nalStream, h264ParserState->sps.ScalingList8x8[1]);
|
|
|
|
if (h264ParserState->sps.chroma_format_idc == 3)
|
|
cemu_assert(false); // todo - more scaling lists to parse
|
|
}
|
|
|
|
bool parseNAL_seq_parameter_set_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, RBSPInputBitstream& nalStream)
|
|
{
|
|
memset(&h264ParserState->sps, 0, sizeof(h264State_seq_parameter_set_t));
|
|
|
|
h264ParserState->sps.profile_idc = nalStream.readU8(); // 0x64 = high profile
|
|
h264ParserState->sps.constraint = nalStream.readU8(); // 6 flags + 2 reserved bits
|
|
h264ParserState->sps.level_idc = nalStream.readU8(); // 0x29 = level 4.1
|
|
|
|
// some default values in case flags are not set
|
|
h264ParserState->sps.separate_colour_plane_flag = 0;
|
|
h264ParserState->sps.chroma_format_idc = 1; // Spec 7.4.2.1.1
|
|
h264ParserState->sps.qpprime_y_zero_transform_bypass_flag = 0;
|
|
h264ParserState->sps.seq_scaling_matrix_present_flag = 0;
|
|
//h264ParserState->sps.mb_adaptive_frame_field_flag = 0;
|
|
|
|
|
|
|
|
uint32 seq_parameter_set_id = nalStream.readUV_E();
|
|
if (h264ParserState->sps.profile_idc == 100 || h264ParserState->sps.profile_idc == 110 || h264ParserState->sps.profile_idc == 122 ||
|
|
h264ParserState->sps.profile_idc == 244 || h264ParserState->sps.profile_idc == 44 || h264ParserState->sps.profile_idc == 83 ||
|
|
h264ParserState->sps.profile_idc == 86 || h264ParserState->sps.profile_idc == 118 || h264ParserState->sps.profile_idc == 128 ||
|
|
h264ParserState->sps.profile_idc == 138 || h264ParserState->sps.profile_idc == 139 || h264ParserState->sps.profile_idc == 134 || h264ParserState->sps.profile_idc == 135)
|
|
{
|
|
h264ParserState->sps.chroma_format_idc = nalStream.readUV_E();
|
|
if (h264ParserState->sps.chroma_format_idc == 3)
|
|
{
|
|
h264ParserState->sps.separate_colour_plane_flag = nalStream.readBit();
|
|
}
|
|
h264ParserState->sps.bit_depth_luma_minus8 = nalStream.readUV_E();
|
|
h264ParserState->sps.bit_depth_chroma_minus8 = nalStream.readUV_E();
|
|
h264ParserState->sps.qpprime_y_zero_transform_bypass_flag = nalStream.readBit();
|
|
h264ParserState->sps.seq_scaling_matrix_present_flag = nalStream.readBit();
|
|
if (h264ParserState->sps.seq_scaling_matrix_present_flag)
|
|
{
|
|
parseNAL_sps_scaling_lists(h264ParserState, nalStream);
|
|
}
|
|
}
|
|
|
|
h264ParserState->sps.log2_max_frame_num_minus4 = nalStream.readUV_E();
|
|
h264ParserState->sps.pic_order_cnt_type = nalStream.readUV_E();
|
|
if (h264ParserState->sps.pic_order_cnt_type == 0)
|
|
{
|
|
h264ParserState->sps.log2_max_pic_order_cnt_lsb_minus4 = nalStream.readUV_E();
|
|
}
|
|
else if (h264ParserState->sps.pic_order_cnt_type == 2)
|
|
{
|
|
// nothing to parse
|
|
}
|
|
else
|
|
{
|
|
// todo - parse fields
|
|
cemu_assert_debug(false);
|
|
}
|
|
h264ParserState->sps.num_ref_frames = nalStream.readUV_E();
|
|
h264ParserState->sps.gaps_in_frame_num_value_allowed_flag = nalStream.readBit();
|
|
h264ParserState->sps.pic_width_in_mbs_minus1 = nalStream.readUV_E();
|
|
h264ParserState->sps.pic_height_in_map_units_minus1 = nalStream.readUV_E();
|
|
h264ParserState->sps.frame_mbs_only_flag = nalStream.readBit();
|
|
if (h264ParserState->sps.frame_mbs_only_flag == 0)
|
|
{
|
|
h264ParserState->sps.mb_adaptive_frame_field_flag = nalStream.readBit();
|
|
cemu_assert_debug(false);
|
|
}
|
|
else
|
|
h264ParserState->sps.mb_adaptive_frame_field_flag = 0; // default is zero?
|
|
|
|
h264ParserState->sps.direct_8x8_inference_flag = nalStream.readBit();
|
|
if (h264ParserState->sps.frame_mbs_only_flag == 0 && h264ParserState->sps.direct_8x8_inference_flag != 1)
|
|
{
|
|
cemu_assert_debug(false); // not allowed
|
|
}
|
|
|
|
h264ParserState->sps.frame_cropping_flag = nalStream.readBit();
|
|
if (h264ParserState->sps.frame_cropping_flag)
|
|
{
|
|
h264ParserState->sps.frame_crop_left_offset = nalStream.readUV_E();
|
|
h264ParserState->sps.frame_crop_right_offset = nalStream.readUV_E();
|
|
h264ParserState->sps.frame_crop_top_offset = nalStream.readUV_E();
|
|
h264ParserState->sps.frame_crop_bottom_offset = nalStream.readUV_E();
|
|
}
|
|
uint8 vui_parameters_present_flag = nalStream.readBit();
|
|
if (vui_parameters_present_flag)
|
|
{
|
|
// vui_parameters
|
|
uint8 aspect_ratio_info_present_flag = nalStream.readBit();
|
|
if (aspect_ratio_info_present_flag)
|
|
{
|
|
uint32 aspect_ratio_idc = nalStream.readBits<8>();
|
|
if (aspect_ratio_idc == 255) // Extended_SAR
|
|
{
|
|
uint16 sar_width = nalStream.readBits<16>();
|
|
uint16 sar_height = nalStream.readBits<16>();
|
|
}
|
|
}
|
|
uint8 overscan_info_present_flag = nalStream.readBit();
|
|
if (overscan_info_present_flag)
|
|
{
|
|
cemu_assert_debug(false);
|
|
}
|
|
uint8 video_signal_type_present_flag = nalStream.readBit();
|
|
if (video_signal_type_present_flag)
|
|
{
|
|
uint8 video_format = nalStream.readBits<3>();
|
|
uint8 video_full_range_flag = nalStream.readBit();
|
|
uint8 colour_description_present_flag = nalStream.readBit();
|
|
if (colour_description_present_flag)
|
|
{
|
|
uint8 colour_primaries = nalStream.readBits<8>();
|
|
uint8 transfer_characteristics = nalStream.readBits<8>();
|
|
uint8 matrix_coefficients = nalStream.readBits<8>();
|
|
}
|
|
}
|
|
uint8 chroma_loc_info_present_flag = nalStream.readBit();
|
|
if (chroma_loc_info_present_flag)
|
|
{
|
|
uint32 chroma_sample_loc_type_top_field = nalStream.readUV_E();
|
|
uint32 chroma_sample_loc_type_bottom_field = nalStream.readUV_E();
|
|
}
|
|
uint8 timing_info_present_flag = nalStream.readBit();
|
|
if (timing_info_present_flag)
|
|
{
|
|
uint32 num_units_in_tick = nalStream.readBits<32>();
|
|
uint32 time_scale = nalStream.readBits<32>();
|
|
uint8 fixed_frame_rate_flag = nalStream.readBits<1>();
|
|
}
|
|
uint8 nal_hrd_parameters_present_flag = nalStream.readBit();
|
|
if (nal_hrd_parameters_present_flag)
|
|
{
|
|
parse_hrd_parameters(h264ParserState, nalStream);
|
|
}
|
|
uint8 vcl_hrd_parameters_present_flag = nalStream.readBit();
|
|
if (vcl_hrd_parameters_present_flag)
|
|
{
|
|
parse_hrd_parameters(h264ParserState, nalStream);
|
|
}
|
|
if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag)
|
|
{
|
|
uint8 low_delay_hrd_flag = nalStream.readBit();
|
|
}
|
|
uint8 pic_struct_present_flag = nalStream.readBit();
|
|
uint8 bitstream_restriction_flag = nalStream.readBit();
|
|
if (bitstream_restriction_flag)
|
|
{
|
|
uint8 motion_vectors_over_pic_boundaries_flag = nalStream.readBit();
|
|
uint32 max_bytes_per_pic_denom = nalStream.readUV_E();
|
|
uint32 max_bits_per_mb_denom = nalStream.readUV_E();
|
|
uint32 log2_max_mv_length_horizontal = nalStream.readUV_E();
|
|
uint32 log2_max_mv_length_vertical = nalStream.readUV_E();
|
|
uint32 max_num_reorder_frames = nalStream.readUV_E();
|
|
uint32 max_dec_frame_buffering = nalStream.readUV_E();
|
|
}
|
|
}
|
|
// trailing bits
|
|
bool nalValid = true;
|
|
if (nalStream.readTrailingRBSPBits() == false)
|
|
nalValid = false;
|
|
if (nalValid)
|
|
{
|
|
if(output)
|
|
output->hasSPS = true;
|
|
h264ParserState->hasSPS = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool parseNAL_pic_parameter_set_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, RBSPInputBitstream& nalStream)
|
|
{
|
|
memset(&h264ParserState->pps, 0, sizeof(h264State_pic_parameter_set_t));
|
|
|
|
h264ParserState->pps.pic_parameter_set_id = nalStream.readUV_E();
|
|
h264ParserState->pps.seq_parameter_set_id = nalStream.readUV_E();
|
|
h264ParserState->pps.entropy_coding_mode_flag = nalStream.readBit();
|
|
h264ParserState->pps.bottom_field_pic_order_in_frame_present_flag = nalStream.readBit();
|
|
|
|
h264ParserState->pps.num_slice_groups_minus1 = nalStream.readUV_E();
|
|
if (h264ParserState->pps.num_slice_groups_minus1 > 0)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return false;
|
|
}
|
|
|
|
h264ParserState->pps.num_ref_idx_l0_default_active_minus1 = nalStream.readUV_E();
|
|
h264ParserState->pps.num_ref_idx_l1_default_active_minus1 = nalStream.readUV_E();
|
|
h264ParserState->pps.weighted_pred_flag = nalStream.readBit();
|
|
h264ParserState->pps.weighted_bipred_idc = nalStream.readBits<2>();
|
|
h264ParserState->pps.pic_init_qp_minus26 = nalStream.readSV_E();
|
|
h264ParserState->pps.pic_init_qs_minus26 = nalStream.readSV_E();
|
|
h264ParserState->pps.chroma_qp_index_offset = nalStream.readSV_E();
|
|
|
|
h264ParserState->pps.deblocking_filter_control_present_flag = nalStream.readBit();
|
|
h264ParserState->pps.constrained_intra_pred_flag = nalStream.readBit();
|
|
h264ParserState->pps.redundant_pic_cnt_present_flag = nalStream.readBit();
|
|
|
|
if (nalStream.more_rbsp_data())
|
|
{
|
|
h264ParserState->pps.transform_8x8_mode_flag = nalStream.readBit();
|
|
h264ParserState->pps.pic_scaling_matrix_present_flag = nalStream.readBit();
|
|
if (h264ParserState->pps.pic_scaling_matrix_present_flag)
|
|
{
|
|
parseNAL_pps_scaling_lists(h264ParserState, nalStream);
|
|
}
|
|
h264ParserState->pps.second_chroma_qp_index_offset = nalStream.readSV_E();
|
|
}
|
|
|
|
// trailing bits
|
|
bool nalValid = true;
|
|
if (nalStream.readTrailingRBSPBits() == false)
|
|
nalValid = false;
|
|
if (nalValid)
|
|
{
|
|
if(output)
|
|
output->hasPPS = true;
|
|
h264ParserState->hasPPS = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void parseNAL_ref_pic_list_modification(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)
|
|
{
|
|
if (!sliceHeader->slice_type.isSliceTypeI() && !sliceHeader->slice_type.isSliceTypeSI())
|
|
{
|
|
uint8 ref_pic_list_modification_flag_l0 = nalStream.readBit();
|
|
if (ref_pic_list_modification_flag_l0)
|
|
{
|
|
sliceHeader->pic_list_modification0Count = 0;
|
|
uint32 modType;
|
|
while(true)
|
|
{
|
|
if (sliceHeader->pic_list_modification0Count >= 32)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return;
|
|
}
|
|
modType = nalStream.readUV_E();
|
|
sliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].type = modType;
|
|
if (modType == 0 || modType == 1)
|
|
{
|
|
sliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].abs_diff_pic_num_minus1 = nalStream.readUV_E();
|
|
}
|
|
else if (modType == 2)
|
|
{
|
|
sliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].long_term_pic_num = nalStream.readUV_E();
|
|
}
|
|
else if (modType == 3)
|
|
{
|
|
// end of list
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
cemu_assert_debug(false); // invalid type
|
|
return;
|
|
}
|
|
sliceHeader->pic_list_modification0Count++;
|
|
}
|
|
}
|
|
}
|
|
if (sliceHeader->slice_type.isSliceTypeB())
|
|
{
|
|
uint8 ref_pic_list_modification_flag_l1 = nalStream.readBit();
|
|
if (ref_pic_list_modification_flag_l1)
|
|
{
|
|
cemu_assert_debug(false); // testing required
|
|
while (true)
|
|
{
|
|
if (sliceHeader->pic_list_modification1Count >= 32)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return;
|
|
}
|
|
uint32 modType = nalStream.readUV_E(); // aka modification_of_pic_nums_idc
|
|
sliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].type = modType;
|
|
if (modType == 0 || modType == 1)
|
|
{
|
|
sliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].abs_diff_pic_num_minus1 = nalStream.readUV_E();
|
|
}
|
|
else if (modType == 2)
|
|
{
|
|
sliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].long_term_pic_num = nalStream.readUV_E();
|
|
}
|
|
else if(modType == 3)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
cemu_assert_debug(false); // invalid mode
|
|
break;
|
|
}
|
|
sliceHeader->pic_list_modification0Count++;
|
|
}
|
|
if (sliceHeader->pic_list_modification1Count > 0)
|
|
{
|
|
cemuLog_logDebug(LogType::Force, "sliceHeader->pic_list_modification1Count non-zero is not supported");
|
|
cemu_assert_unimplemented();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void parseNAL_dec_ref_pic_marking(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)
|
|
{
|
|
sliceHeader->memory_management_control_operation_num = 0;
|
|
if (sliceHeader->IdrPicFlag)
|
|
{
|
|
uint8 no_output_of_prior_pics_flag = nalStream.readBit();
|
|
if (no_output_of_prior_pics_flag)
|
|
cemu_assert_debug(false);
|
|
uint8 long_term_reference_flag = nalStream.readBit();
|
|
if (long_term_reference_flag)
|
|
cemu_assert_debug(false);
|
|
|
|
sliceHeader->adaptive_ref_pic_marking_mode_flag = 1;
|
|
}
|
|
else
|
|
{
|
|
sliceHeader->adaptive_ref_pic_marking_mode_flag = nalStream.readBit();
|
|
if (sliceHeader->adaptive_ref_pic_marking_mode_flag)
|
|
{
|
|
while (true)
|
|
{
|
|
uint32 memory_management_control_operation = nalStream.readUV_E();
|
|
if (memory_management_control_operation == nal_slice_header_t::MEMOP_END)
|
|
break;
|
|
if (sliceHeader->memory_management_control_operation_num >= 16)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return;
|
|
}
|
|
sliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].op = memory_management_control_operation;
|
|
if (memory_management_control_operation == nal_slice_header_t::MEMOP_REMOVE_REF_FROM_SHORT_TERM || memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_LONG_TERM_REF)
|
|
{
|
|
sliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].difference_of_pic_nums_minus1 = nalStream.readUV_E();
|
|
}
|
|
else if (memory_management_control_operation == nal_slice_header_t::MEMOP_REMOVE_REF_FROM_LONG_TERM)
|
|
{
|
|
sliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].long_term_pic_num = nalStream.readUV_E();
|
|
}
|
|
if (memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_LONG_TERM_REF || memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_CURRENT_LONG_TERM_REF)
|
|
{
|
|
sliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].long_term_frame_idx = nalStream.readUV_E();
|
|
}
|
|
if (memory_management_control_operation == nal_slice_header_t::MEMOP_MAX_LONG_TERM_INDEX)
|
|
{
|
|
sliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].max_long_term_frame_idx_plus1 = nalStream.readUV_E();
|
|
}
|
|
sliceHeader->memory_management_control_operation_num++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void parseNAL_pred_weight_table(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)
|
|
{
|
|
uint8 luma_log2_weight_denom = nalStream.readUV_E();
|
|
|
|
uint32 ChromaArrayType;
|
|
if (sps.separate_colour_plane_flag == 0)
|
|
ChromaArrayType = sps.chroma_format_idc;
|
|
else
|
|
ChromaArrayType = 0;
|
|
|
|
if (ChromaArrayType != 0)
|
|
{
|
|
uint32 chroma_log2_weight_denom = nalStream.readUV_E();
|
|
}
|
|
|
|
for (uint32 i = 0; i <= sliceHeader->num_ref_idx_l0_active_minus1; i++)
|
|
{
|
|
uint8 luma_weight_l0_flag = nalStream.readBit();
|
|
if (luma_weight_l0_flag)
|
|
{
|
|
uint32 luma_weight_l0 = nalStream.readSV_E();
|
|
uint32 luma_offset_l0 = nalStream.readSV_E();
|
|
}
|
|
if (ChromaArrayType != 0)
|
|
{
|
|
uint8 chroma_weight_l0_flag = nalStream.readBit();
|
|
if (chroma_weight_l0_flag)
|
|
{
|
|
for (sint32 j = 0; j < 2; j++)
|
|
{
|
|
uint32 chroma_weight_l0 = nalStream.readSV_E();
|
|
uint32 chroma_offset_l0 = nalStream.readSV_E();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (sliceHeader->slice_type.isSliceTypeB())
|
|
{
|
|
for (uint32 i = 0; i <= sliceHeader->num_ref_idx_l1_active_minus1; i++)
|
|
{
|
|
uint8 luma_weight_l1_flag = nalStream.readBit();
|
|
if (luma_weight_l1_flag)
|
|
{
|
|
cemu_assert_debug(false);
|
|
//luma_weight_l1[i]
|
|
//luma_offset_l1[i]
|
|
}
|
|
if (ChromaArrayType != 0)
|
|
{
|
|
cemu_assert_debug(false);
|
|
//chroma_weight_l1_flag
|
|
//if (chroma_weight_l1_flag)
|
|
//{
|
|
// for (j = 0; j < 2; j++)
|
|
// {
|
|
// chroma_weight_l1[i][j]
|
|
// chroma_offset_l1[i][j]
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void parseNAL_slice_header(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, uint8 nal_unit_type, uint8 nal_ref_idc, nal_slice_header_t* sliceHeader)
|
|
{
|
|
bool IdrPicFlag = nal_unit_type == 5;
|
|
|
|
memset(sliceHeader, 0, sizeof(nal_slice_header_t));
|
|
sliceHeader->nal_ref_idc = nal_ref_idc;
|
|
sliceHeader->nal_unit_type = nal_unit_type;
|
|
sliceHeader->first_mb_in_slice = nalStream.readUV_E(); // address of first macroblock in slice
|
|
sliceHeader->slice_type = { nalStream.readUV_E() };
|
|
sliceHeader->pic_parameter_set_id = nalStream.readUV_E();
|
|
|
|
if (sps.separate_colour_plane_flag == 1)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return;
|
|
}
|
|
|
|
sliceHeader->frame_num = nalStream.readBits(sps.log2_max_frame_num_minus4 + 4);
|
|
|
|
if (sps.frame_mbs_only_flag == 0)
|
|
{
|
|
sliceHeader->field_pic_flag = nalStream.readBit();
|
|
if (sliceHeader->field_pic_flag)
|
|
{
|
|
sliceHeader->bottom_field_flag = nalStream.readBit();
|
|
}
|
|
}
|
|
|
|
sliceHeader->IdrPicFlag = IdrPicFlag?1:0;
|
|
|
|
if (IdrPicFlag)
|
|
{
|
|
sliceHeader->idr_pic_id = nalStream.readUV_E();
|
|
}
|
|
if (sps.pic_order_cnt_type == 0)
|
|
{
|
|
sliceHeader->pic_order_cnt_lsb = nalStream.readBits(sps.log2_max_pic_order_cnt_lsb_minus4 + 4);
|
|
if (pps.bottom_field_pic_order_in_frame_present_flag && sliceHeader->field_pic_flag == 0)
|
|
sliceHeader->delta_pic_order_cnt_bottom = nalStream.readSV_E();
|
|
}
|
|
else if (sps.pic_order_cnt_type == 1)
|
|
{
|
|
cemu_assert(false);
|
|
}
|
|
if (pps.redundant_pic_cnt_present_flag)
|
|
{
|
|
sliceHeader->redundant_pic_cnt = nalStream.readUV_E();
|
|
}
|
|
|
|
if (sliceHeader->slice_type.isSliceTypeB())
|
|
{
|
|
sliceHeader->direct_spatial_mv_pred_flag = nalStream.readBit();
|
|
}
|
|
|
|
sliceHeader->num_ref_idx_l0_active_minus1 = pps.num_ref_idx_l0_default_active_minus1;
|
|
sliceHeader->num_ref_idx_l1_active_minus1 = pps.num_ref_idx_l1_default_active_minus1;
|
|
|
|
if (sliceHeader->slice_type.isSliceTypeP() || sliceHeader->slice_type.isSliceTypeSP() || sliceHeader->slice_type.isSliceTypeB())
|
|
{
|
|
sliceHeader->num_ref_idx_active_override_flag = nalStream.readBit();
|
|
if (sliceHeader->num_ref_idx_active_override_flag)
|
|
{
|
|
sliceHeader->num_ref_idx_l0_active_minus1 = nalStream.readUV_E();
|
|
if (sliceHeader->slice_type.isSliceTypeB())
|
|
{
|
|
sliceHeader->num_ref_idx_l1_active_minus1 = nalStream.readUV_E();
|
|
}
|
|
}
|
|
}
|
|
|
|
// todo - ref_pic_list_mvc_modification etc
|
|
if (nal_unit_type == 20 || nal_unit_type == 21)
|
|
{
|
|
cemu_assert_debug(false);
|
|
}
|
|
else
|
|
{
|
|
parseNAL_ref_pic_list_modification(sps, pps, nalStream, sliceHeader);
|
|
}
|
|
|
|
if ((pps.weighted_pred_flag && (sliceHeader->slice_type.isSliceTypeP() || sliceHeader->slice_type.isSliceTypeSP())) || (pps.weighted_bipred_idc == 1 && sliceHeader->slice_type.isSliceTypeB()))
|
|
{
|
|
parseNAL_pred_weight_table(sps, pps, nalStream, sliceHeader);
|
|
}
|
|
|
|
if (sliceHeader->nal_ref_idc != 0)
|
|
{
|
|
parseNAL_dec_ref_pic_marking(sps, pps, nalStream, sliceHeader);
|
|
}
|
|
|
|
if (pps.entropy_coding_mode_flag && !sliceHeader->slice_type.isSliceTypeI() && !sliceHeader->slice_type.isSliceTypeSI())
|
|
{
|
|
uint32 cabac_init_idc = nalStream.readUV_E();
|
|
cemu_assert_debug(cabac_init_idc <= 2); // invalid value
|
|
}
|
|
|
|
sint32 slice_qp_delta = nalStream.readSV_E();
|
|
if (sliceHeader->slice_type.isSliceTypeSP() || sliceHeader->slice_type.isSliceTypeSI())
|
|
{
|
|
if (sliceHeader->slice_type.isSliceTypeSP())
|
|
{
|
|
uint8 sp_for_switch_flag = nalStream.readBit();
|
|
}
|
|
sint32 slice_qs_delta = nalStream.readSV_E();
|
|
}
|
|
|
|
if (pps.deblocking_filter_control_present_flag)
|
|
{
|
|
uint32 disable_deblocking_filter_idc = nalStream.readUV_E();
|
|
if (disable_deblocking_filter_idc != 1)
|
|
{
|
|
sint32 slice_alpha_c0_offset_div2 = nalStream.readSV_E();
|
|
sint32 slice_beta_offset_div2 = nalStream.readSV_E();
|
|
}
|
|
}
|
|
if (pps.num_slice_groups_minus1 > 0 && pps.slice_group_map_type >= 3 && pps.slice_group_map_type <= 5)
|
|
{
|
|
cemu_assert_debug(false); // todo
|
|
}
|
|
}
|
|
|
|
void _calculateFrameOrder(h264ParserState_t* h264ParserState, const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, nal_slice_header_t* sliceHeader)
|
|
{
|
|
if (sps.pic_order_cnt_type == 0)
|
|
{
|
|
// calculate TopFieldOrderCnt
|
|
uint32 prevPicOrderCntMsb;
|
|
uint32 prevPicOrderCntLsb;
|
|
if (sliceHeader->IdrPicFlag)
|
|
{
|
|
sliceHeader->calculated.TopFieldOrderCnt = 0;
|
|
|
|
prevPicOrderCntMsb = 0;
|
|
prevPicOrderCntLsb = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
uint32 prevRefPic_PicOrderCntMsb = h264ParserState->picture_order.prevPicOrderCntMsb;
|
|
uint32 prevRefPic_pic_order_cnt_lsb = h264ParserState->picture_order.prevPicOrderCntLsb; // todo
|
|
|
|
prevPicOrderCntMsb = prevRefPic_PicOrderCntMsb;
|
|
prevPicOrderCntLsb = prevRefPic_pic_order_cnt_lsb;
|
|
|
|
}
|
|
|
|
uint32 MaxPicOrderCntLsb = 1 << (sps.log2_max_pic_order_cnt_lsb_minus4 + 4); // todo - verify
|
|
|
|
uint32 PicOrderCntMsb;
|
|
|
|
if ((sliceHeader->pic_order_cnt_lsb < prevPicOrderCntLsb) && (((sint32)prevPicOrderCntLsb - (sint32)sliceHeader->pic_order_cnt_lsb) >= (sint32)(MaxPicOrderCntLsb / 2)))
|
|
PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb;
|
|
else if ((sliceHeader->pic_order_cnt_lsb > prevPicOrderCntLsb) && (((sint32)sliceHeader->pic_order_cnt_lsb - (sint32)prevPicOrderCntLsb) > (sint32)(MaxPicOrderCntLsb / 2)))
|
|
PicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb;
|
|
else
|
|
PicOrderCntMsb = prevPicOrderCntMsb;
|
|
|
|
uint32 TopFieldOrderCnt = PicOrderCntMsb + sliceHeader->pic_order_cnt_lsb;
|
|
|
|
if (sliceHeader->IdrPicFlag != 0 && TopFieldOrderCnt != 0)
|
|
cemu_assert(false);
|
|
|
|
sliceHeader->calculated.TopFieldOrderCnt = TopFieldOrderCnt;
|
|
|
|
h264ParserState->picture_order.prevPicOrderCntMsb = PicOrderCntMsb;
|
|
h264ParserState->picture_order.prevPicOrderCntLsb = sliceHeader->pic_order_cnt_lsb;
|
|
}
|
|
else if (sps.pic_order_cnt_type == 2)
|
|
{
|
|
// display order matches decode order
|
|
|
|
uint32 prevFrameNum = h264ParserState->picture_order.prevFrameNum;
|
|
;
|
|
uint32 FrameNumOffset;
|
|
if (sliceHeader->IdrPicFlag)
|
|
{
|
|
FrameNumOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
// todo - check for memory_management_control_operation 5
|
|
// prevFrameNumOffset is set equal to the value of FrameNumOffset of the previous picture in decoding order.
|
|
uint32 prevFrameNumOffset = h264ParserState->picture_order.prevFrameNumOffset;
|
|
|
|
if (prevFrameNum > sliceHeader->frame_num)
|
|
FrameNumOffset = prevFrameNumOffset + sps.getMaxFrameNum();
|
|
else
|
|
FrameNumOffset = prevFrameNumOffset;
|
|
|
|
|
|
|
|
}
|
|
|
|
uint32 tempPicOrderCnt;
|
|
if (sliceHeader->IdrPicFlag == 1)
|
|
tempPicOrderCnt = 0;
|
|
else if (sliceHeader->nal_ref_idc == 0)
|
|
tempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader->frame_num) - 1;
|
|
else
|
|
tempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader->frame_num);
|
|
|
|
uint32 TopFieldOrderCnt = 0;
|
|
uint32 BottomFieldOrderCnt = 0;
|
|
|
|
if (sliceHeader->field_pic_flag == 0)
|
|
{
|
|
TopFieldOrderCnt = tempPicOrderCnt;
|
|
BottomFieldOrderCnt = tempPicOrderCnt;
|
|
}
|
|
else if (sliceHeader->bottom_field_flag != 0)
|
|
{
|
|
cemu_assert_debug(false); // fields aren't supported
|
|
BottomFieldOrderCnt = tempPicOrderCnt;
|
|
}
|
|
else
|
|
{
|
|
cemu_assert_debug(false); // fields aren't supported
|
|
TopFieldOrderCnt = tempPicOrderCnt;
|
|
}
|
|
|
|
sliceHeader->calculated.TopFieldOrderCnt = TopFieldOrderCnt;
|
|
|
|
h264ParserState->picture_order.prevFrameNum = sliceHeader->frame_num;
|
|
h264ParserState->picture_order.prevFrameNumOffset = FrameNumOffset;
|
|
}
|
|
else
|
|
{
|
|
cemu_assert_debug(false);
|
|
}
|
|
}
|
|
|
|
void parseNAL_slice_layer_without_partitioning_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, sint32 streamSubOffset, sint32 streamSubLength, RBSPInputBitstream& nalStream, uint8 nal_ref_idc, uint8 nal_unit_type)
|
|
{
|
|
nal_slice_t slice = {};
|
|
cemu_assert_debug(h264ParserState->hasPPS && h264ParserState->hasSPS);
|
|
parseNAL_slice_header(h264ParserState->sps, h264ParserState->pps, nalStream, nal_unit_type, nal_ref_idc, &slice.slice_header);
|
|
_calculateFrameOrder(h264ParserState, h264ParserState->sps, h264ParserState->pps, &slice.slice_header);
|
|
if (output->sliceCount >= output->sliceInfo.size())
|
|
{
|
|
cemu_assert_debug(false); // internal slice buffer full
|
|
return;
|
|
}
|
|
output->sliceInfo[output->sliceCount].header = slice.slice_header;
|
|
output->sliceInfo[output->sliceCount].streamSubOffset = streamSubOffset;
|
|
output->sliceInfo[output->sliceCount].streamSubSize = streamSubLength;
|
|
output->sliceCount++;
|
|
}
|
|
|
|
void h264Parse(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, uint8* data, uint32 length, bool parseSlices)
|
|
{
|
|
memset(output, 0, sizeof(h264ParserOutput_t));
|
|
NALInputBitstream nalStream(data, length);
|
|
|
|
if (nalStream.hasError())
|
|
{
|
|
cemu_assert_debug(false);
|
|
return;
|
|
}
|
|
|
|
// parse NAL data
|
|
while (true)
|
|
{
|
|
if (nalStream.isEndOfStream())
|
|
break;
|
|
RBSPInputBitstream rbspStream;
|
|
if (nalStream.getNextRBSP(rbspStream) == false)
|
|
break;
|
|
|
|
sint32 streamSubOffset = (sint32)(rbspStream.getBasePtr() - data);
|
|
sint32 streamSubLength = rbspStream.getBaseLength();
|
|
|
|
// parse NAL header
|
|
uint8 nalHeaderByte = rbspStream.readU8();
|
|
if ((nalHeaderByte & 0x80) != 0)
|
|
{
|
|
// MSB must be zero
|
|
cemu_assert_debug(false);
|
|
continue;
|
|
}
|
|
uint8 nal_ref_idc = (nalHeaderByte >> 5) & 0x3;
|
|
uint8 nal_unit_type = (nalHeaderByte >> 0) & 0x1f;
|
|
// nal_ref_idc -> If not 0, reference picture. Contains sequence set ??
|
|
// nal_unit_type -> RBSP type
|
|
// nal_unit_type:
|
|
// 0 - unspecified
|
|
// 1 - Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp()
|
|
// 2 - Coded slice data partition A slice_data_partition_a_layer_rbsp()
|
|
// 3 - Coded slice data partition B slice_data_partition_b_layer_rbsp()
|
|
// 4 - Coded slice data partition C slice_data_partition_c_layer_rbsp()
|
|
// 5 - Coded slice of an IDR picture slice_layer_without_partitioning_rbsp()
|
|
// 6 - Supplemental enhancement information (SEI) sei_rbsp()
|
|
// 7 - Sequence parameter set seq_parameter_set_rbsp()
|
|
// 8 - Picture parameter set pic_parameter_set_rbsp()
|
|
// 9 - Access unit delimiter access_unit_delimiter_rbsp()
|
|
// 10 - End of sequence end_of_seq_rbsp()
|
|
// 11 - End of stream end_of_stream_rbsp()
|
|
// 12 - Filler data filler_data_rbsp()
|
|
// 13 to 23 - reserved
|
|
// 24 to 31 - unspecified
|
|
// VCL NAL -> nal_unit_type 1,2,3,4,5
|
|
// non-VCL NAL -> All other nal_unit_type values
|
|
|
|
if (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21)
|
|
{
|
|
cemu_assert_debug(false);
|
|
// todo - there are fields to parse here
|
|
}
|
|
switch (nal_unit_type)
|
|
{
|
|
case 1:
|
|
if (parseSlices)
|
|
parseNAL_slice_layer_without_partitioning_rbsp(h264ParserState, output, streamSubOffset, streamSubLength, rbspStream, nal_ref_idc, nal_unit_type);
|
|
break;
|
|
case 5:
|
|
if (parseSlices)
|
|
parseNAL_slice_layer_without_partitioning_rbsp(h264ParserState, output, streamSubOffset, streamSubLength, rbspStream, nal_ref_idc, nal_unit_type);
|
|
break;
|
|
case 6:
|
|
// SEI
|
|
break;
|
|
case 7:
|
|
cemu_assert_debug(parseNAL_seq_parameter_set_rbsp(h264ParserState, output, rbspStream));
|
|
break;
|
|
case 8:
|
|
cemu_assert_debug(parseNAL_pic_parameter_set_rbsp(h264ParserState, output, rbspStream));
|
|
break;
|
|
case 9:
|
|
// access unit delimiter
|
|
break;
|
|
case 10:
|
|
// end of sequence
|
|
break;
|
|
case 12:
|
|
// filler data
|
|
// seen in Cocoto Magic Circus 2 intro video
|
|
break;
|
|
default:
|
|
cemuLog_logDebug(LogType::Force, "Unsupported NAL unit type {}", nal_unit_type);
|
|
cemu_assert_debug(false);
|
|
// todo
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
sint32 h264GetUnitLength(h264ParserState_t* h264ParserState, uint8* data, uint32 length)
|
|
{
|
|
NALInputBitstream nalStream(data, length);
|
|
|
|
if (nalStream.hasError())
|
|
{
|
|
cemu_assert_debug(false);
|
|
return -1;
|
|
}
|
|
|
|
// search for start code
|
|
sint32 startCodeOffset = 0;
|
|
bool hasStartcode = false;
|
|
while (startCodeOffset < (sint32)(length - 3))
|
|
{
|
|
if (data[startCodeOffset + 0] == 0x00 && data[startCodeOffset + 1] == 0x00 && data[startCodeOffset + 2] == 0x01)
|
|
{
|
|
hasStartcode = true;
|
|
break;
|
|
}
|
|
startCodeOffset++;
|
|
}
|
|
if (hasStartcode == false)
|
|
return -1;
|
|
data += startCodeOffset;
|
|
length -= startCodeOffset;
|
|
|
|
// parse NAL data
|
|
while (true)
|
|
{
|
|
if (nalStream.isEndOfStream())
|
|
break;
|
|
RBSPInputBitstream rbspStream;
|
|
if (nalStream.getNextRBSP(rbspStream, true) == false)
|
|
break;
|
|
|
|
sint32 streamSubOffset = (sint32)(rbspStream.getBasePtr() - data);
|
|
sint32 streamSubLength = rbspStream.getBaseLength();
|
|
|
|
// parse NAL header
|
|
uint8 nalHeaderByte = rbspStream.readU8();
|
|
if ((nalHeaderByte & 0x80) != 0)
|
|
{
|
|
// MSB must be zero
|
|
cemu_assert_debug(false);
|
|
continue;
|
|
}
|
|
uint8 nal_ref_idc = (nalHeaderByte >> 5) & 0x3;
|
|
uint8 nal_unit_type = (nalHeaderByte >> 0) & 0x1f;
|
|
if (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21)
|
|
{
|
|
cemu_assert_debug(false);
|
|
continue;
|
|
}
|
|
switch (nal_unit_type)
|
|
{
|
|
case 1:
|
|
case 5:
|
|
{
|
|
// note: We cant parse the slice data because we dont have SPS and PPS data reliably available
|
|
//
|
|
// currently we just assume there is 1 slice per unit
|
|
return (sint32)((rbspStream.getBasePtr() + rbspStream.getBaseLength()) - data) + startCodeOffset;
|
|
|
|
break;
|
|
}
|
|
case 6:
|
|
// SEI
|
|
break;
|
|
case 7:
|
|
cemu_assert_debug(parseNAL_seq_parameter_set_rbsp(h264ParserState, nullptr, rbspStream));
|
|
break;
|
|
case 8:
|
|
cemu_assert_debug(parseNAL_pic_parameter_set_rbsp(h264ParserState, nullptr, rbspStream));
|
|
break;
|
|
case 9:
|
|
// access unit delimiter
|
|
break;
|
|
case 10:
|
|
// end of sequence
|
|
break;
|
|
default:
|
|
cemuLog_logDebug(LogType::Force, "Unsupported NAL unit type {}", nal_unit_type);
|
|
assert_dbg(); // todo - NAL 10 is used in DKC TF
|
|
// todo
|
|
break;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static const unsigned char h264_default_4x4_Intra[16] =
|
|
{
|
|
6, 13, 13, 20,
|
|
20, 20, 28, 28,
|
|
28, 28, 32, 32,
|
|
32, 37, 37, 42
|
|
};
|
|
|
|
static const unsigned char h264_default_4x4_Inter[16] =
|
|
{
|
|
10, 14, 14, 20,
|
|
20, 20, 24, 24,
|
|
24, 24, 27, 27,
|
|
27, 30, 30, 34
|
|
};
|
|
|
|
static const unsigned char h264_default_8x8_Intra[64] =
|
|
{
|
|
6, 10, 10, 13, 11, 13, 16, 16,
|
|
16, 16, 18, 18, 18, 18, 18, 23,
|
|
23, 23, 23, 23, 23, 25, 25, 25,
|
|
25, 25, 25, 25, 27, 27, 27, 27,
|
|
27, 27, 27, 27, 29, 29, 29, 29,
|
|
29, 29, 29, 31, 31, 31, 31, 31,
|
|
31, 33, 33, 33, 33, 33, 36, 36,
|
|
36, 36, 38, 38, 38, 40, 40, 42
|
|
};
|
|
|
|
static const unsigned char h264_default_8x8_Inter[64] =
|
|
{
|
|
9, 13, 13, 15, 13, 15, 17, 17,
|
|
17, 17, 19, 19, 19, 19, 19, 21,
|
|
21, 21, 21, 21, 21, 22, 22, 22,
|
|
22, 22, 22, 22, 24, 24, 24, 24,
|
|
24, 24, 24, 24, 25, 25, 25, 25,
|
|
25, 25, 25, 27, 27, 27, 27, 27,
|
|
27, 28, 28, 28, 28, 28, 30, 30,
|
|
30, 30, 32, 32, 32, 33, 33, 35
|
|
};
|
|
|
|
void h264Parser_getScalingMatrix4x4(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix4x4)
|
|
{
|
|
// use scaling lists from PPS first
|
|
if (pps->pic_scaling_matrix_present_flag)
|
|
{
|
|
if (pps->ScalingList4x4[index].isPresent)
|
|
{
|
|
cemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)
|
|
memcpy(matrix4x4, pps->ScalingList4x4[index].list, 4 * 4 * sizeof(uint8));
|
|
}
|
|
else
|
|
{
|
|
if (index < 3)
|
|
memcpy(matrix4x4, h264_default_4x4_Intra, 4 * 4 * sizeof(uint8));
|
|
else
|
|
memcpy(matrix4x4, h264_default_4x4_Inter, 4 * 4 * sizeof(uint8));
|
|
}
|
|
return;
|
|
}
|
|
// use scaling lists from SPS
|
|
if (sps->seq_scaling_matrix_present_flag)
|
|
{
|
|
if (sps->ScalingList4x4[index].isPresent)
|
|
{
|
|
cemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)
|
|
memcpy(matrix4x4, sps->ScalingList4x4[index].list, 4 * 4 * sizeof(uint8));
|
|
}
|
|
else
|
|
{
|
|
if (index < 3)
|
|
memcpy(matrix4x4, h264_default_4x4_Intra, 4 * 4 * sizeof(uint8));
|
|
else
|
|
memcpy(matrix4x4, h264_default_4x4_Inter, 4 * 4 * sizeof(uint8));
|
|
}
|
|
return;
|
|
}
|
|
// default (Flat_4x4_16)
|
|
memset(matrix4x4, 16, 4 * 4 * sizeof(uint8));
|
|
}
|
|
|
|
void h264Parser_getScalingMatrix8x8(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix8x8)
|
|
{
|
|
// use scaling lists from PPS first
|
|
if (pps->pic_scaling_matrix_present_flag)
|
|
{
|
|
if (pps->ScalingList8x8[index].isPresent)
|
|
{
|
|
cemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)
|
|
memcpy(matrix8x8, pps->ScalingList8x8[index].list, 8 * 8 * sizeof(uint8));
|
|
}
|
|
else
|
|
{
|
|
if ((index&1) == 0)
|
|
memcpy(matrix8x8, h264_default_8x8_Intra, 8 * 8 * sizeof(uint8));
|
|
else
|
|
memcpy(matrix8x8, h264_default_8x8_Inter, 8 * 8 * sizeof(uint8));
|
|
}
|
|
return;
|
|
}
|
|
// use scaling lists from SPS
|
|
if (sps->seq_scaling_matrix_present_flag)
|
|
{
|
|
if (sps->ScalingList8x8[index].isPresent)
|
|
{
|
|
cemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)
|
|
memcpy(matrix8x8, sps->ScalingList8x8[index].list, 8 * 8 * sizeof(uint8));
|
|
}
|
|
else
|
|
{
|
|
if ((index & 1) == 0)
|
|
memcpy(matrix8x8, h264_default_8x8_Intra, 8 * 8 * sizeof(uint8));
|
|
else
|
|
memcpy(matrix8x8, h264_default_8x8_Inter, 8 * 8 * sizeof(uint8));
|
|
}
|
|
return;
|
|
}
|
|
// default (Flat_8x8_16)
|
|
memset(matrix8x8, 16, 8 * 8 * sizeof(uint8));
|
|
}
|