vdk/format/mkv/demuxer.go

148 lines
2.9 KiB
Go
Raw Normal View History

2022-01-27 09:10:06 +08:00
package mkv
import (
"encoding/binary"
"errors"
"io"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"git.r-2.top/kunmeng/vdk/format/mkv/mkvio"
2022-01-27 09:10:06 +08:00
)
type Demuxer struct {
r *mkvio.Document
pkts []av.Packet
sps []byte
pps []byte
streams []*Stream
ps uint32
stage int
fc int
ls time.Duration
}
func NewDemuxer(r io.Reader) *Demuxer {
return &Demuxer{
r: mkvio.InitDocument(r),
}
}
func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
if err = self.probe(); err != nil {
return
}
for _, stream := range self.streams {
streams = append(streams, stream.CodecData)
}
if len(streams) == 0 {
return nil, errors.New("streams not found")
}
return streams, err
}
func (self *Demuxer) probe() (err error) {
if self.stage == 0 {
var el *mkvio.Element
el, err = self.r.GetVideoCodec()
if err != nil {
return
}
if el.ElementRegister.ID == mkvio.ElementCodecPrivate.ID {
payload := el.Content[6:]
var reader int
for pos := 0; pos < len(payload); pos = reader {
lens := int(binary.BigEndian.Uint16(payload[reader:]))
reader += 2
nal := payload[reader : reader+lens]
naluType := nal[0] & 0x1f
switch naluType {
case h264parser.NALU_SPS:
self.sps = nal
case h264parser.NALU_PPS:
self.pps = nal
}
reader += lens
reader++
}
}
if len(self.sps) > 0 && len(self.pps) > 0 {
var codec av.CodecData
codec, err = h264parser.NewCodecDataFromSPSAndPPS(self.sps, self.pps)
if err != nil {
return
}
stream := &Stream{}
stream.idx = 0
stream.demuxer = self
stream.CodecData = codec
self.streams = append(self.streams, stream)
}
self.stage++
}
return
}
func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
var el mkvio.Element
for {
el, err = self.r.ParseElement()
if err != nil {
return
}
if el.Type == 6 && el.ElementRegister.ID == mkvio.ElementSimpleBlock.ID {
self.fc++
nals, _ := h264parser.SplitNALUs(el.Content[4:])
for _, nal := range nals {
naluType := nal[0] & 0x1f
if naluType == 5 {
l1 := int(binary.BigEndian.Uint16(el.Content[2:4]))
dur := time.Duration(uint32(l1)) * time.Millisecond
self.ls += time.Duration(uint32(l1)) * time.Millisecond
self.ps = 0
pkt = av.Packet{IsKeyFrame: true, Idx: 0, Duration: dur, Time: self.ls, Data: append(binSize(len(nal)), nal...)}
return
} else if naluType == 1 {
l1 := int(binary.BigEndian.Uint16(el.Content[1:3]))
dur := time.Duration(uint32(l1)-self.ps) * time.Millisecond
self.ls += time.Duration(uint32(l1)-self.ps) * time.Millisecond
self.ps = uint32(l1)
pkt = av.Packet{Idx: 0, Duration: dur, Time: self.ls, Data: append(binSize(len(nal)), nal...)}
return
}
}
}
}
return
}
func binSize(val int) []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(val))
return buf
}