mirror of https://bitbucket.org/ausocean/av.git
99 lines
2.4 KiB
Go
99 lines
2.4 KiB
Go
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
|
|
}
|