package h264dec import ( "bytes" "errors" "reflect" "testing" "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" ) func TestNewPPS(t *testing.T) { // TODO: add test with scaling list once we have a test for scalingList func. tests := []struct { in string chromaFormat int want PPS }{ { in: "1" + // ue(v) pic_parameter_set_id = 0 "1" + // ue(v) seq_parameter_set_id = 0 "1" + // u(1) entropy_coding_mode_flag = 1 "0" + // u(1) pic_order_present_flag = 0 "1" + // ue(v) num_slice_groups_minus1 = 0 "1" + // ue(v) num_ref_idx_L0_active_minus1 = 0 "1" + // ue(v) num_ref_idx_L1_active_minus1 = 0 "1" + // u(1) weighted_pred_flag = 1 "00" + // u(2) weighted_bipred_idc = 0 "1" + // se(v) pic_init_qp_minus26 = 0 "1" + // se(v) pic_init_qs_minus26 = 0 "1" + // se(v) chroma_qp_index_offset = 0 "1" + // u(1) deblocking_filter_control_present_flag = 1 "0" + // u(1) constrained_intra_pred_flag = 0 "0" + // u(1) redundant_pic_cnt_present_flag = 0 "10000000", // rbspTrailingBits want: PPS{ ID: 0, SPSID: 0, EntropyCodingMode: 1, BottomFieldPicOrderInFramePresent: false, NumSliceGroupsMinus1: 0, NumRefIdxL0DefaultActiveMinus1: 0, NumRefIdxL1DefaultActiveMinus1: 0, WeightedPred: true, WeightedBipred: 0, PicInitQpMinus26: 0, PicInitQsMinus26: 0, ChromaQpIndexOffset: 0, DeblockingFilterControlPresent: true, ConstrainedIntraPred: false, RedundantPicCntPresent: false, }, }, { in: "1" + // ue(v) pic_parameter_set_id = 0 "1" + // ue(v) seq_parameter_set_id = 0 "1" + // u(1) entropy_coding_mode_flag = 1 "1" + // u(1) bottom_field_pic_order_in_frame_present_flag = 1 "010" + // ue(v) num_slice_groups_minus1 = 1 "1" + // ue(v) slice_group_map_type = 0 "1" + // ue(v) run_length_minus1[0] = 0 "1" + // ue(v) run_length_minus1[1] = 0 "1" + // ue(v) num_ref_idx_L0_active_minus1 = 0 "1" + // ue(v) num_ref_idx_L1_active_minus1 = 0 "1" + // u(1) weighted_pred_flag = 0 "00" + // u(2) weighted_bipred_idc = 0 "011" + // se(v) pic_init_qp_minus26 = -1 "010" + // se(v) pic_init_qs_minus26 = 1 "00100" + // se(v) chroma_qp_index_offset = 2 "0" + // u(1) deblocking_filter_control_present_flag =0 "0" + // u(1) constrained_intra_pred_flag=0 "0" + // u(1) redundant_pic_cnt_present_flag=0 "0" + // u(1) transform_8x8_mode_flag=0 "0" + // u(1) pic_scaling_matrix_present_flag=0 "00100" + // se(v) second_chroma_qp_index_offset=2 "10000", // stop bit and trailing bits want: PPS{ ID: 0, SPSID: 0, EntropyCodingMode: 1, BottomFieldPicOrderInFramePresent: true, NumSliceGroupsMinus1: 1, RunLengthMinus1: []int{0, 0}, NumRefIdxL0DefaultActiveMinus1: 0, NumRefIdxL1DefaultActiveMinus1: 0, WeightedPred: true, WeightedBipred: 0, PicInitQpMinus26: -1, PicInitQsMinus26: 1, ChromaQpIndexOffset: 2, DeblockingFilterControlPresent: false, ConstrainedIntraPred: false, RedundantPicCntPresent: false, Transform8x8Mode: 0, PicScalingMatrixPresent: false, SecondChromaQpIndexOffset: 2, }, }, } for i, test := range tests { bin, err := binToSlice(test.in) if err != nil { t.Fatalf("error: %v converting binary string to slice for test: %d", err, i) } pps, err := NewPPS(bits.NewBitReader(bytes.NewReader(bin)), test.chromaFormat) if err != nil { t.Fatalf("did not expect error: %v for test: %d", err, i) } if !reflect.DeepEqual(test.want, *pps) { t.Errorf("did not get expected result for test: %d.\nGot: %+v\nWant: %+v\n", i, *pps, test.want) } } } // binToSlice is a helper function to convert a string of binary into a // corresponding byte slice, e.g. "0100 0001 1000 1100" => {0x41,0x8c}. // Spaces in the string are ignored. func binToSlice(s string) ([]byte, error) { var ( a byte = 0x80 cur byte bytes []byte ) for _, c := range s { switch c { case ' ': continue case '1': cur |= a case '0': default: return nil, errors.New("invalid binary string") } a >>= 1 if a == 0 { bytes = append(bytes, cur) cur = 0 a = 0x80 } } return bytes, nil }