mirror of https://bitbucket.org/ausocean/av.git
162 lines
4.8 KiB
Go
162 lines
4.8 KiB
Go
package h264
|
|
|
|
import (
|
|
"github.com/ausocean/h264decode/h264/bits"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type NalUnit struct {
|
|
NumBytes int
|
|
ForbiddenZeroBit int
|
|
RefIdc int
|
|
Type int
|
|
SvcExtensionFlag int
|
|
Avc3dExtensionFlag int
|
|
IdrFlag int
|
|
PriorityId int
|
|
NoInterLayerPredFlag int
|
|
DependencyId int
|
|
QualityId int
|
|
TemporalId int
|
|
UseRefBasePicFlag int
|
|
DiscardableFlag int
|
|
OutputFlag int
|
|
ReservedThree2Bits int
|
|
HeaderBytes int
|
|
NonIdrFlag int
|
|
ViewId int
|
|
AnchorPicFlag int
|
|
InterViewFlag int
|
|
ReservedOneBit int
|
|
ViewIdx int
|
|
DepthFlag int
|
|
EmulationPreventionThreeByte byte
|
|
rbsp []byte
|
|
}
|
|
|
|
func NalUnitHeaderSvcExtension(nalUnit *NalUnit, br *bits.BitReader) error {
|
|
return readFields(br, []field{
|
|
{&nalUnit.IdrFlag, "IdrFlag", 1},
|
|
{&nalUnit.PriorityId, "PriorityId", 6},
|
|
{&nalUnit.NoInterLayerPredFlag, "NoInterLayerPredFlag", 1},
|
|
{&nalUnit.DependencyId, "DependencyId", 3},
|
|
{&nalUnit.QualityId, "QualityId", 4},
|
|
{&nalUnit.TemporalId, "TemporalId", 3},
|
|
{&nalUnit.UseRefBasePicFlag, "UseRefBasePicFlag", 1},
|
|
{&nalUnit.DiscardableFlag, "DiscardableFlag", 1},
|
|
{&nalUnit.OutputFlag, "OutputFlag", 1},
|
|
{&nalUnit.ReservedThree2Bits, "ReservedThree2Bits", 2},
|
|
})
|
|
}
|
|
|
|
func NalUnitHeader3davcExtension(nalUnit *NalUnit, br *bits.BitReader) error {
|
|
return readFields(br, []field{
|
|
{&nalUnit.ViewIdx, "ViewIdx", 8},
|
|
{&nalUnit.DepthFlag, "DepthFlag", 1},
|
|
{&nalUnit.NonIdrFlag, "NonIdrFlag", 1},
|
|
{&nalUnit.TemporalId, "TemporalId", 3},
|
|
{&nalUnit.AnchorPicFlag, "AnchorPicFlag", 1},
|
|
{&nalUnit.InterViewFlag, "InterViewFlag", 1},
|
|
})
|
|
}
|
|
|
|
func NalUnitHeaderMvcExtension(nalUnit *NalUnit, br *bits.BitReader) error {
|
|
return readFields(br, []field{
|
|
{&nalUnit.NonIdrFlag, "NonIdrFlag", 1},
|
|
{&nalUnit.PriorityId, "PriorityId", 6},
|
|
{&nalUnit.ViewId, "ViewId", 10},
|
|
{&nalUnit.TemporalId, "TemporalId", 3},
|
|
{&nalUnit.AnchorPicFlag, "AnchorPicFlag", 1},
|
|
{&nalUnit.InterViewFlag, "InterViewFlag", 1},
|
|
{&nalUnit.ReservedOneBit, "ReservedOneBit", 1},
|
|
})
|
|
}
|
|
|
|
func (n *NalUnit) RBSP() []byte {
|
|
return n.rbsp
|
|
}
|
|
|
|
func NewNalUnit(frame []byte, numBytesInNal int) (*NalUnit, error) {
|
|
logger.Printf("debug: reading %d byte NAL\n", numBytesInNal)
|
|
nalUnit := NalUnit{
|
|
NumBytes: numBytesInNal,
|
|
HeaderBytes: 1,
|
|
}
|
|
// TODO: pass in actual io.Reader to NewBitReader
|
|
br := bits.NewBitReader(nil)
|
|
|
|
err := readFields(br, []field{
|
|
{&nalUnit.ForbiddenZeroBit, "ForbiddenZeroBit", 1},
|
|
{&nalUnit.RefIdc, "NalRefIdc", 2},
|
|
{&nalUnit.Type, "NalUnitType", 5},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if nalUnit.Type == 14 || nalUnit.Type == 20 || nalUnit.Type == 21 {
|
|
if nalUnit.Type != 21 {
|
|
b, err := br.ReadBits(1)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read SvcExtensionFlag")
|
|
}
|
|
nalUnit.SvcExtensionFlag = int(b)
|
|
} else {
|
|
b, err := br.ReadBits(1)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read Avc3dExtensionFlag")
|
|
}
|
|
nalUnit.Avc3dExtensionFlag = int(b)
|
|
}
|
|
if nalUnit.SvcExtensionFlag == 1 {
|
|
NalUnitHeaderSvcExtension(&nalUnit, br)
|
|
nalUnit.HeaderBytes += 3
|
|
} else if nalUnit.Avc3dExtensionFlag == 1 {
|
|
NalUnitHeader3davcExtension(&nalUnit, br)
|
|
nalUnit.HeaderBytes += 2
|
|
} else {
|
|
NalUnitHeaderMvcExtension(&nalUnit, br)
|
|
nalUnit.HeaderBytes += 3
|
|
|
|
}
|
|
}
|
|
|
|
logger.Printf("debug: found %d byte header. Reading body\n", nalUnit.HeaderBytes)
|
|
for i := nalUnit.HeaderBytes; i < nalUnit.NumBytes; i++ {
|
|
next3Bytes, err := br.PeekBits(24)
|
|
if err != nil {
|
|
logger.Printf("error: while reading next 3 NAL bytes: %v\n", err)
|
|
break
|
|
}
|
|
// Little odd, the err above and the i+2 check might be synonyms
|
|
if i+2 < nalUnit.NumBytes && next3Bytes == 0x000003 {
|
|
for j := 0; j < 2; j++ {
|
|
rbspByte, err := br.ReadBits(8)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read rbspByte")
|
|
}
|
|
nalUnit.rbsp = append(nalUnit.rbsp, byte(rbspByte))
|
|
}
|
|
i += 2
|
|
|
|
// Read Emulation prevention three byte.
|
|
eptByte, err := br.ReadBits(8)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read eptByte")
|
|
}
|
|
nalUnit.EmulationPreventionThreeByte = byte(eptByte)
|
|
} else {
|
|
if b, err := br.ReadBits(8); err == nil {
|
|
nalUnit.rbsp = append(nalUnit.rbsp, byte(b))
|
|
} else {
|
|
logger.Printf("error: while reading byte %d of %d nal bytes: %v\n", i, nalUnit.NumBytes, err)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// nalUnit.rbsp = frame[nalUnit.HeaderBytes:]
|
|
logger.Printf("info: decoded %s NAL with %d RBSP bytes\n", NALUnitType[nalUnit.Type], len(nalUnit.rbsp))
|
|
return &nalUnit, nil
|
|
}
|