h264parser: remove old bits use
This commit is contained in:
parent
b8afa6ca0c
commit
9feea9df46
@ -4,7 +4,7 @@ package h264parser
|
|||||||
import (
|
import (
|
||||||
"github.com/nareix/joy4/av"
|
"github.com/nareix/joy4/av"
|
||||||
"github.com/nareix/bits"
|
"github.com/nareix/bits"
|
||||||
"io"
|
"github.com/nareix/pio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"bytes"
|
"bytes"
|
||||||
)
|
)
|
||||||
@ -199,26 +199,8 @@ Additionally, there is a new variable called NALULengthSizeMinusOne. This confus
|
|||||||
An advantage to this format is the ability to configure the decoder at the start and jump into the middle of a stream. This is a common use case where the media is available on a random access medium such as a hard drive, and is therefore used in common container formats such as MP4 and MKV.
|
An advantage to this format is the ability to configure the decoder at the start and jump into the middle of a stream. This is a common use case where the media is available on a random access medium such as a hard drive, and is therefore used in common container formats such as MP4 and MKV.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func WalkNALUsAnnexb(nalus [][]byte, write func([]byte)) {
|
var StartCodeBytes = []byte{0,0,1}
|
||||||
for i, nalu := range(nalus) {
|
var AUDBytes = []byte{0,0,0,1,0x9,0xf0,0,0,0,1} // AUD
|
||||||
if i == 0 {
|
|
||||||
write([]byte{0,0,0,1,0x9,0xf0,0,0,0,1}) // AUD
|
|
||||||
} else {
|
|
||||||
write([]byte{0,0,1})
|
|
||||||
}
|
|
||||||
write(nalu)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func WalkNALUsAVCC(nalus [][]byte, write func([]byte)) {
|
|
||||||
for _, nalu := range(nalus) {
|
|
||||||
var b [4]byte
|
|
||||||
bits.PutUIntBE(b[:], uint(len(nalu)), 32)
|
|
||||||
write(b[:])
|
|
||||||
write(nalu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckNALUsType(b []byte) (typ int) {
|
func CheckNALUsType(b []byte) (typ int) {
|
||||||
_, typ = SplitNALUs(b)
|
_, typ = SplitNALUs(b)
|
||||||
@ -236,11 +218,11 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
|
|||||||
return [][]byte{b}, NALU_RAW
|
return [][]byte{b}, NALU_RAW
|
||||||
}
|
}
|
||||||
|
|
||||||
val3 := bits.GetUIntBE(b, 24)
|
val3 := pio.U24BE(b)
|
||||||
val4 := bits.GetUIntBE(b, 32)
|
val4 := pio.U32BE(b)
|
||||||
|
|
||||||
// maybe AVCC
|
// maybe AVCC
|
||||||
if val4 <= uint(len(b)) {
|
if val4 <= uint32(len(b)) {
|
||||||
_val4 := val4
|
_val4 := val4
|
||||||
_b := b[4:]
|
_b := b[4:]
|
||||||
nalus := [][]byte{}
|
nalus := [][]byte{}
|
||||||
@ -250,9 +232,9 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
|
|||||||
if len(_b) < 4 {
|
if len(_b) < 4 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
_val4 = bits.GetUIntBE(_b, 32)
|
_val4 = pio.U32BE(_b)
|
||||||
_b = _b[4:]
|
_b = _b[4:]
|
||||||
if _val4 > uint(len(_b)) {
|
if _val4 > uint32(len(_b)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,10 +266,10 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
|
|||||||
_val4 = 0
|
_val4 = 0
|
||||||
for pos < len(b) {
|
for pos < len(b) {
|
||||||
if pos+2 < len(b) && b[pos] == 0 {
|
if pos+2 < len(b) && b[pos] == 0 {
|
||||||
_val3 = bits.GetUIntBE(b[pos:], 24)
|
_val3 = pio.U24BE(b[pos:])
|
||||||
if _val3 == 0 {
|
if _val3 == 0 {
|
||||||
if pos+3 < len(b) {
|
if pos+3 < len(b) {
|
||||||
_val4 = uint(b[pos+3])
|
_val4 = uint32(b[pos+3])
|
||||||
if _val4 == 1 {
|
if _val4 == 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -516,50 +498,6 @@ func ParseSPS(data []byte) (self SPSInfo, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteAVCDecoderConfRecord(w io.Writer, self AVCDecoderConfRecord) (err error) {
|
|
||||||
if err = bits.WriteUIntBE(w, 1, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteUIntBE(w, uint(self.AVCProfileIndication), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteUIntBE(w, uint(self.ProfileCompatibility), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteUIntBE(w, uint(self.AVCLevelIndication), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteUIntBE(w, uint(self.LengthSizeMinusOne|0xfc), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = bits.WriteUIntBE(w, uint(len(self.SPS)|0xe0), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, data := range self.SPS {
|
|
||||||
if err = bits.WriteUIntBE(w, uint(len(data)), 16); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteBytes(w, data, len(data)); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = bits.WriteUIntBE(w, uint(len(self.PPS)), 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, data := range self.PPS {
|
|
||||||
if err = bits.WriteUIntBE(w, uint(len(data)), 16); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = bits.WriteBytes(w, data, len(data)); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodecData struct {
|
type CodecData struct {
|
||||||
Record []byte
|
Record []byte
|
||||||
RecordInfo AVCDecoderConfRecord
|
RecordInfo AVCDecoderConfRecord
|
||||||
@ -592,7 +530,7 @@ func (self CodecData) Height() int {
|
|||||||
|
|
||||||
func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err error) {
|
func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err error) {
|
||||||
self.Record = record
|
self.Record = record
|
||||||
if self.RecordInfo, err = ParseAVCDecoderConfRecord(record); err != nil {
|
if _, err = (&self.RecordInfo).Unmarshal(record); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(self.RecordInfo.SPS) == 0 {
|
if len(self.RecordInfo.SPS) == 0 {
|
||||||
@ -612,18 +550,19 @@ func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err er
|
|||||||
|
|
||||||
func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err error) {
|
func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err error) {
|
||||||
recordinfo := AVCDecoderConfRecord{}
|
recordinfo := AVCDecoderConfRecord{}
|
||||||
recordinfo.AVCProfileIndication = uint(sps[1])
|
recordinfo.AVCProfileIndication = sps[1]
|
||||||
recordinfo.ProfileCompatibility = uint(sps[2])
|
recordinfo.ProfileCompatibility = sps[2]
|
||||||
recordinfo.AVCLevelIndication = uint(sps[3])
|
recordinfo.AVCLevelIndication = sps[3]
|
||||||
recordinfo.SPS = [][]byte{sps}
|
recordinfo.SPS = [][]byte{sps}
|
||||||
recordinfo.PPS = [][]byte{pps}
|
recordinfo.PPS = [][]byte{pps}
|
||||||
recordinfo.LengthSizeMinusOne = 3
|
recordinfo.LengthSizeMinusOne = 3
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
if err = WriteAVCDecoderConfRecord(buf, recordinfo); err != nil {
|
buf := make([]byte, recordinfo.Len())
|
||||||
return
|
recordinfo.Marshal(buf)
|
||||||
}
|
|
||||||
self.RecordInfo = recordinfo
|
self.RecordInfo = recordinfo
|
||||||
self.Record = buf.Bytes()
|
self.Record = buf
|
||||||
|
|
||||||
if self.SPSInfo, err = ParseSPS(sps); err != nil {
|
if self.SPSInfo, err = ParseSPS(sps); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -631,66 +570,106 @@ func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AVCDecoderConfRecord struct {
|
type AVCDecoderConfRecord struct {
|
||||||
AVCProfileIndication uint
|
AVCProfileIndication uint8
|
||||||
ProfileCompatibility uint
|
ProfileCompatibility uint8
|
||||||
AVCLevelIndication uint
|
AVCLevelIndication uint8
|
||||||
LengthSizeMinusOne uint
|
LengthSizeMinusOne uint8
|
||||||
SPS [][]byte
|
SPS [][]byte
|
||||||
PPS [][]byte
|
PPS [][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseAVCDecoderConfRecord(config []byte) (self AVCDecoderConfRecord, err error) {
|
var ErrDecconfInvalid = fmt.Errorf("h264parser: AVCDecoderConfRecord invalid")
|
||||||
r := bytes.NewReader(config)
|
|
||||||
|
|
||||||
if _, err = bits.ReadUIntBE(r, 8); err != nil {
|
func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
||||||
|
if len(b) < 7 {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if self.AVCProfileIndication, err = bits.ReadUIntBE(r, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if self.ProfileCompatibility, err = bits.ReadUIntBE(r, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if self.AVCLevelIndication, err = bits.ReadUIntBE(r, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if self.LengthSizeMinusOne, err = bits.ReadUIntBE(r, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.LengthSizeMinusOne &= 0x03
|
|
||||||
|
|
||||||
var u uint
|
|
||||||
var n, length int
|
|
||||||
var data []byte
|
|
||||||
|
|
||||||
if u, err = bits.ReadUIntBE(r, 8); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n = int(u&0x1f)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
if u, err = bits.ReadUIntBE(r, 16); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
length = int(u)
|
|
||||||
if data, err = bits.ReadBytes(r, length); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.SPS = append(self.SPS, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u, err = bits.ReadUIntBE(r, 8); err != nil {
|
self.AVCProfileIndication = b[1]
|
||||||
|
self.ProfileCompatibility = b[2]
|
||||||
|
self.AVCLevelIndication = b[3]
|
||||||
|
self.LengthSizeMinusOne = b[4]&0x03
|
||||||
|
spscount := int(b[5]&0x1f)
|
||||||
|
n += 6
|
||||||
|
|
||||||
|
for i := 0; i < spscount; i++ {
|
||||||
|
if len(b) < n+2 {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = int(u)
|
spslen := int(pio.U16BE(b[n:]))
|
||||||
for i := 0; i < n; i++ {
|
n += 2
|
||||||
if u, err = bits.ReadUIntBE(r, 16); err != nil {
|
|
||||||
|
if len(b) < n+spslen {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
length = int(u)
|
self.SPS = append(self.SPS, b[n:n+spslen])
|
||||||
if data, err = bits.ReadBytes(r, length); err != nil {
|
n += spslen
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b) < n+1 {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.PPS = append(self.PPS, data)
|
ppscount := int(b[n])
|
||||||
|
n++
|
||||||
|
|
||||||
|
for i := 0; i < ppscount; i++ {
|
||||||
|
if len(b) < n+2 {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ppslen := int(pio.U16BE(b[n:]))
|
||||||
|
n += 2
|
||||||
|
|
||||||
|
if len(b) < n+ppslen {
|
||||||
|
err = ErrDecconfInvalid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.PPS = append(self.PPS, b[n:n+ppslen])
|
||||||
|
n += ppslen
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self AVCDecoderConfRecord) Len() (n int) {
|
||||||
|
n = 7
|
||||||
|
for _, sps := range self.SPS {
|
||||||
|
n += 2+len(sps)
|
||||||
|
}
|
||||||
|
for _, pps := range self.PPS {
|
||||||
|
n += 2+len(pps)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) {
|
||||||
|
b[0] = 1
|
||||||
|
b[1] = self.AVCProfileIndication
|
||||||
|
b[2] = self.ProfileCompatibility
|
||||||
|
b[3] = self.AVCLevelIndication
|
||||||
|
b[4] = self.LengthSizeMinusOne|0xfc
|
||||||
|
b[5] = uint8(len(self.SPS))|0xe0
|
||||||
|
n += 6
|
||||||
|
|
||||||
|
for _, sps := range self.SPS {
|
||||||
|
pio.PutU16BE(b[n:], uint16(len(sps)))
|
||||||
|
n += 2
|
||||||
|
copy(b[n:], sps)
|
||||||
|
n += len(sps)
|
||||||
|
}
|
||||||
|
|
||||||
|
b[n] = uint8(len(self.PPS))
|
||||||
|
n++
|
||||||
|
|
||||||
|
for _, pps := range self.PPS {
|
||||||
|
pio.PutU16BE(b[n:], uint16(len(pps)))
|
||||||
|
n += 2
|
||||||
|
copy(b[n:], pps)
|
||||||
|
n += len(pps)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -762,43 +741,3 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
type CodecInfo struct {
|
|
||||||
Record AVCDecoderConfRecord
|
|
||||||
SPSInfo SPSInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseCodecData(config []byte) (info CodecInfo, err error) {
|
|
||||||
if info.Record, err = ParseAVCDecoderConfRecord(config); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(info.Record.SPS) < 1 {
|
|
||||||
err = fmt.Errorf("CodecData invalid: no SPS found in AVCDecoderConfRecord")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if info.SPSInfo, err = ParseSPS(info.Record.SPS[0]); err != nil {
|
|
||||||
err = fmt.Errorf("CodecData invalid: parse SPS failed(%s)", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateCodecDataBySPSAndPPS(SPS, PPS []byte) (codecData []byte, err error) {
|
|
||||||
self := AVCDecoderConfRecord{}
|
|
||||||
self.AVCProfileIndication = uint(SPS[1])
|
|
||||||
self.ProfileCompatibility = uint(SPS[2])
|
|
||||||
self.AVCLevelIndication = uint(SPS[3])
|
|
||||||
self.SPS = [][]byte{SPS}
|
|
||||||
self.PPS = [][]byte{PPS}
|
|
||||||
self.LengthSizeMinusOne = 3
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
if err = WriteAVCDecoderConfRecord(buf, self); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
codecData = buf.Bytes()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user