-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #321 from Eyevinn/hevc-sei1
HEVC PicTiming SEI message support
- Loading branch information
Showing
6 changed files
with
227 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package sei | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/Eyevinn/mp4ff/bits" | ||
) | ||
|
||
// PicTimingHevcSEI carries the data of an SEI 1 PicTiming message for HEVC. | ||
// The corresponding SEI 1 for AVC is very different. Time code is in SEI 136 for HEVC. | ||
// Defined in ISO/IEC 23008-2 Ed 5. Section D.2.3 (page 372) and D.3.2.3 (page 405) | ||
type PicTimingHevcSEI struct { | ||
ExternalParams HEVCPicTimingParams `json:"-"` | ||
FrameFieldInfo *HEVCFrameFieldInfo `json:"FrameFieldInfo,omitempty"` | ||
AuCpbRemovalDelayMinus1 uint32 `json:"AuCpbRemovalDelayMinus1,omitempty"` | ||
PicDpbOutputDelay uint32 `json:"PicDpbOutputDelay,omitempty"` | ||
PicDpbOutputDuDelay uint32 `json:"PicDpbOutputDuDelay,omitempty"` | ||
NumDecodingUnitsMinus1 uint32 `json:"NumDecodingUnitsMinus1,omitempty"` | ||
DuCommonCpbRemovalDelayFlag bool `json:"DuCommonCpbRemovalDelayFlag,omitempty"` | ||
DuCommonCpbRemovalDelayIncrementMinus1 uint32 `json:"DuCommonCpbRemovalDelayIncrementMinus1,omitempty"` | ||
NumNalusInDuMinus1 []uint32 `json:"NumNalusInDuMinus1,omitempty"` | ||
DuCpbRemovalDelayIncrementMinus1 []uint32 `json:"DuCpbRemovalDelayIncrementMinus1,omitempty"` | ||
payload []byte `json:"-"` | ||
} | ||
|
||
type HEVCPicTimingParams struct { | ||
FrameFieldInfoPresentFlag bool | ||
CpbDpbDelaysPresentFlag bool | ||
SubPicHrdParamsPresentFlag bool | ||
SubPicCpbParamsInPicTimingSeiFlag bool | ||
AuCbpRemovalDelayLengthMinus1 uint8 | ||
DpbOutputDelayLengthMinus1 uint8 | ||
DpbOutputDelayDuLengthMinus1 uint8 | ||
DuCpbRemovalDelayIncrementLengthMinus1 uint8 | ||
} | ||
|
||
type HEVCFrameFieldInfo struct { | ||
PicStruct uint8 // 4 bits | ||
SourceScanType uint8 // 2 bits | ||
DuplicateFlag bool `json:"DuplicateFlag,omitempty"` // 1bit | ||
} | ||
|
||
func DecodePicTimingHevcSEI(sd *SEIData, exPar HEVCPicTimingParams) (SEIMessage, error) { | ||
buf := bytes.NewBuffer(sd.Payload()) | ||
br := bits.NewAccErrEBSPReader(buf) | ||
pt := PicTimingHevcSEI{ | ||
payload: sd.Payload(), | ||
} | ||
if exPar.FrameFieldInfoPresentFlag { | ||
frameFieldInfo := &HEVCFrameFieldInfo{} | ||
frameFieldInfo.PicStruct = uint8(br.Read(4)) | ||
frameFieldInfo.SourceScanType = uint8(br.Read(2)) | ||
frameFieldInfo.DuplicateFlag = br.ReadFlag() | ||
pt.FrameFieldInfo = frameFieldInfo | ||
} | ||
if exPar.CpbDpbDelaysPresentFlag { | ||
pt.AuCpbRemovalDelayMinus1 = uint32(br.Read(int(exPar.AuCbpRemovalDelayLengthMinus1) + 1)) | ||
pt.PicDpbOutputDelay = uint32(br.Read(int(exPar.DpbOutputDelayLengthMinus1) + 1)) | ||
if exPar.SubPicHrdParamsPresentFlag { | ||
pt.PicDpbOutputDuDelay = uint32(br.Read(int(exPar.DpbOutputDelayDuLengthMinus1) + 1)) | ||
if exPar.SubPicCpbParamsInPicTimingSeiFlag { | ||
pt.NumDecodingUnitsMinus1 = uint32(br.ReadExpGolomb()) | ||
pt.DuCommonCpbRemovalDelayFlag = br.ReadFlag() | ||
if pt.DuCommonCpbRemovalDelayFlag { | ||
pt.DuCommonCpbRemovalDelayIncrementMinus1 = uint32(br.Read(int(exPar.DuCpbRemovalDelayIncrementLengthMinus1) + 1)) | ||
} | ||
for i := uint32(0); i <= pt.NumDecodingUnitsMinus1; i++ { | ||
pt.NumNalusInDuMinus1[i] = uint32(br.ReadExpGolomb()) | ||
if !pt.DuCommonCpbRemovalDelayFlag && i < pt.NumDecodingUnitsMinus1 { | ||
pt.DuCpbRemovalDelayIncrementMinus1[i] = uint32(br.Read(int(exPar.DuCpbRemovalDelayIncrementLengthMinus1) + 1)) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return &pt, br.AccError() | ||
} | ||
|
||
// Type returns the SEI payload type. | ||
func (s *PicTimingHevcSEI) Type() uint { | ||
return SEIPicTimingType | ||
} | ||
|
||
// Payload returns the SEI raw rbsp payload. | ||
func (s *PicTimingHevcSEI) Payload() []byte { | ||
return s.payload | ||
} | ||
|
||
// String returns string representation of PicTiming SEI1. | ||
func (s *PicTimingHevcSEI) String() string { | ||
msgType := SEIType(s.Type()) | ||
msg := fmt.Sprintf("%s: ", msgType) | ||
if s.FrameFieldInfo != nil { | ||
msg += fmt.Sprintf("FrameFieldInfo: %+v, ", s.FrameFieldInfo) | ||
} | ||
return msg | ||
} | ||
|
||
// Size is size in bytes of raw SEI message rbsp payload. | ||
func (s *PicTimingHevcSEI) Size() uint { | ||
return uint(len(s.payload)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package sei | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"testing" | ||
|
||
"github.com/go-test/deep" | ||
) | ||
|
||
func TestHEVCSETI1PicTiming(t *testing.T) { | ||
|
||
cases := []struct { | ||
name string | ||
naluPayloadHex string | ||
extParams HEVCPicTimingParams | ||
expected PicTimingHevcSEI | ||
expNonFatalErr error | ||
}{ | ||
{ | ||
name: "HEVC_SETI1PicTiming", | ||
naluPayloadHex: "01071000001a0000030180", | ||
extParams: HEVCPicTimingParams{ | ||
FrameFieldInfoPresentFlag: true, | ||
CpbDpbDelaysPresentFlag: true, | ||
SubPicHrdParamsPresentFlag: false, | ||
SubPicCpbParamsInPicTimingSeiFlag: false, | ||
AuCbpRemovalDelayLengthMinus1: 23, | ||
DpbOutputDelayLengthMinus1: 0, | ||
DpbOutputDelayDuLengthMinus1: 23, | ||
DuCpbRemovalDelayIncrementLengthMinus1: 0, | ||
}, | ||
expected: PicTimingHevcSEI{ | ||
FrameFieldInfo: &HEVCFrameFieldInfo{ | ||
PicStruct: 1, | ||
SourceScanType: 0, | ||
DuplicateFlag: false, | ||
}, | ||
}, | ||
expNonFatalErr: nil, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
seiNaluPayload, _ := hex.DecodeString(tc.naluPayloadHex) | ||
r := bytes.NewReader(seiNaluPayload) | ||
seis, err := ExtractSEIData(r) | ||
if err != nil && err != tc.expNonFatalErr { | ||
t.Error(err) | ||
} | ||
if len(seis) != 1 { | ||
t.Errorf("%s: Not %d but %d sei messages found", tc.name, 1, len(seis)) | ||
} | ||
seiMessage, err := DecodePicTimingHevcSEI(&seis[0], tc.extParams) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
if seiMessage.Type() != SEIPicTimingType { | ||
t.Errorf("%s: got SEI type %d instead of %d", tc.name, seiMessage.Type(), SEIPicTimingType) | ||
} | ||
seiPT := seiMessage.(*PicTimingHevcSEI) | ||
diff := deep.Equal(seiPT.FrameFieldInfo, tc.expected.FrameFieldInfo) | ||
if diff != nil { | ||
t.Errorf("%s: %v %s", tc.name, diff, "frame field info mismatch") | ||
} | ||
} | ||
} |