joy4/demuxer.go
2016-04-03 20:19:37 +08:00

223 lines
4.3 KiB
Go

package ts
import (
"io"
"bytes"
"fmt"
"github.com/nareix/mp4/isom"
)
type Demuxer struct {
R io.Reader
pat PAT
pmt *PMT
Tracks []*Track
TrackH264 *Track
TrackAAC *Track
}
// ParsePacket() (pid uint, counter int, isStart bool, pts, dst int64, isKeyFrame bool)
// WritePayload(pid, pts, dts, isKeyFrame, payloads, isVideoFrame)
func (self *Demuxer) TimeScale() int64 {
return PTS_HZ
}
func (self *Demuxer) ReadHeader() (err error) {
self.Tracks = []*Track{}
self.TrackH264 = nil
self.TrackAAC = nil
for {
if self.pmt != nil {
n := 0
for _, track := range(self.Tracks) {
if track.payloadReady {
n++
}
}
if n == len(self.Tracks) {
break
}
}
if err = self.readPacket(); err != nil {
return
}
}
return
}
func (self *Demuxer) ReadSample() (track *Track, err error) {
if len(self.Tracks) == 0 {
err = fmt.Errorf("no track")
return
}
for {
for _, _track := range(self.Tracks) {
if _track.payloadReady {
track = _track
return
}
}
if err = self.readPacket(); err != nil {
return
}
}
}
func (self *Demuxer) readPacket() (err error) {
var header TSHeader
var n int
var data [188]byte
if header, n, err = ReadTSPacket(self.R, data[:]); err != nil {
return
}
payload := data[:n]
if header.PID == 0 {
if self.pat, err = ReadPAT(bytes.NewReader(payload)); err != nil {
return
}
} else {
if self.pmt == nil {
for _, entry := range(self.pat.Entries) {
if entry.ProgramMapPID == header.PID {
self.pmt = new(PMT)
if *self.pmt, err = ReadPMT(bytes.NewReader(payload)); err != nil {
return
}
for _, info := range(self.pmt.ElementaryStreamInfos) {
track := &Track{}
track.demuxer = self
track.pid = info.ElementaryPID
switch info.StreamType {
case ElementaryStreamTypeH264:
track.Type = H264
self.TrackH264 = track
self.Tracks = append(self.Tracks, track)
case ElementaryStreamTypeAdtsAAC:
track.Type = AAC
self.TrackAAC = track
self.Tracks = append(self.Tracks, track)
}
}
}
}
} else {
for _, track := range(self.Tracks) {
if header.PID == track.pid {
if err = track.appendPacket(header, payload); err != nil {
return
}
}
}
}
}
return
}
func (self *Track) GetMPEG4AudioConfig() isom.MPEG4AudioConfig {
return self.mpeg4AudioConfig
}
func (self *Track) ReadSample() (pts int64, dts int64, isKeyFrame bool, data []byte, err error) {
for !self.payloadReady {
if err = self.demuxer.readPacket(); err != nil {
return
}
}
if self.Type == AAC {
var n, framelen int
if _, data, n, framelen, err = isom.ReadADTSFrame(self.payload); err != nil {
return
}
self.payload = self.payload[framelen:]
pts = self.PTS
dts = pts
self.PTS += int64(PTS_HZ*n)/int64(self.mpeg4AudioConfig.SampleRate)
if len(self.payload) == 0 {
self.payloadReady = false
}
} else {
dts = int64(self.peshdr.DTS)
pts = int64(self.peshdr.PTS)
if dts == 0 {
dts = pts
}
isKeyFrame = self.tshdr.RandomAccessIndicator
data = self.payload
self.payloadReady = false
}
return
}
func (self *Track) appendPayload() (err error) {
self.payload = self.buf.Bytes()
if len(self.payload) == 0 {
err = fmt.Errorf("empty payload")
return
}
if self.Type == AAC {
if !self.mpeg4AudioConfig.IsValid() {
if self.mpeg4AudioConfig, _, _, _, err = isom.ReadADTSFrame(self.payload); err != nil {
return
}
self.mpeg4AudioConfig = self.mpeg4AudioConfig.Complete()
if !self.mpeg4AudioConfig.IsValid() {
err = fmt.Errorf("invalid MPEG4AudioConfig")
return
}
}
self.PTS = int64(self.peshdr.PTS)
}
self.payloadReady = true
return
}
func (self *Track) appendPacket(header TSHeader, payload []byte) (err error) {
r := bytes.NewReader(payload)
lr := &io.LimitedReader{R: r, N: int64(len(payload))}
if header.PayloadUnitStart && self.peshdr != nil && self.peshdr.DataLength == 0 {
if err = self.appendPayload(); err != nil {
return
}
}
if header.PayloadUnitStart {
self.payloadReady = false
self.buf = bytes.Buffer{}
if self.peshdr, err = ReadPESHeader(lr); err != nil {
return
}
self.tshdr = header
}
if _, err = io.CopyN(&self.buf, lr, lr.N); err != nil {
return
}
if self.buf.Len() == int(self.peshdr.DataLength) {
if err = self.appendPayload(); err != nil {
return
}
}
return
}