container/mts: added payload.go file with Extract function and types

payload.go has been added which will contain functionality for dealing with MTS
payloads. A function has been added called Extract, which will return a Clip. Clip
is a type representing a sequence of media frames ([]Frame). Type Frame has been
added which represents a media frame. It provides fields to hold the media as
byte slice, PTS to hold the PES timestamp, an ID for identification of codec type
and finally the relevant Meta from the most recent PMT.
This commit is contained in:
Saxon 2019-06-12 01:17:14 +09:30
parent e4bce3bcb3
commit b473451288
1 changed files with 98 additions and 0 deletions

98
container/mts/payload.go Normal file
View File

@ -0,0 +1,98 @@
package mts
import (
"errors"
"github.com/Comcast/gots/packet"
"github.com/Comcast/gots/pes"
)
// Extract extracts the media from an MPEG-TS clip given by p.
func Extract(p []byte) (Clip, error) {
l := len(p)
// Check that clip is divisible by 188, i.e. contains a series of full MPEG-TS clips.
if l%PacketSize != 0 {
return nil, errors.New("MTS clip is not of valid size")
}
// This will hold a copy of all the media in the MTS clip.
buf := make([]byte, 0, l/PacketSize)
var clip Clip
var meta map[string]string
var err error
var prev *Frame
// Go through and get the number of frames, and also their size and allocate
// mem to clip.
var pkt packet.Packet
for i := 0; i < l; i += PacketSize {
copy(pkt[:], p[i:i+PacketSize])
idx := len(buf)
switch pkt.PID() {
case PatPid: // Do nothing.
case PmtPid:
meta, err = ExtractMeta(pkt[:])
if err != nil {
return nil, err
}
default:
// Get the MTS payload.
payload, err := pkt.Payload()
if err != nil {
return nil, err
}
// If PUSI is true then we know it's the start of a new frame, and we have
// a PES header in the MTS payload.
if pkt.PayloadUnitStartIndicator() {
_pes, err := pes.NewPESHeader(payload)
if err != nil {
return nil, err
}
pesData := _pes.Data()
lenOfFrame := len(pesData)
// If we have a previous Frame, then we need to adjust upper bound of
// it's media data.
if prev != nil {
prev.Media = prev.Media[:lenOfFrame]
}
// Create a new frame.
prev = &Frame{
Media: buf[idx:],
PTS: _pes.PTS(),
Meta: meta,
}
// Append media data to underlying media buffer.
buf = append(buf, pesData...)
} else {
buf = append(buf, payload...)
}
// And then append to the clip.
clip = append(clip, *prev)
}
}
// Copy over data
return nil, nil
}
// Clip represents a clip of media, i.e. a sequence of media frames.
type Clip []Frame
// Frame describes a media frame that may be extracted from a PES packet.
type Frame struct {
Media []byte // Contains the media from the frame.
PTS uint64 // PTS from PES packet (this gives time relative from start of stream).
ID int8 // StreamID from the PES packet, identifying media codec.
Meta map[string]string // Contains metadata from PMT relevant to this frame.
}
// Bytes returns the concatentated media bytes from each frame in the Clip c.
func (c *Clip) Bytes() []byte {
return nil
}