Skip to content

Commit

Permalink
fix: add forgotten hevc/sei files
Browse files Browse the repository at this point in the history
  • Loading branch information
tobbee committed Jan 23, 2024
1 parent a1ab453 commit bbd4656
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
74 changes: 74 additions & 0 deletions hevc/sei.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package hevc

import (
"bytes"
"errors"
"fmt"

"github.com/Eyevinn/mp4ff/sei"
)

var (
ErrNotSEINalu = errors.New("not an SEI NAL unit")
)

// ParseSEINalu - parse SEI NAL unit (incl header) and return messages given SPS.
// Returns sei.ErrRbspTrailingBitsMissing if the NALU is missing the trailing bits.
func ParseSEINalu(nalu []byte, sps *SPS) ([]sei.SEIMessage, error) {
switch GetNaluType(nalu[0]) {
case NALU_SEI_PREFIX, NALU_SEI_SUFFIX:
default:
return nil, ErrNotSEINalu
}
seiBytes := nalu[2:] // Skip NALU header
buf := bytes.NewReader(seiBytes)
seiDatas, err := sei.ExtractSEIData(buf)
missingRbspTrailingBits := false
if err != nil {
if errors.Is(err, sei.ErrRbspTrailingBitsMissing) {
missingRbspTrailingBits = true
} else {
return nil, fmt.Errorf("extracting SEI data: %w", err)
}
}

seiMsgs := make([]sei.SEIMessage, 0, len(seiDatas))
var seiMsg sei.SEIMessage
for _, seiData := range seiDatas {
switch {
case seiData.Type() == sei.SEIPicTimingType && sps != nil && sps.VUI != nil:
htp := fillHEVCPicTimingParams(sps)
seiMsg, err = sei.DecodePicTimingHevcSEI(&seiData, htp)
default:
seiMsg, err = sei.DecodeSEIMessage(&seiData, sei.HEVC)
}
if err != nil {
return nil, fmt.Errorf("sei decode: %w", err)
}
seiMsgs = append(seiMsgs, seiMsg)
}
if missingRbspTrailingBits {
return seiMsgs, sei.ErrRbspTrailingBitsMissing
}
return seiMsgs, nil
}

func fillHEVCPicTimingParams(sps *SPS) sei.HEVCPicTimingParams {
hpt := sei.HEVCPicTimingParams{}
if sps.VUI == nil {
return hpt
}
hpt.FrameFieldInfoPresentFlag = sps.VUI.FrameFieldInfoPresentFlag
hrd := sps.VUI.HrdParameters
if hrd == nil {
return hpt
}
hpt.CpbDpbDelaysPresentFlag = hrd.CpbDpbDelaysPresentFlag()
hpt.SubPicHrdParamsPresentFlag = hrd.SubPicHrdParamsPresentFlag
hpt.SubPicCpbParamsInPicTimingSeiFlag = hrd.SubPicCpbParamsInPicTimingSeiFlag
hpt.AuCbpRemovalDelayLengthMinus1 = hrd.AuCpbRemovalDelayLengthMinus1
hpt.DpbOutputDelayLengthMinus1 = hrd.DpbOutputDelayLengthMinus1
hpt.DpbOutputDelayDuLengthMinus1 = hrd.DpbOutputDelayDuLengthMinus1
hpt.DuCpbRemovalDelayIncrementLengthMinus1 = hrd.DuCpbRemovalDelayIncrementLengthMinus1
return hpt
}
69 changes: 69 additions & 0 deletions hevc/sei_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package hevc

import (
"encoding/hex"
"testing"

"github.com/Eyevinn/mp4ff/sei"
)

func TestSEIParsing(t *testing.T) {
testCases := []struct {
desc string
spsNALUHex string
seiNALUHex string
expectedMsgs []sei.SEIMessage
expectedFrameField *sei.HEVCFrameFieldInfo
expectedErr error
}{
{
desc: "Test SEI HEVC pic_timing with SPS",
spsNALUHex: "420101014000000300400000030000030078a003c080221f7a3ee46c1bdf4f60280d00000303e80000c350601def7e00028b1c001443c8",
seiNALUHex: "4e0101071000001a0000030180",
expectedMsgs: []sei.SEIMessage{&sei.PicTimingHevcSEI{}},
expectedFrameField: &sei.HEVCFrameFieldInfo{
PicStruct: 1,
SourceScanType: 0,
DuplicateFlag: false,
},
expectedErr: nil,
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
spsBytes, err := hex.DecodeString(tc.spsNALUHex)
if err != nil {
t.Error(err)
}
sps, err := ParseSPSNALUnit(spsBytes)
if err != nil {
t.Fatalf("ParseSPSNALU failed: %v", err)
}
seiBytes, err := hex.DecodeString(tc.seiNALUHex)
if err != nil {
t.Error(err)
}
msgs, err := ParseSEINalu(seiBytes, sps)
if err != tc.expectedErr {
t.Fatalf("expected err %q got : %v", tc.expectedErr, err)
}
if len(msgs) != len(tc.expectedMsgs) {
t.Fatalf("Expected %d messages, got %d", len(tc.expectedMsgs), len(msgs))
}
for i, msg := range msgs {
msgType := msg.Type()
if msgType != tc.expectedMsgs[i].Type() {
t.Errorf("Expected message type %d, got %d", tc.expectedMsgs[i].Type(), msg.Type())
}
if (msg.Type() == sei.SEIPicTimingType) && tc.expectedFrameField != nil {
picTimeSEI := msg.(*sei.PicTimingHevcSEI)
gotFrameField := picTimeSEI.FrameFieldInfo
if *gotFrameField != *tc.expectedFrameField {
t.Errorf("Expected framefield %+v, got %+v", tc.expectedFrameField, gotFrameField)
}
}
}
})
}
}

0 comments on commit bbd4656

Please sign in to comment.