go fmt
This commit is contained in:
parent
7098ea1efd
commit
01b5cd703f
86
av/av.go
86
av/av.go
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode.
|
// Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode.
|
||||||
package av
|
package av
|
||||||
|
|
||||||
@ -11,17 +10,17 @@ import (
|
|||||||
type SampleFormat uint8
|
type SampleFormat uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
U8 = SampleFormat(iota + 1) // 8-bit unsigned integer
|
U8 = SampleFormat(iota + 1) // 8-bit unsigned integer
|
||||||
S16 // signed 16-bit integer
|
S16 // signed 16-bit integer
|
||||||
S32 // signed 32-bit integer
|
S32 // signed 32-bit integer
|
||||||
FLT // 32-bit float
|
FLT // 32-bit float
|
||||||
DBL // 64-bit float
|
DBL // 64-bit float
|
||||||
U8P // 8-bit unsigned integer in planar
|
U8P // 8-bit unsigned integer in planar
|
||||||
S16P // signed 16-bit integer in planar
|
S16P // signed 16-bit integer in planar
|
||||||
S32P // signed 32-bit integer in planar
|
S32P // signed 32-bit integer in planar
|
||||||
FLTP // 32-bit float in planar
|
FLTP // 32-bit float in planar
|
||||||
DBLP // 64-bit float in planar
|
DBLP // 64-bit float in planar
|
||||||
U32 // unsigned 32-bit integer
|
U32 // unsigned 32-bit integer
|
||||||
)
|
)
|
||||||
|
|
||||||
func (self SampleFormat) BytesPerSample() int {
|
func (self SampleFormat) BytesPerSample() int {
|
||||||
@ -116,11 +115,11 @@ func (self ChannelLayout) Count() (n int) {
|
|||||||
type CodecType uint32
|
type CodecType uint32
|
||||||
|
|
||||||
var (
|
var (
|
||||||
H264 = MakeVideoCodecType(avCodecTypeMagic + 1)
|
H264 = MakeVideoCodecType(avCodecTypeMagic + 1)
|
||||||
AAC = MakeAudioCodecType(avCodecTypeMagic + 1)
|
AAC = MakeAudioCodecType(avCodecTypeMagic + 1)
|
||||||
PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2)
|
PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2)
|
||||||
PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3)
|
PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3)
|
||||||
SPEEX = MakeAudioCodecType(avCodecTypeMagic + 4)
|
SPEEX = MakeAudioCodecType(avCodecTypeMagic + 4)
|
||||||
NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5)
|
NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -179,15 +178,15 @@ type CodecData interface {
|
|||||||
|
|
||||||
type VideoCodecData interface {
|
type VideoCodecData interface {
|
||||||
CodecData
|
CodecData
|
||||||
Width() int // Video width
|
Width() int // Video width
|
||||||
Height() int // Video height
|
Height() int // Video height
|
||||||
}
|
}
|
||||||
|
|
||||||
type AudioCodecData interface {
|
type AudioCodecData interface {
|
||||||
CodecData
|
CodecData
|
||||||
SampleFormat() SampleFormat // audio sample format
|
SampleFormat() SampleFormat // audio sample format
|
||||||
SampleRate() int // audio sample rate
|
SampleRate() int // audio sample rate
|
||||||
ChannelLayout() ChannelLayout // audio channel layout
|
ChannelLayout() ChannelLayout // audio channel layout
|
||||||
PacketDuration([]byte) (time.Duration, error) // get audio compressed packet duration
|
PacketDuration([]byte) (time.Duration, error) // get audio compressed packet duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +195,7 @@ type PacketWriter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PacketReader interface {
|
type PacketReader interface {
|
||||||
ReadPacket() (Packet,error)
|
ReadPacket() (Packet, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Muxer describes the steps of writing compressed audio/video packets into container formats like MP4/FLV/MPEG-TS.
|
// Muxer describes the steps of writing compressed audio/video packets into container formats like MP4/FLV/MPEG-TS.
|
||||||
@ -204,8 +203,8 @@ type PacketReader interface {
|
|||||||
// Container formats, rtmp.Conn, and transcode.Muxer implements Muxer interface.
|
// Container formats, rtmp.Conn, and transcode.Muxer implements Muxer interface.
|
||||||
type Muxer interface {
|
type Muxer interface {
|
||||||
WriteHeader([]CodecData) error // write the file header
|
WriteHeader([]CodecData) error // write the file header
|
||||||
PacketWriter // write compressed audio/video packets
|
PacketWriter // write compressed audio/video packets
|
||||||
WriteTrailer() error // finish writing file, this func can be called only once
|
WriteTrailer() error // finish writing file, this func can be called only once
|
||||||
}
|
}
|
||||||
|
|
||||||
// Muxer with Close() method
|
// Muxer with Close() method
|
||||||
@ -216,7 +215,7 @@ type MuxCloser interface {
|
|||||||
|
|
||||||
// Demuxer can read compressed audio/video packets from container formats like MP4/FLV/MPEG-TS.
|
// Demuxer can read compressed audio/video packets from container formats like MP4/FLV/MPEG-TS.
|
||||||
type Demuxer interface {
|
type Demuxer interface {
|
||||||
PacketReader // read compressed audio/video packets
|
PacketReader // read compressed audio/video packets
|
||||||
Streams() ([]CodecData, error) // reads the file header, contains video/audio meta infomations
|
Streams() ([]CodecData, error) // reads the file header, contains video/audio meta infomations
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,20 +227,20 @@ type DemuxCloser interface {
|
|||||||
|
|
||||||
// Packet stores compressed audio/video data.
|
// Packet stores compressed audio/video data.
|
||||||
type Packet struct {
|
type Packet struct {
|
||||||
IsKeyFrame bool // video packet is key frame
|
IsKeyFrame bool // video packet is key frame
|
||||||
Idx int8 // stream index in container format
|
Idx int8 // stream index in container format
|
||||||
CompositionTime time.Duration // packet presentation time minus decode time for H264 B-Frame
|
CompositionTime time.Duration // packet presentation time minus decode time for H264 B-Frame
|
||||||
Time time.Duration // packet decode time
|
Time time.Duration // packet decode time
|
||||||
Data []byte // packet data
|
Data []byte // packet data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw audio frame.
|
// Raw audio frame.
|
||||||
type AudioFrame struct {
|
type AudioFrame struct {
|
||||||
SampleFormat SampleFormat // audio sample format, e.g: S16,FLTP,...
|
SampleFormat SampleFormat // audio sample format, e.g: S16,FLTP,...
|
||||||
ChannelLayout ChannelLayout // audio channel layout, e.g: CH_MONO,CH_STEREO,...
|
ChannelLayout ChannelLayout // audio channel layout, e.g: CH_MONO,CH_STEREO,...
|
||||||
SampleCount int // sample count in this frame
|
SampleCount int // sample count in this frame
|
||||||
SampleRate int // sample rate
|
SampleRate int // sample rate
|
||||||
Data [][]byte // data array for planar format len(Data) > 1
|
Data [][]byte // data array for planar format len(Data) > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self AudioFrame) Duration() time.Duration {
|
func (self AudioFrame) Duration() time.Duration {
|
||||||
@ -291,26 +290,25 @@ func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) {
|
|||||||
// AudioEncoder can encode raw audio frame into compressed audio packets.
|
// AudioEncoder can encode raw audio frame into compressed audio packets.
|
||||||
// cgo/ffmpeg inplements AudioEncoder, using ffmpeg.NewAudioEncoder to create it.
|
// cgo/ffmpeg inplements AudioEncoder, using ffmpeg.NewAudioEncoder to create it.
|
||||||
type AudioEncoder interface {
|
type AudioEncoder interface {
|
||||||
CodecData() (AudioCodecData, error) // encoder's codec data can put into container
|
CodecData() (AudioCodecData, error) // encoder's codec data can put into container
|
||||||
Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s)
|
Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s)
|
||||||
Close() // close encoder, free cgo contexts
|
Close() // close encoder, free cgo contexts
|
||||||
SetSampleRate(int) (error) // set encoder sample rate
|
SetSampleRate(int) error // set encoder sample rate
|
||||||
SetChannelLayout(ChannelLayout) (error) // set encoder channel layout
|
SetChannelLayout(ChannelLayout) error // set encoder channel layout
|
||||||
SetSampleFormat(SampleFormat) (error) // set encoder sample format
|
SetSampleFormat(SampleFormat) error // set encoder sample format
|
||||||
SetBitrate(int) (error) // set encoder bitrate
|
SetBitrate(int) error // set encoder bitrate
|
||||||
SetOption(string,interface{}) (error) // encoder setopt, in ffmpeg is av_opt_set_dict()
|
SetOption(string, interface{}) error // encoder setopt, in ffmpeg is av_opt_set_dict()
|
||||||
GetOption(string,interface{}) (error) // encoder getopt
|
GetOption(string, interface{}) error // encoder getopt
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioDecoder can decode compressed audio packets into raw audio frame.
|
// AudioDecoder can decode compressed audio packets into raw audio frame.
|
||||||
// use ffmpeg.NewAudioDecoder to create it.
|
// use ffmpeg.NewAudioDecoder to create it.
|
||||||
type AudioDecoder interface {
|
type AudioDecoder interface {
|
||||||
Decode([]byte) (bool, AudioFrame, error) // decode one compressed audio packet
|
Decode([]byte) (bool, AudioFrame, error) // decode one compressed audio packet
|
||||||
Close() // close decode, free cgo contexts
|
Close() // close decode, free cgo contexts
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioResampler can convert raw audio frames in different sample rate/format/channel layout.
|
// AudioResampler can convert raw audio frames in different sample rate/format/channel layout.
|
||||||
type AudioResampler interface {
|
type AudioResampler interface {
|
||||||
Resample(AudioFrame) (AudioFrame, error) // convert raw audio frames
|
Resample(AudioFrame) (AudioFrame, error) // convert raw audio frames
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,19 +2,19 @@ package avconv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
"github.com/datarhei/joy4/av/pktque"
|
"github.com/datarhei/joy4/av/pktque"
|
||||||
"github.com/datarhei/joy4/av/transcode"
|
"github.com/datarhei/joy4/av/transcode"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
|
||||||
type Option struct {
|
type Option struct {
|
||||||
Transcode bool
|
Transcode bool
|
||||||
Args []string
|
Args []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@ -23,7 +23,7 @@ type Options struct {
|
|||||||
|
|
||||||
type Demuxer struct {
|
type Demuxer struct {
|
||||||
transdemux *transcode.Demuxer
|
transdemux *transcode.Demuxer
|
||||||
streams []av.CodecData
|
streams []av.CodecData
|
||||||
Options
|
Options
|
||||||
Demuxer av.Demuxer
|
Demuxer av.Demuxer
|
||||||
}
|
}
|
||||||
@ -56,10 +56,10 @@ func (self *Demuxer) prepare() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var streams []av.CodecData
|
var streams []av.CodecData
|
||||||
if streams, err = self.Demuxer.Streams(); err != nil {
|
if streams, err = self.Demuxer.Streams(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
supports := self.Options.OutputCodecTypes
|
supports := self.Options.OutputCodecTypes
|
||||||
@ -83,7 +83,7 @@ func (self *Demuxer) prepare() (err error) {
|
|||||||
ok = true
|
ok = true
|
||||||
|
|
||||||
var enctype av.CodecType
|
var enctype av.CodecType
|
||||||
for _, typ:= range supports {
|
for _, typ := range supports {
|
||||||
if typ.IsAudio() {
|
if typ.IsAudio() {
|
||||||
if enc, _ = avutil.DefaultHandlers.NewAudioEncoder(typ); enc != nil {
|
if enc, _ = avutil.DefaultHandlers.NewAudioEncoder(typ); enc != nil {
|
||||||
enctype = typ
|
enctype = typ
|
||||||
@ -152,7 +152,7 @@ func ConvertCmdline(args []string) (err error) {
|
|||||||
flagt = false
|
flagt = false
|
||||||
var f float64
|
var f float64
|
||||||
fmt.Sscanf(arg, "%f", &f)
|
fmt.Sscanf(arg, "%f", &f)
|
||||||
duration = time.Duration(f*float64(time.Second))
|
duration = time.Duration(f * float64(time.Second))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
output = arg
|
output = arg
|
||||||
@ -223,7 +223,7 @@ func ConvertCmdline(args []string) (err error) {
|
|||||||
}
|
}
|
||||||
filterdemux := &pktque.FilterDemuxer{
|
filterdemux := &pktque.FilterDemuxer{
|
||||||
Demuxer: convdemux,
|
Demuxer: convdemux,
|
||||||
Filter: filters,
|
Filter: filters,
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -252,4 +252,3 @@ func ConvertCmdline(args []string) (err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package avutil
|
package avutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/datarhei/joy4/av"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/datarhei/joy4/av"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HandlerDemuxer struct {
|
type HandlerDemuxer struct {
|
||||||
@ -22,7 +23,7 @@ func (self *HandlerDemuxer) Close() error {
|
|||||||
|
|
||||||
type HandlerMuxer struct {
|
type HandlerMuxer struct {
|
||||||
av.Muxer
|
av.Muxer
|
||||||
w io.WriteCloser
|
w io.WriteCloser
|
||||||
stage int
|
stage int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,18 +55,18 @@ func (self *HandlerMuxer) Close() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RegisterHandler struct {
|
type RegisterHandler struct {
|
||||||
Ext string
|
Ext string
|
||||||
ReaderDemuxer func(io.Reader)av.Demuxer
|
ReaderDemuxer func(io.Reader) av.Demuxer
|
||||||
WriterMuxer func(io.Writer)av.Muxer
|
WriterMuxer func(io.Writer) av.Muxer
|
||||||
UrlMuxer func(string)(bool,av.MuxCloser,error)
|
UrlMuxer func(string) (bool, av.MuxCloser, error)
|
||||||
UrlDemuxer func(string)(bool,av.DemuxCloser,error)
|
UrlDemuxer func(string) (bool, av.DemuxCloser, error)
|
||||||
UrlReader func(string)(bool,io.ReadCloser,error)
|
UrlReader func(string) (bool, io.ReadCloser, error)
|
||||||
Probe func([]byte)bool
|
Probe func([]byte) bool
|
||||||
AudioEncoder func(av.CodecType)(av.AudioEncoder,error)
|
AudioEncoder func(av.CodecType) (av.AudioEncoder, error)
|
||||||
AudioDecoder func(av.AudioCodecData)(av.AudioDecoder,error)
|
AudioDecoder func(av.AudioCodecData) (av.AudioDecoder, error)
|
||||||
ServerDemuxer func(string)(bool,av.DemuxCloser,error)
|
ServerDemuxer func(string) (bool, av.DemuxCloser, error)
|
||||||
ServerMuxer func(string)(bool,av.MuxCloser,error)
|
ServerMuxer func(string) (bool, av.MuxCloser, error)
|
||||||
CodecTypes []av.CodecType
|
CodecTypes []av.CodecType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
@ -108,7 +109,7 @@ func (self *Handlers) NewAudioEncoder(typ av.CodecType) (enc av.AudioEncoder, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("avutil: encoder", typ, "not found")
|
err = fmt.Errorf("avutil: encoder %s not found", typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ func (self *Handlers) NewAudioDecoder(codec av.AudioCodecData) (dec av.AudioDeco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("avutil: decoder", codec.Type(), "not found")
|
err = fmt.Errorf("avutil: decoder %s not found", codec.Type())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +168,7 @@ func (self *Handlers) Open(uri string) (demuxer av.DemuxCloser, err error) {
|
|||||||
}
|
}
|
||||||
demuxer = &HandlerDemuxer{
|
demuxer = &HandlerDemuxer{
|
||||||
Demuxer: handler.ReaderDemuxer(r),
|
Demuxer: handler.ReaderDemuxer(r),
|
||||||
r: r,
|
r: r,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -196,7 +197,7 @@ func (self *Handlers) Open(uri string) (demuxer av.DemuxCloser, err error) {
|
|||||||
}
|
}
|
||||||
demuxer = &HandlerDemuxer{
|
demuxer = &HandlerDemuxer{
|
||||||
Demuxer: handler.ReaderDemuxer(_r),
|
Demuxer: handler.ReaderDemuxer(_r),
|
||||||
r: r,
|
r: r,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -254,7 +255,7 @@ func (self *Handlers) FindCreate(uri string) (handler RegisterHandler, muxer av.
|
|||||||
}
|
}
|
||||||
muxer = &HandlerMuxer{
|
muxer = &HandlerMuxer{
|
||||||
Muxer: handler.WriterMuxer(w),
|
Muxer: handler.WriterMuxer(w),
|
||||||
w: w,
|
w: w,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
|
|
||||||
// Package pktque provides packet Filter interface and structures used by other components.
|
// Package pktque provides packet Filter interface and structures used by other components.
|
||||||
package pktque
|
package pktque
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
@ -30,8 +29,8 @@ func (self Filters) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoid
|
|||||||
// Wrap origin Demuxer and Filter into a new Demuxer, when read this Demuxer filters will be called.
|
// Wrap origin Demuxer and Filter into a new Demuxer, when read this Demuxer filters will be called.
|
||||||
type FilterDemuxer struct {
|
type FilterDemuxer struct {
|
||||||
av.Demuxer
|
av.Demuxer
|
||||||
Filter Filter
|
Filter Filter
|
||||||
streams []av.CodecData
|
streams []av.CodecData
|
||||||
videoidx int
|
videoidx int
|
||||||
audioidx int
|
audioidx int
|
||||||
}
|
}
|
||||||
@ -81,9 +80,9 @@ func (self *WaitKeyFrame) ModifyPacket(pkt *av.Packet, streams []av.CodecData, v
|
|||||||
|
|
||||||
// Fix incorrect packet timestamps.
|
// Fix incorrect packet timestamps.
|
||||||
type FixTime struct {
|
type FixTime struct {
|
||||||
zerobase time.Duration
|
zerobase time.Duration
|
||||||
incrbase time.Duration
|
incrbase time.Duration
|
||||||
lasttime time.Duration
|
lasttime time.Duration
|
||||||
StartFromZero bool // make timestamp start from zero
|
StartFromZero bool // make timestamp start from zero
|
||||||
MakeIncrement bool // force timestamp increment
|
MakeIncrement bool // force timestamp increment
|
||||||
}
|
}
|
||||||
@ -114,14 +113,14 @@ func (self *FixTime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoi
|
|||||||
// Drop incorrect packets to make A/V sync.
|
// Drop incorrect packets to make A/V sync.
|
||||||
type AVSync struct {
|
type AVSync struct {
|
||||||
MaxTimeDiff time.Duration
|
MaxTimeDiff time.Duration
|
||||||
time []time.Duration
|
time []time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *AVSync) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
|
func (self *AVSync) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
|
||||||
if self.time == nil {
|
if self.time == nil {
|
||||||
self.time = make([]time.Duration, len(streams))
|
self.time = make([]time.Duration, len(streams))
|
||||||
if self.MaxTimeDiff == 0 {
|
if self.MaxTimeDiff == 0 {
|
||||||
self.MaxTimeDiff = time.Millisecond*500
|
self.MaxTimeDiff = time.Millisecond * 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,4 +187,3 @@ func (self *Walltime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, video
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ type tlSeg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Timeline struct {
|
type Timeline struct {
|
||||||
segs []tlSeg
|
segs []tlSeg
|
||||||
headtm time.Duration
|
headtm time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Timeline) Push(tm time.Duration, dur time.Duration) {
|
func (self *Timeline) Push(tm time.Duration, dur time.Duration) {
|
||||||
if len(self.segs) > 0 {
|
if len(self.segs) > 0 {
|
||||||
tail := self.segs[len(self.segs)-1]
|
tail := self.segs[len(self.segs)-1]
|
||||||
diff := tm-(tail.tm+tail.dur)
|
diff := tm - (tail.tm + tail.dur)
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
tm -= diff
|
tm -= diff
|
||||||
}
|
}
|
||||||
@ -58,4 +58,3 @@ func (self *Timeline) Pop(dur time.Duration) (tm time.Duration) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
package pubsub
|
package pubsub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/datarhei/joy4/av"
|
|
||||||
"github.com/datarhei/joy4/av/pktque"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/datarhei/joy4/av"
|
||||||
|
"github.com/datarhei/joy4/av/pktque"
|
||||||
)
|
)
|
||||||
|
|
||||||
// time
|
// time
|
||||||
@ -97,7 +98,6 @@ func (self *Queue) WritePacket(pkt av.Packet) (err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//println("shrink", self.curgopcount, self.maxgopcount, self.buf.Head, self.buf.Tail, "count", self.buf.Count, "size", self.buf.Size)
|
|
||||||
|
|
||||||
self.cond.Broadcast()
|
self.cond.Broadcast()
|
||||||
|
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
|
|
||||||
// Package transcoder implements Transcoder based on Muxer/Demuxer and AudioEncoder/AudioDecoder interface.
|
// Package transcoder implements Transcoder based on Muxer/Demuxer and AudioEncoder/AudioDecoder interface.
|
||||||
package transcode
|
package transcode
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/av/pktque"
|
"github.com/datarhei/joy4/av/pktque"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
|
||||||
type tStream struct {
|
type tStream struct {
|
||||||
codec av.CodecData
|
codec av.CodecData
|
||||||
timeline *pktque.Timeline
|
timeline *pktque.Timeline
|
||||||
aencodec, adecodec av.AudioCodecData
|
aencodec, adecodec av.AudioCodecData
|
||||||
aenc av.AudioEncoder
|
aenc av.AudioEncoder
|
||||||
adec av.AudioDecoder
|
adec av.AudioDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@ -27,7 +26,7 @@ type Options struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Transcoder struct {
|
type Transcoder struct {
|
||||||
streams []*tStream
|
streams []*tStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTranscoder(streams []av.CodecData, options Options) (_self *Transcoder, err error) {
|
func NewTranscoder(streams []av.CodecData, options Options) (_self *Transcoder, err error) {
|
||||||
@ -150,8 +149,8 @@ func (self *Transcoder) Close() (err error) {
|
|||||||
// Wrap transcoder and origin Muxer into new Muxer.
|
// Wrap transcoder and origin Muxer into new Muxer.
|
||||||
// Write to new Muxer will do transcoding automatically.
|
// Write to new Muxer will do transcoding automatically.
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
av.Muxer // origin Muxer
|
av.Muxer // origin Muxer
|
||||||
Options // transcode options
|
Options // transcode options
|
||||||
transcoder *Transcoder
|
transcoder *Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +194,7 @@ type Demuxer struct {
|
|||||||
av.Demuxer
|
av.Demuxer
|
||||||
Options
|
Options
|
||||||
transcoder *Transcoder
|
transcoder *Transcoder
|
||||||
outpkts []av.Packet
|
outpkts []av.Packet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Demuxer) prepare() (err error) {
|
func (self *Demuxer) prepare() (err error) {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package aacparser
|
package aacparser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/datarhei/joy4/utils/bits"
|
|
||||||
"github.com/datarhei/joy4/av"
|
|
||||||
"time"
|
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/datarhei/joy4/av"
|
||||||
|
"github.com/datarhei/joy4/utils/bits"
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// copied from libavcodec/mpeg4audio.h
|
// copied from libavcodec/mpeg4audio.h
|
||||||
@ -83,12 +83,12 @@ These are the channel configurations:
|
|||||||
var chanConfigTable = []av.ChannelLayout{
|
var chanConfigTable = []av.ChannelLayout{
|
||||||
0,
|
0,
|
||||||
av.CH_FRONT_CENTER,
|
av.CH_FRONT_CENTER,
|
||||||
av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT,
|
av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT,
|
||||||
av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT,
|
av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT,
|
||||||
av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_CENTER,
|
av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_CENTER,
|
||||||
av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT,
|
av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT,
|
||||||
av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT|av.CH_LOW_FREQ,
|
av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT | av.CH_LOW_FREQ,
|
||||||
av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_SIDE_LEFT|av.CH_SIDE_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT|av.CH_LOW_FREQ,
|
av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_SIDE_LEFT | av.CH_SIDE_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT | av.CH_LOW_FREQ,
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseADTSHeader(frame []byte) (config MPEG4AudioConfig, hdrlen int, framelen int, samples int, err error) {
|
func ParseADTSHeader(frame []byte) (config MPEG4AudioConfig, hdrlen int, framelen int, samples int, err error) {
|
||||||
@ -266,7 +266,7 @@ func WriteMPEG4AudioConfig(w io.Writer, config MPEG4AudioConfig) (err error) {
|
|||||||
|
|
||||||
type CodecData struct {
|
type CodecData struct {
|
||||||
ConfigBytes []byte
|
ConfigBytes []byte
|
||||||
Config MPEG4AudioConfig
|
Config MPEG4AudioConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self CodecData) Type() av.CodecType {
|
func (self CodecData) Type() av.CodecType {
|
||||||
@ -308,4 +308,3 @@ func NewCodecDataFromMPEG4AudioConfigBytes(config []byte) (self CodecData, err e
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration, error) {
|
|||||||
// libavcodec/libspeexdec.c
|
// libavcodec/libspeexdec.c
|
||||||
// samples = samplerate/50
|
// samples = samplerate/50
|
||||||
// duration = 0.02s
|
// duration = 0.02s
|
||||||
return time.Millisecond*20, nil
|
return time.Millisecond * 20, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData {
|
func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData {
|
||||||
@ -61,4 +61,3 @@ func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData {
|
|||||||
codec.ChannelLayout_ = cl
|
codec.ChannelLayout_ = cl
|
||||||
return codec
|
return codec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CodecData struct {
|
type CodecData struct {
|
||||||
CodecType_ av.CodecType
|
CodecType_ av.CodecType
|
||||||
SampleRate_ int
|
SampleRate_ int
|
||||||
SampleFormat_ av.SampleFormat
|
SampleFormat_ av.SampleFormat
|
||||||
ChannelLayout_ av.ChannelLayout
|
ChannelLayout_ av.ChannelLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,4 +26,3 @@ func (self CodecData) ChannelLayout() av.ChannelLayout {
|
|||||||
func (self CodecData) SampleRate() int {
|
func (self CodecData) SampleRate() int {
|
||||||
return self.SampleRate_
|
return self.SampleRate_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
|
|
||||||
package h264parser
|
package h264parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/utils/bits"
|
"github.com/datarhei/joy4/utils/bits"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"fmt"
|
|
||||||
"bytes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -199,8 +198,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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var StartCodeBytes = []byte{0,0,1}
|
var StartCodeBytes = []byte{0, 0, 1}
|
||||||
var AUDBytes = []byte{0,0,0,1,0x9,0xf0,0,0,0,1} // AUD
|
var AUDBytes = []byte{0, 0, 0, 1, 0x9, 0xf0, 0, 0, 0, 1} // AUD
|
||||||
|
|
||||||
func CheckNALUsType(b []byte) (typ int) {
|
func CheckNALUsType(b []byte) (typ int) {
|
||||||
_, typ = SplitNALUs(b)
|
_, typ = SplitNALUs(b)
|
||||||
@ -499,9 +498,9 @@ func ParseSPS(data []byte) (self SPSInfo, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CodecData struct {
|
type CodecData struct {
|
||||||
Record []byte
|
Record []byte
|
||||||
RecordInfo AVCDecoderConfRecord
|
RecordInfo AVCDecoderConfRecord
|
||||||
SPSInfo SPSInfo
|
SPSInfo SPSInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self CodecData) Type() av.CodecType {
|
func (self CodecData) Type() av.CodecType {
|
||||||
@ -589,8 +588,8 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
|||||||
self.AVCProfileIndication = b[1]
|
self.AVCProfileIndication = b[1]
|
||||||
self.ProfileCompatibility = b[2]
|
self.ProfileCompatibility = b[2]
|
||||||
self.AVCLevelIndication = b[3]
|
self.AVCLevelIndication = b[3]
|
||||||
self.LengthSizeMinusOne = b[4]&0x03
|
self.LengthSizeMinusOne = b[4] & 0x03
|
||||||
spscount := int(b[5]&0x1f)
|
spscount := int(b[5] & 0x1f)
|
||||||
n += 6
|
n += 6
|
||||||
|
|
||||||
for i := 0; i < spscount; i++ {
|
for i := 0; i < spscount; i++ {
|
||||||
@ -638,10 +637,10 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
|||||||
func (self AVCDecoderConfRecord) Len() (n int) {
|
func (self AVCDecoderConfRecord) Len() (n int) {
|
||||||
n = 7
|
n = 7
|
||||||
for _, sps := range self.SPS {
|
for _, sps := range self.SPS {
|
||||||
n += 2+len(sps)
|
n += 2 + len(sps)
|
||||||
}
|
}
|
||||||
for _, pps := range self.PPS {
|
for _, pps := range self.PPS {
|
||||||
n += 2+len(pps)
|
n += 2 + len(pps)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -651,8 +650,8 @@ func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) {
|
|||||||
b[1] = self.AVCProfileIndication
|
b[1] = self.AVCProfileIndication
|
||||||
b[2] = self.ProfileCompatibility
|
b[2] = self.ProfileCompatibility
|
||||||
b[3] = self.AVCLevelIndication
|
b[3] = self.AVCLevelIndication
|
||||||
b[4] = self.LengthSizeMinusOne|0xfc
|
b[4] = self.LengthSizeMinusOne | 0xfc
|
||||||
b[5] = uint8(len(self.SPS))|0xe0
|
b[5] = uint8(len(self.SPS)) | 0xe0
|
||||||
n += 6
|
n += 6
|
||||||
|
|
||||||
for _, sps := range self.SPS {
|
for _, sps := range self.SPS {
|
||||||
@ -690,7 +689,7 @@ func (self SliceType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SLICE_P = iota+1
|
SLICE_P = iota + 1
|
||||||
SLICE_B
|
SLICE_B
|
||||||
SLICE_I
|
SLICE_I
|
||||||
)
|
)
|
||||||
@ -702,9 +701,9 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nal_unit_type := packet[0]&0x1f
|
nal_unit_type := packet[0] & 0x1f
|
||||||
switch nal_unit_type {
|
switch nal_unit_type {
|
||||||
case 1,2,5,19:
|
case 1, 2, 5, 19:
|
||||||
// slice_layer_without_partitioning_rbsp
|
// slice_layer_without_partitioning_rbsp
|
||||||
// slice_data_partition_a_layer_rbsp
|
// slice_data_partition_a_layer_rbsp
|
||||||
|
|
||||||
@ -727,11 +726,11 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch u {
|
switch u {
|
||||||
case 0,3,5,8:
|
case 0, 3, 5, 8:
|
||||||
sliceType = SLICE_P
|
sliceType = SLICE_P
|
||||||
case 1,6:
|
case 1, 6:
|
||||||
sliceType = SLICE_B
|
sliceType = SLICE_B
|
||||||
case 2,4,7,9:
|
case 2, 4, 7, 9:
|
||||||
sliceType = SLICE_I
|
sliceType = SLICE_I
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("h264parser: slice_type=%d invalid", u)
|
err = fmt.Errorf("h264parser: slice_type=%d invalid", u)
|
||||||
@ -740,4 +739,3 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
package h264parser
|
package h264parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
func TestParser(t *testing.T) {
|
||||||
@ -20,4 +19,3 @@ func TestParser(t *testing.T) {
|
|||||||
nalus, ok = SplitNALUs(avccFrame)
|
nalus, ok = SplitNALUs(avccFrame)
|
||||||
t.Log(ok, len(nalus))
|
t.Log(ok, len(nalus))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
doc.go
1
doc.go
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// Package joy4 is a Golang audio/video library and streaming server.
|
// Package joy4 is a Golang audio/video library and streaming server.
|
||||||
// JOY4 is powerful library written in golang, well-designed interface makes a few lines
|
// JOY4 is powerful library written in golang, well-designed interface makes a few lines
|
||||||
// of code can do a lot of things such as reading, writing, transcoding among
|
// of code can do a lot of things such as reading, writing, transcoding among
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
|
|
||||||
package aac
|
package aac
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
|
||||||
"github.com/datarhei/joy4/av"
|
|
||||||
"github.com/datarhei/joy4/codec/aacparser"
|
|
||||||
"time"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"github.com/datarhei/joy4/av"
|
||||||
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
|
"github.com/datarhei/joy4/codec/aacparser"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
config aacparser.MPEG4AudioConfig
|
config aacparser.MPEG4AudioConfig
|
||||||
adtshdr []byte
|
adtshdr []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMuxer(w io.Writer) *Muxer {
|
func NewMuxer(w io.Writer) *Muxer {
|
||||||
return &Muxer{
|
return &Muxer{
|
||||||
adtshdr: make([]byte, aacparser.ADTSHeaderLength),
|
adtshdr: make([]byte, aacparser.ADTSHeaderLength),
|
||||||
w: w,
|
w: w,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +51,10 @@ func (self *Muxer) WriteTrailer() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Demuxer struct {
|
type Demuxer struct {
|
||||||
r *bufio.Reader
|
r *bufio.Reader
|
||||||
config aacparser.MPEG4AudioConfig
|
config aacparser.MPEG4AudioConfig
|
||||||
codecdata av.CodecData
|
codecdata av.CodecData
|
||||||
ts time.Duration
|
ts time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDemuxer(r io.Reader) *Demuxer {
|
func NewDemuxer(r io.Reader) *Demuxer {
|
||||||
|
@ -3,7 +3,6 @@ package flv
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
"github.com/datarhei/joy4/codec"
|
"github.com/datarhei/joy4/codec"
|
||||||
@ -11,6 +10,7 @@ import (
|
|||||||
"github.com/datarhei/joy4/codec/fake"
|
"github.com/datarhei/joy4/codec/fake"
|
||||||
"github.com/datarhei/joy4/codec/h264parser"
|
"github.com/datarhei/joy4/codec/h264parser"
|
||||||
"github.com/datarhei/joy4/format/flv/flvio"
|
"github.com/datarhei/joy4/format/flv/flvio"
|
||||||
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package flvio
|
package flvio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"math"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AMF0ParseError struct {
|
type AMF0ParseError struct {
|
||||||
Offset int
|
Offset int
|
||||||
Message string
|
Message string
|
||||||
Next *AMF0ParseError
|
Next *AMF0ParseError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *AMF0ParseError) Error() string {
|
func (self *AMF0ParseError) Error() string {
|
||||||
@ -25,9 +25,9 @@ func (self *AMF0ParseError) Error() string {
|
|||||||
func amf0ParseErr(message string, offset int, err error) error {
|
func amf0ParseErr(message string, offset int, err error) error {
|
||||||
next, _ := err.(*AMF0ParseError)
|
next, _ := err.(*AMF0ParseError)
|
||||||
return &AMF0ParseError{
|
return &AMF0ParseError{
|
||||||
Offset: offset,
|
Offset: offset,
|
||||||
Message: message,
|
Message: message,
|
||||||
Next: next,
|
Next: next,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ func LenAMF0Val(_val interface{}) (n int) {
|
|||||||
case AMFECMAArray:
|
case AMFECMAArray:
|
||||||
n += 5
|
n += 5
|
||||||
for k, v := range val {
|
for k, v := range val {
|
||||||
n += 2+len(k)
|
n += 2 + len(k)
|
||||||
n += LenAMF0Val(v)
|
n += LenAMF0Val(v)
|
||||||
}
|
}
|
||||||
n += 3
|
n += 3
|
||||||
@ -142,7 +142,7 @@ func LenAMF0Val(_val interface{}) (n int) {
|
|||||||
n++
|
n++
|
||||||
for k, v := range val {
|
for k, v := range val {
|
||||||
if len(k) > 0 {
|
if len(k) > 0 {
|
||||||
n += 2+len(k)
|
n += 2 + len(k)
|
||||||
n += LenAMF0Val(v)
|
n += LenAMF0Val(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ func LenAMF0Val(_val interface{}) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case time.Time:
|
case time.Time:
|
||||||
n += 1+8+2
|
n += 1 + 8 + 2
|
||||||
|
|
||||||
case bool:
|
case bool:
|
||||||
n += 2
|
n += 2
|
||||||
@ -253,7 +253,7 @@ func FillAMF0Val(b []byte, _val interface{}) (n int) {
|
|||||||
b[n] = datemarker
|
b[n] = datemarker
|
||||||
n++
|
n++
|
||||||
u := val.UnixNano()
|
u := val.UnixNano()
|
||||||
f := float64(u/1000000)
|
f := float64(u / 1000000)
|
||||||
n += fillBEFloat64(b[n:], f)
|
n += fillBEFloat64(b[n:], f)
|
||||||
pio.PutU16BE(b[n:], uint16(0))
|
pio.PutU16BE(b[n:], uint16(0))
|
||||||
n += 2
|
n += 2
|
||||||
@ -278,7 +278,6 @@ func FillAMF0Val(b []byte, _val interface{}) (n int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func ParseAMF0Val(b []byte) (val interface{}, n int, err error) {
|
func ParseAMF0Val(b []byte) (val interface{}, n int, err error) {
|
||||||
return parseAMF0Val(b, 0)
|
return parseAMF0Val(b, 0)
|
||||||
}
|
}
|
||||||
@ -320,7 +319,7 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
err = amf0ParseErr("string.body", offset+n, err)
|
err = amf0ParseErr("string.body", offset+n, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val = string(b[n:n+length])
|
val = string(b[n : n+length])
|
||||||
n += length
|
n += length
|
||||||
|
|
||||||
case objectmarker:
|
case objectmarker:
|
||||||
@ -340,7 +339,7 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
err = amf0ParseErr("object.key.body", offset+n, err)
|
err = amf0ParseErr("object.key.body", offset+n, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
okey := string(b[n:n+length])
|
okey := string(b[n : n+length])
|
||||||
n += length
|
n += length
|
||||||
|
|
||||||
var nval int
|
var nval int
|
||||||
@ -387,7 +386,7 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
err = amf0ParseErr("array.key.body", offset+n, err)
|
err = amf0ParseErr("array.key.body", offset+n, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
okey := string(b[n:n+length])
|
okey := string(b[n : n+length])
|
||||||
n += length
|
n += length
|
||||||
|
|
||||||
var nval int
|
var nval int
|
||||||
@ -439,7 +438,7 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ts := parseBEFloat64(b[n:])
|
ts := parseBEFloat64(b[n:])
|
||||||
n += 8+2
|
n += 8 + 2
|
||||||
|
|
||||||
val = time.Unix(int64(ts/1000), (int64(ts)%1000)*1000000)
|
val = time.Unix(int64(ts/1000), (int64(ts)%1000)*1000000)
|
||||||
|
|
||||||
@ -455,7 +454,7 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
err = amf0ParseErr("longstring.body", offset+n, err)
|
err = amf0ParseErr("longstring.body", offset+n, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val = string(b[n:n+length])
|
val = string(b[n : n+length])
|
||||||
n += length
|
n += length
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -465,4 +464,3 @@ func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ package flvio
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package format
|
package format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
|
"github.com/datarhei/joy4/format/aac"
|
||||||
|
"github.com/datarhei/joy4/format/flv"
|
||||||
"github.com/datarhei/joy4/format/mp4"
|
"github.com/datarhei/joy4/format/mp4"
|
||||||
"github.com/datarhei/joy4/format/ts"
|
|
||||||
"github.com/datarhei/joy4/format/rtmp"
|
"github.com/datarhei/joy4/format/rtmp"
|
||||||
"github.com/datarhei/joy4/format/rtsp"
|
"github.com/datarhei/joy4/format/rtsp"
|
||||||
"github.com/datarhei/joy4/format/flv"
|
"github.com/datarhei/joy4/format/ts"
|
||||||
"github.com/datarhei/joy4/format/aac"
|
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterAll() {
|
func RegisterAll() {
|
||||||
@ -18,4 +18,3 @@ func RegisterAll() {
|
|||||||
avutil.DefaultHandlers.Add(flv.Handler)
|
avutil.DefaultHandlers.Add(flv.Handler)
|
||||||
avutil.DefaultHandlers.Add(aac.Handler)
|
avutil.DefaultHandlers.Add(aac.Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package mp4
|
package mp4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
||||||
@ -13,7 +13,7 @@ func Handler(h *avutil.RegisterHandler) {
|
|||||||
|
|
||||||
h.Probe = func(b []byte) bool {
|
h.Probe = func(b []byte) bool {
|
||||||
switch string(b[4:8]) {
|
switch string(b[4:8]) {
|
||||||
case "moov","ftyp","free","mdat","moof":
|
case "moov", "ftyp", "free", "mdat", "moof":
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -29,4 +29,3 @@ func Handler(h *avutil.RegisterHandler) {
|
|||||||
|
|
||||||
h.CodecTypes = CodecTypes
|
h.CodecTypes = CodecTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ func (self AVC1Desc) Tag() Tag {
|
|||||||
return AVC1
|
return AVC1
|
||||||
}
|
}
|
||||||
|
|
||||||
const URL = Tag(0x75726c20)
|
const URL = Tag(0x75726c20)
|
||||||
|
|
||||||
func (self DataReferUrl) Tag() Tag {
|
func (self DataReferUrl) Tag() Tag {
|
||||||
return URL
|
return URL
|
||||||
@ -204,16 +204,16 @@ func (self SoundMediaInfo) Tag() Tag {
|
|||||||
const MDAT = Tag(0x6d646174)
|
const MDAT = Tag(0x6d646174)
|
||||||
|
|
||||||
type Movie struct {
|
type Movie struct {
|
||||||
Header *MovieHeader
|
Header *MovieHeader
|
||||||
MovieExtend *MovieExtend
|
MovieExtend *MovieExtend
|
||||||
Tracks []*Track
|
Tracks []*Track
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Movie) Marshal(b []byte) (n int) {
|
func (self Movie) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MOOV))
|
pio.PutU32BE(b[4:], uint32(MOOV))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -315,28 +315,28 @@ func (self Movie) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MovieHeader struct {
|
type MovieHeader struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
ModifyTime time.Time
|
ModifyTime time.Time
|
||||||
TimeScale int32
|
TimeScale int32
|
||||||
Duration int32
|
Duration int32
|
||||||
PreferredRate float64
|
PreferredRate float64
|
||||||
PreferredVolume float64
|
PreferredVolume float64
|
||||||
Matrix [9]int32
|
Matrix [9]int32
|
||||||
PreviewTime time.Time
|
PreviewTime time.Time
|
||||||
PreviewDuration time.Time
|
PreviewDuration time.Time
|
||||||
PosterTime time.Time
|
PosterTime time.Time
|
||||||
SelectionTime time.Time
|
SelectionTime time.Time
|
||||||
SelectionDuration time.Time
|
SelectionDuration time.Time
|
||||||
CurrentTime time.Time
|
CurrentTime time.Time
|
||||||
NextTrackId int32
|
NextTrackId int32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MovieHeader) Marshal(b []byte) (n int) {
|
func (self MovieHeader) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MVHD))
|
pio.PutU32BE(b[4:], uint32(MVHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -389,7 +389,7 @@ func (self MovieHeader) Len() (n int) {
|
|||||||
n += 4
|
n += 4
|
||||||
n += 2
|
n += 2
|
||||||
n += 10
|
n += 10
|
||||||
n += 4*len(self.Matrix[:])
|
n += 4 * len(self.Matrix[:])
|
||||||
n += 4
|
n += 4
|
||||||
n += 4
|
n += 4
|
||||||
n += 4
|
n += 4
|
||||||
@ -508,15 +508,15 @@ func (self MovieHeader) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Track struct {
|
type Track struct {
|
||||||
Header *TrackHeader
|
Header *TrackHeader
|
||||||
Media *Media
|
Media *Media
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Track) Marshal(b []byte) (n int) {
|
func (self Track) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TRAK))
|
pio.PutU32BE(b[4:], uint32(TRAK))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -576,7 +576,7 @@ func (self *Track) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -600,24 +600,24 @@ func (self Track) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackHeader struct {
|
type TrackHeader struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
ModifyTime time.Time
|
ModifyTime time.Time
|
||||||
TrackId int32
|
TrackId int32
|
||||||
Duration int32
|
Duration int32
|
||||||
Layer int16
|
Layer int16
|
||||||
AlternateGroup int16
|
AlternateGroup int16
|
||||||
Volume float64
|
Volume float64
|
||||||
Matrix [9]int32
|
Matrix [9]int32
|
||||||
TrackWidth float64
|
TrackWidth float64
|
||||||
TrackHeight float64
|
TrackHeight float64
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackHeader) Marshal(b []byte) (n int) {
|
func (self TrackHeader) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TKHD))
|
pio.PutU32BE(b[4:], uint32(TKHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -667,7 +667,7 @@ func (self TrackHeader) Len() (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
n += 2
|
n += 2
|
||||||
n += 2
|
n += 2
|
||||||
n += 4*len(self.Matrix[:])
|
n += 4 * len(self.Matrix[:])
|
||||||
n += 4
|
n += 4
|
||||||
n += 4
|
n += 4
|
||||||
return
|
return
|
||||||
@ -759,17 +759,17 @@ func (self TrackHeader) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HandlerRefer struct {
|
type HandlerRefer struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Type [4]byte
|
Type [4]byte
|
||||||
SubType [4]byte
|
SubType [4]byte
|
||||||
Name []byte
|
Name []byte
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self HandlerRefer) Marshal(b []byte) (n int) {
|
func (self HandlerRefer) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(HDLR))
|
pio.PutU32BE(b[4:], uint32(HDLR))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -831,16 +831,16 @@ func (self HandlerRefer) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Media struct {
|
type Media struct {
|
||||||
Header *MediaHeader
|
Header *MediaHeader
|
||||||
Handler *HandlerRefer
|
Handler *HandlerRefer
|
||||||
Info *MediaInfo
|
Info *MediaInfo
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Media) Marshal(b []byte) (n int) {
|
func (self Media) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MDIA))
|
pio.PutU32BE(b[4:], uint32(MDIA))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -915,7 +915,7 @@ func (self *Media) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -942,20 +942,20 @@ func (self Media) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MediaHeader struct {
|
type MediaHeader struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
ModifyTime time.Time
|
ModifyTime time.Time
|
||||||
TimeScale int32
|
TimeScale int32
|
||||||
Duration int32
|
Duration int32
|
||||||
Language int16
|
Language int16
|
||||||
Quality int16
|
Quality int16
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MediaHeader) Marshal(b []byte) (n int) {
|
func (self MediaHeader) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MDHD))
|
pio.PutU32BE(b[4:], uint32(MDHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1048,17 +1048,17 @@ func (self MediaHeader) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MediaInfo struct {
|
type MediaInfo struct {
|
||||||
Sound *SoundMediaInfo
|
Sound *SoundMediaInfo
|
||||||
Video *VideoMediaInfo
|
Video *VideoMediaInfo
|
||||||
Data *DataInfo
|
Data *DataInfo
|
||||||
Sample *SampleTable
|
Sample *SampleTable
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MediaInfo) Marshal(b []byte) (n int) {
|
func (self MediaInfo) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MINF))
|
pio.PutU32BE(b[4:], uint32(MINF))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1148,7 +1148,7 @@ func (self *MediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -1178,14 +1178,14 @@ func (self MediaInfo) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataInfo struct {
|
type DataInfo struct {
|
||||||
Refer *DataRefer
|
Refer *DataRefer
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DataInfo) Marshal(b []byte) (n int) {
|
func (self DataInfo) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(DINF))
|
pio.PutU32BE(b[4:], uint32(DINF))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1230,7 +1230,7 @@ func (self *DataInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -1251,15 +1251,15 @@ func (self DataInfo) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataRefer struct {
|
type DataRefer struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Url *DataReferUrl
|
Url *DataReferUrl
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DataRefer) Marshal(b []byte) (n int) {
|
func (self DataRefer) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(DREF))
|
pio.PutU32BE(b[4:], uint32(DREF))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1313,7 +1313,7 @@ func (self *DataRefer) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch tag {
|
switch tag {
|
||||||
case URL :
|
case URL:
|
||||||
{
|
{
|
||||||
atom := &DataReferUrl{}
|
atom := &DataReferUrl{}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
@ -1335,14 +1335,14 @@ func (self DataRefer) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataReferUrl struct {
|
type DataReferUrl struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DataReferUrl) Marshal(b []byte) (n int) {
|
func (self DataReferUrl) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(URL ))
|
pio.PutU32BE(b[4:], uint32(URL))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1381,15 +1381,15 @@ func (self DataReferUrl) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SoundMediaInfo struct {
|
type SoundMediaInfo struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Balance int16
|
Balance int16
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SoundMediaInfo) Marshal(b []byte) (n int) {
|
func (self SoundMediaInfo) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(SMHD))
|
pio.PutU32BE(b[4:], uint32(SMHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1440,16 +1440,16 @@ func (self SoundMediaInfo) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VideoMediaInfo struct {
|
type VideoMediaInfo struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
GraphicsMode int16
|
GraphicsMode int16
|
||||||
Opcolor [3]int16
|
Opcolor [3]int16
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self VideoMediaInfo) Marshal(b []byte) (n int) {
|
func (self VideoMediaInfo) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(VMHD))
|
pio.PutU32BE(b[4:], uint32(VMHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1471,7 +1471,7 @@ func (self VideoMediaInfo) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 2
|
n += 2
|
||||||
n += 2*len(self.Opcolor[:])
|
n += 2 * len(self.Opcolor[:])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *VideoMediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *VideoMediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -1510,19 +1510,19 @@ func (self VideoMediaInfo) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SampleTable struct {
|
type SampleTable struct {
|
||||||
SampleDesc *SampleDesc
|
SampleDesc *SampleDesc
|
||||||
TimeToSample *TimeToSample
|
TimeToSample *TimeToSample
|
||||||
CompositionOffset *CompositionOffset
|
CompositionOffset *CompositionOffset
|
||||||
SampleToChunk *SampleToChunk
|
SampleToChunk *SampleToChunk
|
||||||
SyncSample *SyncSample
|
SyncSample *SyncSample
|
||||||
ChunkOffset *ChunkOffset
|
ChunkOffset *ChunkOffset
|
||||||
SampleSize *SampleSize
|
SampleSize *SampleSize
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SampleTable) Marshal(b []byte) (n int) {
|
func (self SampleTable) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STBL))
|
pio.PutU32BE(b[4:], uint32(STBL))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1680,16 +1680,16 @@ func (self SampleTable) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SampleDesc struct {
|
type SampleDesc struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
AVC1Desc *AVC1Desc
|
AVC1Desc *AVC1Desc
|
||||||
MP4ADesc *MP4ADesc
|
MP4ADesc *MP4ADesc
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SampleDesc) Marshal(b []byte) (n int) {
|
func (self SampleDesc) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STSD))
|
pio.PutU32BE(b[4:], uint32(STSD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1773,7 +1773,7 @@ func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -1797,22 +1797,22 @@ func (self SampleDesc) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MP4ADesc struct {
|
type MP4ADesc struct {
|
||||||
DataRefIdx int16
|
DataRefIdx int16
|
||||||
Version int16
|
Version int16
|
||||||
RevisionLevel int16
|
RevisionLevel int16
|
||||||
Vendor int32
|
Vendor int32
|
||||||
NumberOfChannels int16
|
NumberOfChannels int16
|
||||||
SampleSize int16
|
SampleSize int16
|
||||||
CompressionId int16
|
CompressionId int16
|
||||||
SampleRate float64
|
SampleRate float64
|
||||||
Conf *ElemStreamDesc
|
Conf *ElemStreamDesc
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MP4ADesc) Marshal(b []byte) (n int) {
|
func (self MP4ADesc) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MP4A))
|
pio.PutU32BE(b[4:], uint32(MP4A))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1935,7 +1935,7 @@ func (self *MP4ADesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -1956,28 +1956,28 @@ func (self MP4ADesc) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AVC1Desc struct {
|
type AVC1Desc struct {
|
||||||
DataRefIdx int16
|
DataRefIdx int16
|
||||||
Version int16
|
Version int16
|
||||||
Revision int16
|
Revision int16
|
||||||
Vendor int32
|
Vendor int32
|
||||||
TemporalQuality int32
|
TemporalQuality int32
|
||||||
SpatialQuality int32
|
SpatialQuality int32
|
||||||
Width int16
|
Width int16
|
||||||
Height int16
|
Height int16
|
||||||
HorizontalResolution float64
|
HorizontalResolution float64
|
||||||
VorizontalResolution float64
|
VorizontalResolution float64
|
||||||
FrameCount int16
|
FrameCount int16
|
||||||
CompressorName [32]byte
|
CompressorName [32]byte
|
||||||
Depth int16
|
Depth int16
|
||||||
ColorTableId int16
|
ColorTableId int16
|
||||||
Conf *AVC1Conf
|
Conf *AVC1Conf
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self AVC1Desc) Marshal(b []byte) (n int) {
|
func (self AVC1Desc) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(AVC1))
|
pio.PutU32BE(b[4:], uint32(AVC1))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2154,7 +2154,7 @@ func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -2175,13 +2175,13 @@ func (self AVC1Desc) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AVC1Conf struct {
|
type AVC1Conf struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self AVC1Conf) Marshal(b []byte) (n int) {
|
func (self AVC1Conf) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(AVCC))
|
pio.PutU32BE(b[4:], uint32(AVCC))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2207,15 +2207,15 @@ func (self AVC1Conf) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TimeToSample struct {
|
type TimeToSample struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Entries []TimeToSampleEntry
|
Entries []TimeToSampleEntry
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TimeToSample) Marshal(b []byte) (n int) {
|
func (self TimeToSample) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STTS))
|
pio.PutU32BE(b[4:], uint32(STTS))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2237,7 +2237,7 @@ func (self TimeToSample) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 4
|
n += 4
|
||||||
n += LenTimeToSampleEntry*len(self.Entries)
|
n += LenTimeToSampleEntry * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *TimeToSample) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *TimeToSample) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -2274,8 +2274,8 @@ func (self TimeToSample) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TimeToSampleEntry struct {
|
type TimeToSampleEntry struct {
|
||||||
Count uint32
|
Count uint32
|
||||||
Duration uint32
|
Duration uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTimeToSampleEntry(b []byte) (self TimeToSampleEntry) {
|
func GetTimeToSampleEntry(b []byte) (self TimeToSampleEntry) {
|
||||||
@ -2291,15 +2291,15 @@ func PutTimeToSampleEntry(b []byte, self TimeToSampleEntry) {
|
|||||||
const LenTimeToSampleEntry = 8
|
const LenTimeToSampleEntry = 8
|
||||||
|
|
||||||
type SampleToChunk struct {
|
type SampleToChunk struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Entries []SampleToChunkEntry
|
Entries []SampleToChunkEntry
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SampleToChunk) Marshal(b []byte) (n int) {
|
func (self SampleToChunk) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STSC))
|
pio.PutU32BE(b[4:], uint32(STSC))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2321,7 +2321,7 @@ func (self SampleToChunk) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 4
|
n += 4
|
||||||
n += LenSampleToChunkEntry*len(self.Entries)
|
n += LenSampleToChunkEntry * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *SampleToChunk) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *SampleToChunk) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -2358,9 +2358,9 @@ func (self SampleToChunk) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SampleToChunkEntry struct {
|
type SampleToChunkEntry struct {
|
||||||
FirstChunk uint32
|
FirstChunk uint32
|
||||||
SamplesPerChunk uint32
|
SamplesPerChunk uint32
|
||||||
SampleDescId uint32
|
SampleDescId uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSampleToChunkEntry(b []byte) (self SampleToChunkEntry) {
|
func GetSampleToChunkEntry(b []byte) (self SampleToChunkEntry) {
|
||||||
@ -2378,15 +2378,15 @@ func PutSampleToChunkEntry(b []byte, self SampleToChunkEntry) {
|
|||||||
const LenSampleToChunkEntry = 12
|
const LenSampleToChunkEntry = 12
|
||||||
|
|
||||||
type CompositionOffset struct {
|
type CompositionOffset struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Entries []CompositionOffsetEntry
|
Entries []CompositionOffsetEntry
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self CompositionOffset) Marshal(b []byte) (n int) {
|
func (self CompositionOffset) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(CTTS))
|
pio.PutU32BE(b[4:], uint32(CTTS))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2408,7 +2408,7 @@ func (self CompositionOffset) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 4
|
n += 4
|
||||||
n += LenCompositionOffsetEntry*len(self.Entries)
|
n += LenCompositionOffsetEntry * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *CompositionOffset) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *CompositionOffset) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -2445,8 +2445,8 @@ func (self CompositionOffset) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CompositionOffsetEntry struct {
|
type CompositionOffsetEntry struct {
|
||||||
Count uint32
|
Count uint32
|
||||||
Offset uint32
|
Offset uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCompositionOffsetEntry(b []byte) (self CompositionOffsetEntry) {
|
func GetCompositionOffsetEntry(b []byte) (self CompositionOffsetEntry) {
|
||||||
@ -2462,15 +2462,15 @@ func PutCompositionOffsetEntry(b []byte, self CompositionOffsetEntry) {
|
|||||||
const LenCompositionOffsetEntry = 8
|
const LenCompositionOffsetEntry = 8
|
||||||
|
|
||||||
type SyncSample struct {
|
type SyncSample struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Entries []uint32
|
Entries []uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SyncSample) Marshal(b []byte) (n int) {
|
func (self SyncSample) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STSS))
|
pio.PutU32BE(b[4:], uint32(STSS))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2492,7 +2492,7 @@ func (self SyncSample) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 4
|
n += 4
|
||||||
n += 4*len(self.Entries)
|
n += 4 * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *SyncSample) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *SyncSample) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -2529,15 +2529,15 @@ func (self SyncSample) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ChunkOffset struct {
|
type ChunkOffset struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Entries []uint32
|
Entries []uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self ChunkOffset) Marshal(b []byte) (n int) {
|
func (self ChunkOffset) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STCO))
|
pio.PutU32BE(b[4:], uint32(STCO))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2559,7 +2559,7 @@ func (self ChunkOffset) Len() (n int) {
|
|||||||
n += 1
|
n += 1
|
||||||
n += 3
|
n += 3
|
||||||
n += 4
|
n += 4
|
||||||
n += 4*len(self.Entries)
|
n += 4 * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *ChunkOffset) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *ChunkOffset) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -2596,15 +2596,15 @@ func (self ChunkOffset) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MovieFrag struct {
|
type MovieFrag struct {
|
||||||
Header *MovieFragHeader
|
Header *MovieFragHeader
|
||||||
Tracks []*TrackFrag
|
Tracks []*TrackFrag
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MovieFrag) Marshal(b []byte) (n int) {
|
func (self MovieFrag) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MOOF))
|
pio.PutU32BE(b[4:], uint32(MOOF))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2664,7 +2664,7 @@ func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -2688,15 +2688,15 @@ func (self MovieFrag) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MovieFragHeader struct {
|
type MovieFragHeader struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Seqnum uint32
|
Seqnum uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MovieFragHeader) Marshal(b []byte) (n int) {
|
func (self MovieFragHeader) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MFHD))
|
pio.PutU32BE(b[4:], uint32(MFHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2744,16 +2744,16 @@ func (self MovieFragHeader) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackFrag struct {
|
type TrackFrag struct {
|
||||||
Header *TrackFragHeader
|
Header *TrackFragHeader
|
||||||
DecodeTime *TrackFragDecodeTime
|
DecodeTime *TrackFragDecodeTime
|
||||||
Run *TrackFragRun
|
Run *TrackFragRun
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackFrag) Marshal(b []byte) (n int) {
|
func (self TrackFrag) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TRAF))
|
pio.PutU32BE(b[4:], uint32(TRAF))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2828,7 +2828,7 @@ func (self *TrackFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -2855,14 +2855,14 @@ func (self TrackFrag) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MovieExtend struct {
|
type MovieExtend struct {
|
||||||
Tracks []*TrackExtend
|
Tracks []*TrackExtend
|
||||||
Unknowns []Atom
|
Unknowns []Atom
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self MovieExtend) Marshal(b []byte) (n int) {
|
func (self MovieExtend) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(MVEX))
|
pio.PutU32BE(b[4:], uint32(MVEX))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2907,7 +2907,7 @@ func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
|
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
|
||||||
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
|
||||||
err = parseErr("", n+offset, err)
|
err = parseErr("", n+offset, err)
|
||||||
return
|
return
|
||||||
@ -2928,19 +2928,19 @@ func (self MovieExtend) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackExtend struct {
|
type TrackExtend struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
TrackId uint32
|
TrackId uint32
|
||||||
DefaultSampleDescIdx uint32
|
DefaultSampleDescIdx uint32
|
||||||
DefaultSampleDuration uint32
|
DefaultSampleDuration uint32
|
||||||
DefaultSampleSize uint32
|
DefaultSampleSize uint32
|
||||||
DefaultSampleFlags uint32
|
DefaultSampleFlags uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackExtend) Marshal(b []byte) (n int) {
|
func (self TrackExtend) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TREX))
|
pio.PutU32BE(b[4:], uint32(TREX))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -3024,16 +3024,16 @@ func (self TrackExtend) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SampleSize struct {
|
type SampleSize struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
SampleSize uint32
|
SampleSize uint32
|
||||||
Entries []uint32
|
Entries []uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self SampleSize) Marshal(b []byte) (n int) {
|
func (self SampleSize) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(STSZ))
|
pio.PutU32BE(b[4:], uint32(STSZ))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -3064,7 +3064,7 @@ func (self SampleSize) Len() (n int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n += 4
|
n += 4
|
||||||
n += 4*len(self.Entries)
|
n += 4 * len(self.Entries)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (self *SampleSize) Unmarshal(b []byte, offset int) (n int, err error) {
|
func (self *SampleSize) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||||
@ -3110,17 +3110,17 @@ func (self SampleSize) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackFragRun struct {
|
type TrackFragRun struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
DataOffset uint32
|
DataOffset uint32
|
||||||
FirstSampleFlags uint32
|
FirstSampleFlags uint32
|
||||||
Entries []TrackFragRunEntry
|
Entries []TrackFragRunEntry
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackFragRun) Marshal(b []byte) (n int) {
|
func (self TrackFragRun) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TRUN))
|
pio.PutU32BE(b[4:], uint32(TRUN))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -3280,10 +3280,10 @@ func (self TrackFragRun) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackFragRunEntry struct {
|
type TrackFragRunEntry struct {
|
||||||
Duration uint32
|
Duration uint32
|
||||||
Size uint32
|
Size uint32
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Cts uint32
|
Cts uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTrackFragRunEntry(b []byte) (self TrackFragRunEntry) {
|
func GetTrackFragRunEntry(b []byte) (self TrackFragRunEntry) {
|
||||||
@ -3303,19 +3303,19 @@ func PutTrackFragRunEntry(b []byte, self TrackFragRunEntry) {
|
|||||||
const LenTrackFragRunEntry = 16
|
const LenTrackFragRunEntry = 16
|
||||||
|
|
||||||
type TrackFragHeader struct {
|
type TrackFragHeader struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
BaseDataOffset uint64
|
BaseDataOffset uint64
|
||||||
StsdId uint32
|
StsdId uint32
|
||||||
DefaultDuration uint32
|
DefaultDuration uint32
|
||||||
DefaultSize uint32
|
DefaultSize uint32
|
||||||
DefaultFlags uint32
|
DefaultFlags uint32
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackFragHeader) Marshal(b []byte) (n int) {
|
func (self TrackFragHeader) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TFHD))
|
pio.PutU32BE(b[4:], uint32(TFHD))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -3459,15 +3459,15 @@ func (self TrackFragHeader) Children() (r []Atom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackFragDecodeTime struct {
|
type TrackFragDecodeTime struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Time time.Time
|
Time time.Time
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self TrackFragDecodeTime) Marshal(b []byte) (n int) {
|
func (self TrackFragDecodeTime) Marshal(b []byte) (n int) {
|
||||||
pio.PutU32BE(b[4:], uint32(TFDT))
|
pio.PutU32BE(b[4:], uint32(TFDT))
|
||||||
n += self.marshal(b[8:])+8
|
n += self.marshal(b[8:]) + 8
|
||||||
pio.PutU32BE(b[0:], uint32(n))
|
pio.PutU32BE(b[0:], uint32(n))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
|
||||||
"go/printer"
|
"go/printer"
|
||||||
|
"go/token"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getexprs(e ast.Expr) string {
|
func getexprs(e ast.Expr) string {
|
||||||
@ -37,7 +36,7 @@ func genatomdecl(origfn *ast.FuncDecl, origname, origtag string) (decls []ast.De
|
|||||||
if typ == "_unknowns" {
|
if typ == "_unknowns" {
|
||||||
fieldslist.List = append(fieldslist.List, &ast.Field{
|
fieldslist.List = append(fieldslist.List, &ast.Field{
|
||||||
Names: []*ast.Ident{ast.NewIdent("Unknowns")},
|
Names: []*ast.Ident{ast.NewIdent("Unknowns")},
|
||||||
Type: ast.NewIdent("[]Atom"),
|
Type: ast.NewIdent("[]Atom"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@ -67,24 +66,24 @@ func genatomdecl(origfn *ast.FuncDecl, origname, origtag string) (decls []ast.De
|
|||||||
case "bytesleft":
|
case "bytesleft":
|
||||||
typ = "[]byte"
|
typ = "[]byte"
|
||||||
case "bytes":
|
case "bytes":
|
||||||
typ = "["+name2+"]byte"
|
typ = "[" + name2 + "]byte"
|
||||||
case "uint24":
|
case "uint24":
|
||||||
typ = "uint32"
|
typ = "uint32"
|
||||||
case "time64", "time32":
|
case "time64", "time32":
|
||||||
typ = "time.Time"
|
typ = "time.Time"
|
||||||
case "atom":
|
case "atom":
|
||||||
typ = "*"+name2
|
typ = "*" + name2
|
||||||
case "atoms":
|
case "atoms":
|
||||||
typ = "[]*"+name2
|
typ = "[]*" + name2
|
||||||
case "slice":
|
case "slice":
|
||||||
typ = "[]"+name2
|
typ = "[]" + name2
|
||||||
case "array":
|
case "array":
|
||||||
typ = "["+len3+"]"+name2
|
typ = "[" + len3 + "]" + name2
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldslist.List = append(fieldslist.List, &ast.Field{
|
fieldslist.List = append(fieldslist.List, &ast.Field{
|
||||||
Names: []*ast.Ident{ast.NewIdent(name)},
|
Names: []*ast.Ident{ast.NewIdent(name)},
|
||||||
Type: ast.NewIdent(typ),
|
Type: ast.NewIdent(typ),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +134,7 @@ func typegetlen(typ string) (n int) {
|
|||||||
func typegetlens(typ string) string {
|
func typegetlens(typ string) string {
|
||||||
n := typegetlen(typ)
|
n := typegetlen(typ)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return "Len"+typ
|
return "Len" + typ
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprint(n)
|
return fmt.Sprint(n)
|
||||||
}
|
}
|
||||||
@ -187,7 +186,7 @@ func typegetputfn(typ string) (fn string) {
|
|||||||
case "fixed16":
|
case "fixed16":
|
||||||
fn = "PutFixed16"
|
fn = "PutFixed16"
|
||||||
default:
|
default:
|
||||||
fn = "Put"+typ
|
fn = "Put" + typ
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -218,7 +217,7 @@ func typegetgetfn(typ string) (fn string) {
|
|||||||
case "fixed16":
|
case "fixed16":
|
||||||
fn = "GetFixed16"
|
fn = "GetFixed16"
|
||||||
default:
|
default:
|
||||||
fn = "Get"+typ
|
fn = "Get" + typ
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -237,14 +236,14 @@ func addn(n int) (stmts []ast.Stmt) {
|
|||||||
return addns(fmt.Sprint(n))
|
return addns(fmt.Sprint(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func simplecall(fun string, args... string) *ast.ExprStmt {
|
func simplecall(fun string, args ...string) *ast.ExprStmt {
|
||||||
_args := []ast.Expr{}
|
_args := []ast.Expr{}
|
||||||
for _, s := range args {
|
for _, s := range args {
|
||||||
_args = append(_args, ast.NewIdent(s))
|
_args = append(_args, ast.NewIdent(s))
|
||||||
}
|
}
|
||||||
return &ast.ExprStmt{
|
return &ast.ExprStmt{
|
||||||
X: &ast.CallExpr{
|
X: &ast.CallExpr{
|
||||||
Fun: ast.NewIdent(fun),
|
Fun: ast.NewIdent(fun),
|
||||||
Args: _args,
|
Args: _args,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -283,7 +282,7 @@ func newdecl(origname, name string, params, res []*ast.Field, stmts []ast.Stmt)
|
|||||||
List: []*ast.Field{
|
List: []*ast.Field{
|
||||||
&ast.Field{
|
&ast.Field{
|
||||||
Names: []*ast.Ident{ast.NewIdent("self")},
|
Names: []*ast.Ident{ast.NewIdent("self")},
|
||||||
Type: ast.NewIdent(origname),
|
Type: ast.NewIdent(origname),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -319,7 +318,7 @@ func getstructputgetlenfn(origfn *ast.FuncDecl, origname string) (decls []ast.De
|
|||||||
getstmts = append(getstmts, &ast.ReturnStmt{})
|
getstmts = append(getstmts, &ast.ReturnStmt{})
|
||||||
|
|
||||||
decls = append(decls, &ast.FuncDecl{
|
decls = append(decls, &ast.FuncDecl{
|
||||||
Name: ast.NewIdent("Get"+origname),
|
Name: ast.NewIdent("Get" + origname),
|
||||||
Type: &ast.FuncType{
|
Type: &ast.FuncType{
|
||||||
Params: &ast.FieldList{
|
Params: &ast.FieldList{
|
||||||
List: []*ast.Field{
|
List: []*ast.Field{
|
||||||
@ -336,7 +335,7 @@ func getstructputgetlenfn(origfn *ast.FuncDecl, origname string) (decls []ast.De
|
|||||||
})
|
})
|
||||||
|
|
||||||
decls = append(decls, &ast.FuncDecl{
|
decls = append(decls, &ast.FuncDecl{
|
||||||
Name: ast.NewIdent("Put"+origname),
|
Name: ast.NewIdent("Put" + origname),
|
||||||
Type: &ast.FuncType{
|
Type: &ast.FuncType{
|
||||||
Params: &ast.FieldList{
|
Params: &ast.FieldList{
|
||||||
List: []*ast.Field{
|
List: []*ast.Field{
|
||||||
@ -352,7 +351,7 @@ func getstructputgetlenfn(origfn *ast.FuncDecl, origname string) (decls []ast.De
|
|||||||
Tok: token.CONST,
|
Tok: token.CONST,
|
||||||
Specs: []ast.Spec{
|
Specs: []ast.Spec{
|
||||||
&ast.ValueSpec{
|
&ast.ValueSpec{
|
||||||
Names: []*ast.Ident{ast.NewIdent("Len"+origname)},
|
Names: []*ast.Ident{ast.NewIdent("Len" + origname)},
|
||||||
Values: []ast.Expr{ast.NewIdent(fmt.Sprint(totlen))},
|
Values: []ast.Expr{ast.NewIdent(fmt.Sprint(totlen))},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -371,7 +370,7 @@ func cc4decls(name string) (decls []ast.Decl) {
|
|||||||
},
|
},
|
||||||
Values: []ast.Expr{
|
Values: []ast.Expr{
|
||||||
&ast.CallExpr{
|
&ast.CallExpr{
|
||||||
Fun: ast.NewIdent("Tag"),
|
Fun: ast.NewIdent("Tag"),
|
||||||
Args: []ast.Expr{&ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("0x%x", []byte(name))}},
|
Args: []ast.Expr{&ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("0x%x", []byte(name))}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -431,7 +430,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
|
|
||||||
callmarshal := func(name string) (stmts []ast.Stmt) {
|
callmarshal := func(name string) (stmts []ast.Stmt) {
|
||||||
callexpr := &ast.CallExpr{
|
callexpr := &ast.CallExpr{
|
||||||
Fun: ast.NewIdent(name+".Marshal"),
|
Fun: ast.NewIdent(name + ".Marshal"),
|
||||||
Args: []ast.Expr{ast.NewIdent("b[n:]")},
|
Args: []ast.Expr{ast.NewIdent("b[n:]")},
|
||||||
}
|
}
|
||||||
assign := &ast.AssignStmt{
|
assign := &ast.AssignStmt{
|
||||||
@ -446,7 +445,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
callputstruct := func(typ, name string) (stmts []ast.Stmt) {
|
callputstruct := func(typ, name string) (stmts []ast.Stmt) {
|
||||||
stmts = append(stmts, &ast.ExprStmt{
|
stmts = append(stmts, &ast.ExprStmt{
|
||||||
X: &ast.CallExpr{
|
X: &ast.CallExpr{
|
||||||
Fun: ast.NewIdent(typegetputfn(typ)),
|
Fun: ast.NewIdent(typegetputfn(typ)),
|
||||||
Args: []ast.Expr{ast.NewIdent("b[n:]"), ast.NewIdent(name)},
|
Args: []ast.Expr{ast.NewIdent("b[n:]"), ast.NewIdent(name)},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -459,7 +458,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
calllenstruct := func(typ, name string) (stmts []ast.Stmt) {
|
calllenstruct := func(typ, name string) (stmts []ast.Stmt) {
|
||||||
inc := typegetlens(typ)+"*len("+name+")"
|
inc := typegetlens(typ) + "*len(" + name + ")"
|
||||||
stmts = append(stmts, &ast.AssignStmt{
|
stmts = append(stmts, &ast.AssignStmt{
|
||||||
Tok: token.ADD_ASSIGN,
|
Tok: token.ADD_ASSIGN,
|
||||||
Lhs: []ast.Expr{ast.NewIdent("n")},
|
Lhs: []ast.Expr{ast.NewIdent("n")},
|
||||||
@ -470,7 +469,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
|
|
||||||
calllen := func(name string) (stmts []ast.Stmt) {
|
calllen := func(name string) (stmts []ast.Stmt) {
|
||||||
callexpr := &ast.CallExpr{
|
callexpr := &ast.CallExpr{
|
||||||
Fun: ast.NewIdent(name+".Len"),
|
Fun: ast.NewIdent(name + ".Len"),
|
||||||
Args: []ast.Expr{},
|
Args: []ast.Expr{},
|
||||||
}
|
}
|
||||||
assign := &ast.AssignStmt{
|
assign := &ast.AssignStmt{
|
||||||
@ -484,13 +483,13 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
|
|
||||||
foreach := func(name, field string, block []ast.Stmt) (stmts []ast.Stmt) {
|
foreach := func(name, field string, block []ast.Stmt) (stmts []ast.Stmt) {
|
||||||
rangestmt := &ast.RangeStmt{
|
rangestmt := &ast.RangeStmt{
|
||||||
Key: ast.NewIdent("_"),
|
Key: ast.NewIdent("_"),
|
||||||
Value: ast.NewIdent(name),
|
Value: ast.NewIdent(name),
|
||||||
Body: &ast.BlockStmt{
|
Body: &ast.BlockStmt{
|
||||||
List: block,
|
List: block,
|
||||||
},
|
},
|
||||||
Tok: token.DEFINE,
|
Tok: token.DEFINE,
|
||||||
X: ast.NewIdent(field),
|
X: ast.NewIdent(field),
|
||||||
}
|
}
|
||||||
stmts = append(stmts, rangestmt)
|
stmts = append(stmts, rangestmt)
|
||||||
return
|
return
|
||||||
@ -511,7 +510,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
List: block,
|
List: block,
|
||||||
},
|
},
|
||||||
Tok: token.DEFINE,
|
Tok: token.DEFINE,
|
||||||
X: ast.NewIdent(field),
|
X: ast.NewIdent(field),
|
||||||
}
|
}
|
||||||
stmts = append(stmts, rangestmt)
|
stmts = append(stmts, rangestmt)
|
||||||
return
|
return
|
||||||
@ -574,7 +573,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
unmarshalatom := func(typ, init string) (stmts []ast.Stmt) {
|
unmarshalatom := func(typ, init string) (stmts []ast.Stmt) {
|
||||||
return []ast.Stmt{
|
return []ast.Stmt{
|
||||||
&ast.AssignStmt{Tok: token.DEFINE,
|
&ast.AssignStmt{Tok: token.DEFINE,
|
||||||
Lhs: []ast.Expr{ast.NewIdent("atom")}, Rhs: []ast.Expr{ast.NewIdent("&"+typ+"{"+init+"}")},
|
Lhs: []ast.Expr{ast.NewIdent("atom")}, Rhs: []ast.Expr{ast.NewIdent("&" + typ + "{" + init + "}")},
|
||||||
},
|
},
|
||||||
&ast.IfStmt{
|
&ast.IfStmt{
|
||||||
Init: &ast.AssignStmt{
|
Init: &ast.AssignStmt{
|
||||||
@ -591,10 +590,10 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
unmrashalatoms := func() (stmts []ast.Stmt) {
|
unmrashalatoms := func() (stmts []ast.Stmt) {
|
||||||
blocks := []ast.Stmt{}
|
blocks := []ast.Stmt{}
|
||||||
|
|
||||||
blocks = append(blocks, &ast.AssignStmt{ Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("tag")},
|
blocks = append(blocks, &ast.AssignStmt{Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("tag")},
|
||||||
Rhs: []ast.Expr{ast.NewIdent("Tag(pio.U32BE(b[n+4:]))")},
|
Rhs: []ast.Expr{ast.NewIdent("Tag(pio.U32BE(b[n+4:]))")},
|
||||||
})
|
})
|
||||||
blocks = append(blocks, &ast.AssignStmt{ Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("size")},
|
blocks = append(blocks, &ast.AssignStmt{Tok: token.DEFINE, Lhs: []ast.Expr{ast.NewIdent("size")},
|
||||||
Rhs: []ast.Expr{ast.NewIdent("int(pio.U32BE(b[n:]))")},
|
Rhs: []ast.Expr{ast.NewIdent("int(pio.U32BE(b[n:]))")},
|
||||||
})
|
})
|
||||||
blocks = append(blocks, &ast.IfStmt{
|
blocks = append(blocks, &ast.IfStmt{
|
||||||
@ -614,7 +613,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, atom := range atomarrnames {
|
for i, atom := range atomarrnames {
|
||||||
selfatom := "self."+atom
|
selfatom := "self." + atom
|
||||||
cases = append(cases, &ast.CaseClause{
|
cases = append(cases, &ast.CaseClause{
|
||||||
List: []ast.Expr{ast.NewIdent(strings.ToUpper(struct2tag(atomarrtypes[i])))},
|
List: []ast.Expr{ast.NewIdent(strings.ToUpper(struct2tag(atomarrtypes[i])))},
|
||||||
Body: []ast.Stmt{&ast.BlockStmt{
|
Body: []ast.Stmt{&ast.BlockStmt{
|
||||||
@ -635,7 +634,7 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
blocks = append(blocks, &ast.SwitchStmt{
|
blocks = append(blocks, &ast.SwitchStmt{
|
||||||
Tag: ast.NewIdent("tag"),
|
Tag: ast.NewIdent("tag"),
|
||||||
Body: &ast.BlockStmt{List: cases},
|
Body: &ast.BlockStmt{List: cases},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -659,9 +658,9 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
ifnotnil := func(name string, block []ast.Stmt) (stmts []ast.Stmt) {
|
ifnotnil := func(name string, block []ast.Stmt) (stmts []ast.Stmt) {
|
||||||
stmts = append(stmts, &ast.IfStmt{
|
stmts = append(stmts, &ast.IfStmt{
|
||||||
Cond: &ast.BinaryExpr{
|
Cond: &ast.BinaryExpr{
|
||||||
X: ast.NewIdent(name),
|
X: ast.NewIdent(name),
|
||||||
Op: token.NEQ,
|
Op: token.NEQ,
|
||||||
Y: ast.NewIdent("nil"),
|
Y: ast.NewIdent("nil"),
|
||||||
},
|
},
|
||||||
Body: &ast.BlockStmt{List: block},
|
Body: &ast.BlockStmt{List: block},
|
||||||
})
|
})
|
||||||
@ -693,9 +692,9 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
checkcurlen := func(inc, debug string) (stmts []ast.Stmt) {
|
checkcurlen := func(inc, debug string) (stmts []ast.Stmt) {
|
||||||
stmts = append(stmts, &ast.IfStmt{
|
stmts = append(stmts, &ast.IfStmt{
|
||||||
Cond: &ast.BinaryExpr{
|
Cond: &ast.BinaryExpr{
|
||||||
X: ast.NewIdent("len(b)"),
|
X: ast.NewIdent("len(b)"),
|
||||||
Op: token.LSS,
|
Op: token.LSS,
|
||||||
Y: ast.NewIdent("n+"+inc),
|
Y: ast.NewIdent("n+" + inc),
|
||||||
},
|
},
|
||||||
Body: &ast.BlockStmt{List: parseerrreturn(debug)},
|
Body: &ast.BlockStmt{List: parseerrreturn(debug)},
|
||||||
})
|
})
|
||||||
@ -710,20 +709,20 @@ func getatommarshalfn(origfn *ast.FuncDecl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkstructlendo := func(typ, name, debug string,
|
checkstructlendo := func(typ, name, debug string,
|
||||||
foreach func(string,[]ast.Stmt)[]ast.Stmt,
|
foreach func(string, []ast.Stmt) []ast.Stmt,
|
||||||
) (stmts []ast.Stmt) {
|
) (stmts []ast.Stmt) {
|
||||||
inc := typegetlens(typ)+"*len("+name+")"
|
inc := typegetlens(typ) + "*len(" + name + ")"
|
||||||
stmts = append(stmts, checkcurlen(inc, debug)...)
|
stmts = append(stmts, checkcurlen(inc, debug)...)
|
||||||
stmts = append(stmts, foreach(name, append(
|
stmts = append(stmts, foreach(name, append(
|
||||||
[]ast.Stmt{
|
[]ast.Stmt{
|
||||||
&ast.AssignStmt{
|
&ast.AssignStmt{
|
||||||
Tok: token.ASSIGN,
|
Tok: token.ASSIGN,
|
||||||
Lhs: []ast.Expr{
|
Lhs: []ast.Expr{
|
||||||
ast.NewIdent(name+"[i]"),
|
ast.NewIdent(name + "[i]"),
|
||||||
},
|
},
|
||||||
Rhs: []ast.Expr{
|
Rhs: []ast.Expr{
|
||||||
&ast.CallExpr{
|
&ast.CallExpr{
|
||||||
Fun: ast.NewIdent(typegetgetfn(typ)),
|
Fun: ast.NewIdent(typegetgetfn(typ)),
|
||||||
Args: []ast.Expr{ast.NewIdent("b[n:]")},
|
Args: []ast.Expr{ast.NewIdent("b[n:]")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1054,4 +1053,3 @@ func main() {
|
|||||||
genatoms(os.Args[2], os.Args[3])
|
genatoms(os.Args[2], os.Args[3])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,4 +434,3 @@ func tfdt_TrackFragDecodeTime() {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
|
|
||||||
package mp4io
|
package mp4io
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
|
||||||
"os"
|
|
||||||
"io"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ParseError struct {
|
type ParseError struct {
|
||||||
Debug string
|
Debug string
|
||||||
Offset int
|
Offset int
|
||||||
prev *ParseError
|
prev *ParseError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ParseError) Error() string {
|
func (self *ParseError) Error() string {
|
||||||
@ -22,7 +21,7 @@ func (self *ParseError) Error() string {
|
|||||||
for p := self; p != nil; p = p.prev {
|
for p := self; p != nil; p = p.prev {
|
||||||
s = append(s, fmt.Sprintf("%s:%d", p.Debug, p.Offset))
|
s = append(s, fmt.Sprintf("%s:%d", p.Debug, p.Offset))
|
||||||
}
|
}
|
||||||
return "mp4io: parse error: "+strings.Join(s, ",")
|
return "mp4io: parse error: " + strings.Join(s, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseErr(debug string, offset int, prev error) (err error) {
|
func parseErr(debug string, offset int, prev error) (err error) {
|
||||||
@ -33,37 +32,37 @@ func parseErr(debug string, offset int, prev error) (err error) {
|
|||||||
func GetTime32(b []byte) (t time.Time) {
|
func GetTime32(b []byte) (t time.Time) {
|
||||||
sec := pio.U32BE(b)
|
sec := pio.U32BE(b)
|
||||||
t = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
t = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
t = t.Add(time.Second*time.Duration(sec))
|
t = t.Add(time.Second * time.Duration(sec))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutTime32(b []byte, t time.Time) {
|
func PutTime32(b []byte, t time.Time) {
|
||||||
dur := t.Sub(time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC))
|
dur := t.Sub(time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC))
|
||||||
sec := uint32(dur/time.Second)
|
sec := uint32(dur / time.Second)
|
||||||
pio.PutU32BE(b, sec)
|
pio.PutU32BE(b, sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTime64(b []byte) (t time.Time) {
|
func GetTime64(b []byte) (t time.Time) {
|
||||||
sec := pio.U64BE(b)
|
sec := pio.U64BE(b)
|
||||||
t = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
t = time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
t = t.Add(time.Second*time.Duration(sec))
|
t = t.Add(time.Second * time.Duration(sec))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutTime64(b []byte, t time.Time) {
|
func PutTime64(b []byte, t time.Time) {
|
||||||
dur := t.Sub(time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC))
|
dur := t.Sub(time.Date(1904, time.January, 1, 0, 0, 0, 0, time.UTC))
|
||||||
sec := uint64(dur/time.Second)
|
sec := uint64(dur / time.Second)
|
||||||
pio.PutU64BE(b, sec)
|
pio.PutU64BE(b, sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutFixed16(b []byte, f float64) {
|
func PutFixed16(b []byte, f float64) {
|
||||||
intpart, fracpart := math.Modf(f)
|
intpart, fracpart := math.Modf(f)
|
||||||
b[0] = uint8(intpart)
|
b[0] = uint8(intpart)
|
||||||
b[1] = uint8(fracpart*256.0)
|
b[1] = uint8(fracpart * 256.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFixed16(b []byte) float64 {
|
func GetFixed16(b []byte) float64 {
|
||||||
return float64(b[0])+float64(b[1])/256.0
|
return float64(b[0]) + float64(b[1])/256.0
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutFixed32(b []byte, f float64) {
|
func PutFixed32(b []byte, f float64) {
|
||||||
@ -73,7 +72,7 @@ func PutFixed32(b []byte, f float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetFixed32(b []byte) float64 {
|
func GetFixed32(b []byte) float64 {
|
||||||
return float64(pio.U16BE(b[0:2]))+float64(pio.U16BE(b[2:4]))/65536.0
|
return float64(pio.U16BE(b[0:2])) + float64(pio.U16BE(b[2:4]))/65536.0
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tag uint32
|
type Tag uint32
|
||||||
@ -89,21 +88,21 @@ func (self Tag) String() string {
|
|||||||
return string(b[:])
|
return string(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
type Atom interface{
|
type Atom interface {
|
||||||
Pos() (int,int)
|
Pos() (int, int)
|
||||||
Tag() Tag
|
Tag() Tag
|
||||||
Marshal([]byte) int
|
Marshal([]byte) int
|
||||||
Unmarshal([]byte, int) (int,error)
|
Unmarshal([]byte, int) (int, error)
|
||||||
Len() int
|
Len() int
|
||||||
Children() []Atom
|
Children() []Atom
|
||||||
}
|
}
|
||||||
|
|
||||||
type AtomPos struct {
|
type AtomPos struct {
|
||||||
Offset int
|
Offset int
|
||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self AtomPos) Pos() (int,int) {
|
func (self AtomPos) Pos() (int, int) {
|
||||||
return self.Offset, self.Size
|
return self.Offset, self.Size
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +189,7 @@ const (
|
|||||||
|
|
||||||
type ElemStreamDesc struct {
|
type ElemStreamDesc struct {
|
||||||
DecConfig []byte
|
DecConfig []byte
|
||||||
TrackId uint16
|
TrackId uint16
|
||||||
AtomPos
|
AtomPos
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,10 +199,10 @@ func (self ElemStreamDesc) Children() []Atom {
|
|||||||
|
|
||||||
func (self ElemStreamDesc) fillLength(b []byte, length int) (n int) {
|
func (self ElemStreamDesc) fillLength(b []byte, length int) (n int) {
|
||||||
for i := 3; i > 0; i-- {
|
for i := 3; i > 0; i-- {
|
||||||
b[n] = uint8(length>>uint(7*i))&0x7f|0x80
|
b[n] = uint8(length>>uint(7*i))&0x7f | 0x80
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
b[n] = uint8(length&0x7f)
|
b[n] = uint8(length & 0x7f)
|
||||||
n++
|
n++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -220,7 +219,7 @@ func (self ElemStreamDesc) fillDescHdr(b []byte, tag uint8, datalen int) (n int)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self ElemStreamDesc) lenESDescHdr() (n int) {
|
func (self ElemStreamDesc) lenESDescHdr() (n int) {
|
||||||
return self.lenDescHdr()+3
|
return self.lenDescHdr() + 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self ElemStreamDesc) fillESDescHdr(b []byte, datalen int) (n int) {
|
func (self ElemStreamDesc) fillESDescHdr(b []byte, datalen int) (n int) {
|
||||||
@ -233,7 +232,7 @@ func (self ElemStreamDesc) fillESDescHdr(b []byte, datalen int) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self ElemStreamDesc) lenDecConfigDescHdr() (n int) {
|
func (self ElemStreamDesc) lenDecConfigDescHdr() (n int) {
|
||||||
return self.lenDescHdr()+2+3+4+4+self.lenDescHdr()
|
return self.lenDescHdr() + 2 + 3 + 4 + 4 + self.lenDescHdr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self ElemStreamDesc) fillDecConfigDescHdr(b []byte, datalen int) (n int) {
|
func (self ElemStreamDesc) fillDecConfigDescHdr(b []byte, datalen int) (n int) {
|
||||||
@ -256,7 +255,7 @@ func (self ElemStreamDesc) fillDecConfigDescHdr(b []byte, datalen int) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self ElemStreamDesc) Len() (n int) {
|
func (self ElemStreamDesc) Len() (n int) {
|
||||||
return 8+4+self.lenESDescHdr()+self.lenDecConfigDescHdr()+len(self.DecConfig)+self.lenDescHdr()+1
|
return 8 + 4 + self.lenESDescHdr() + self.lenDecConfigDescHdr() + len(self.DecConfig) + self.lenDescHdr() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version(4)
|
// Version(4)
|
||||||
@ -328,7 +327,7 @@ func (self *ElemStreamDesc) parseDesc(b []byte, offset int) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MP4DecConfigDescrTag:
|
case MP4DecConfigDescrTag:
|
||||||
const size = 2+3+4+4
|
const size = 2 + 3 + 4 + 4
|
||||||
if len(b) < n+size {
|
if len(b) < n+size {
|
||||||
err = parseErr("MP4DecSpecificDescrTag", offset+n, err)
|
err = parseErr("MP4DecSpecificDescrTag", offset+n, err)
|
||||||
return
|
return
|
||||||
@ -353,7 +352,7 @@ func (self *ElemStreamDesc) parseLength(b []byte, offset int) (n int, length int
|
|||||||
}
|
}
|
||||||
c := b[n]
|
c := b[n]
|
||||||
n++
|
n++
|
||||||
length = (length<<7)|(int(c)&0x7f)
|
length = (length << 7) | (int(c) & 0x7f)
|
||||||
if c&0x80 == 0 {
|
if c&0x80 == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -500,4 +499,3 @@ func (self *Track) GetElemStreamDesc() (esds *ElemStreamDesc) {
|
|||||||
esds, _ = atom.(*ElemStreamDesc)
|
esds, _ = atom.(*ElemStreamDesc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
package mp4
|
package mp4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/codec/aacparser"
|
"github.com/datarhei/joy4/codec/aacparser"
|
||||||
"github.com/datarhei/joy4/codec/h264parser"
|
"github.com/datarhei/joy4/codec/h264parser"
|
||||||
"github.com/datarhei/joy4/format/mp4/mp4io"
|
"github.com/datarhei/joy4/format/mp4/mp4io"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"io"
|
"io"
|
||||||
"bufio"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
w io.WriteSeeker
|
w io.WriteSeeker
|
||||||
bufw *bufio.Writer
|
bufw *bufio.Writer
|
||||||
wpos int64
|
wpos int64
|
||||||
streams []*Stream
|
streams []*Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMuxer(w io.WriteSeeker) *Muxer {
|
func NewMuxer(w io.WriteSeeker) *Muxer {
|
||||||
return &Muxer{
|
return &Muxer{
|
||||||
w: w,
|
w: w,
|
||||||
bufw: bufio.NewWriterSize(w, pio.RecommendBufioSize),
|
bufw: bufio.NewWriterSize(w, pio.RecommendBufioSize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func (self *Muxer) newStream(codec av.CodecData) (err error) {
|
|||||||
|
|
||||||
stream.trackAtom = &mp4io.Track{
|
stream.trackAtom = &mp4io.Track{
|
||||||
Header: &mp4io.TrackHeader{
|
Header: &mp4io.TrackHeader{
|
||||||
TrackId: int32(len(self.streams)+1),
|
TrackId: int32(len(self.streams) + 1),
|
||||||
Flags: 0x0003, // Track enabled | Track in movie
|
Flags: 0x0003, // Track enabled | Track in movie
|
||||||
Duration: 0, // fill later
|
Duration: 0, // fill later
|
||||||
Matrix: [9]int32{0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000},
|
Matrix: [9]int32{0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000},
|
||||||
@ -109,7 +109,7 @@ func (self *Stream) fillTrackAtom() (err error) {
|
|||||||
Conf: &mp4io.AVC1Conf{Data: codec.AVCDecoderConfRecordBytes()},
|
Conf: &mp4io.AVC1Conf{Data: codec.AVCDecoderConfRecordBytes()},
|
||||||
}
|
}
|
||||||
self.trackAtom.Media.Handler = &mp4io.HandlerRefer{
|
self.trackAtom.Media.Handler = &mp4io.HandlerRefer{
|
||||||
SubType: [4]byte{'v','i','d','e'},
|
SubType: [4]byte{'v', 'i', 'd', 'e'},
|
||||||
Name: []byte("Video Media Handler"),
|
Name: []byte("Video Media Handler"),
|
||||||
}
|
}
|
||||||
self.trackAtom.Media.Info.Video = &mp4io.VideoMediaInfo{
|
self.trackAtom.Media.Info.Video = &mp4io.VideoMediaInfo{
|
||||||
@ -132,7 +132,7 @@ func (self *Stream) fillTrackAtom() (err error) {
|
|||||||
self.trackAtom.Header.Volume = 1
|
self.trackAtom.Header.Volume = 1
|
||||||
self.trackAtom.Header.AlternateGroup = 1
|
self.trackAtom.Header.AlternateGroup = 1
|
||||||
self.trackAtom.Media.Handler = &mp4io.HandlerRefer{
|
self.trackAtom.Media.Handler = &mp4io.HandlerRefer{
|
||||||
SubType: [4]byte{'s','o','u','n'},
|
SubType: [4]byte{'s', 'o', 'u', 'n'},
|
||||||
Name: []byte("Sound Handler"),
|
Name: []byte("Sound Handler"),
|
||||||
}
|
}
|
||||||
self.trackAtom.Media.Info.Sound = &mp4io.SoundMediaInfo{}
|
self.trackAtom.Media.Info.Sound = &mp4io.SoundMediaInfo{}
|
||||||
|
@ -17,7 +17,7 @@ type Stream struct {
|
|||||||
timeScale int64
|
timeScale int64
|
||||||
duration int64
|
duration int64
|
||||||
|
|
||||||
muxer *Muxer
|
muxer *Muxer
|
||||||
demuxer *Demuxer
|
demuxer *Demuxer
|
||||||
|
|
||||||
sample *mp4io.SampleTable
|
sample *mp4io.SampleTable
|
||||||
@ -42,17 +42,17 @@ type Stream struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func timeToTs(tm time.Duration, timeScale int64) int64 {
|
func timeToTs(tm time.Duration, timeScale int64) int64 {
|
||||||
return int64(tm*time.Duration(timeScale) / time.Second)
|
return int64(tm * time.Duration(timeScale) / time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tsToTime(ts int64, timeScale int64) time.Duration {
|
func tsToTime(ts int64, timeScale int64) time.Duration {
|
||||||
return time.Duration(ts)*time.Second / time.Duration(timeScale)
|
return time.Duration(ts) * time.Second / time.Duration(timeScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Stream) timeToTs(tm time.Duration) int64 {
|
func (self *Stream) timeToTs(tm time.Duration) int64 {
|
||||||
return int64(tm*time.Duration(self.timeScale) / time.Second)
|
return int64(tm * time.Duration(self.timeScale) / time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Stream) tsToTime(ts int64) time.Duration {
|
func (self *Stream) tsToTime(ts int64) time.Duration {
|
||||||
return time.Duration(ts)*time.Second / time.Duration(self.timeScale)
|
return time.Duration(ts) * time.Second / time.Duration(self.timeScale)
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
"github.com/datarhei/joy4/codec"
|
"github.com/datarhei/joy4/codec"
|
||||||
"github.com/datarhei/joy4/codec/aacparser"
|
"github.com/datarhei/joy4/codec/aacparser"
|
||||||
"github.com/datarhei/joy4/codec/h264parser"
|
"github.com/datarhei/joy4/codec/h264parser"
|
||||||
"github.com/datarhei/joy4/format/rtsp/sdp"
|
"github.com/datarhei/joy4/format/rtsp/sdp"
|
||||||
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
@ -31,7 +31,7 @@ var DebugRtsp = false
|
|||||||
var SkipErrRtpBlock = false
|
var SkipErrRtpBlock = false
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stageDescribeDone = iota+1
|
stageDescribeDone = iota + 1
|
||||||
stageSetupDone
|
stageSetupDone
|
||||||
stageWaitCodecData
|
stageWaitCodecData
|
||||||
stageCodecDataDone
|
stageCodecDataDone
|
||||||
@ -39,7 +39,7 @@ const (
|
|||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
DebugRtsp bool
|
DebugRtsp bool
|
||||||
DebugRtp bool
|
DebugRtp bool
|
||||||
Headers []string
|
Headers []string
|
||||||
|
|
||||||
SkipErrRtpBlock bool
|
SkipErrRtpBlock bool
|
||||||
@ -52,20 +52,20 @@ type Client struct {
|
|||||||
|
|
||||||
stage int
|
stage int
|
||||||
|
|
||||||
setupIdx []int
|
setupIdx []int
|
||||||
setupMap []int
|
setupMap []int
|
||||||
|
|
||||||
authHeaders func(method string) []string
|
authHeaders func(method string) []string
|
||||||
|
|
||||||
url *url.URL
|
url *url.URL
|
||||||
conn *connWithTimeout
|
conn *connWithTimeout
|
||||||
brconn *bufio.Reader
|
brconn *bufio.Reader
|
||||||
requestUri string
|
requestUri string
|
||||||
cseq uint
|
cseq uint
|
||||||
streams []*Stream
|
streams []*Stream
|
||||||
streamsintf []av.CodecData
|
streamsintf []av.CodecData
|
||||||
session string
|
session string
|
||||||
body io.Reader
|
body io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
@ -76,7 +76,7 @@ type Request struct {
|
|||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
StatusCode int
|
StatusCode int
|
||||||
Headers textproto.MIMEHeader
|
Headers textproto.MIMEHeader
|
||||||
ContentLength int
|
ContentLength int
|
||||||
Body []byte
|
Body []byte
|
||||||
|
|
||||||
@ -105,12 +105,12 @@ func DialTimeout(uri string, timeout time.Duration) (self *Client, err error) {
|
|||||||
connt := &connWithTimeout{Conn: conn}
|
connt := &connWithTimeout{Conn: conn}
|
||||||
|
|
||||||
self = &Client{
|
self = &Client{
|
||||||
conn: connt,
|
conn: connt,
|
||||||
brconn: bufio.NewReaderSize(connt, 256),
|
brconn: bufio.NewReaderSize(connt, 256),
|
||||||
url: URL,
|
url: URL,
|
||||||
requestUri: u2.String(),
|
requestUri: u2.String(),
|
||||||
DebugRtp: DebugRtp,
|
DebugRtp: DebugRtp,
|
||||||
DebugRtsp: DebugRtsp,
|
DebugRtsp: DebugRtsp,
|
||||||
SkipErrRtpBlock: SkipErrRtpBlock,
|
SkipErrRtpBlock: SkipErrRtpBlock,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -121,7 +121,7 @@ func Dial(uri string) (self *Client, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Client) allCodecDataReady() bool {
|
func (self *Client) allCodecDataReady() bool {
|
||||||
for _, si:= range self.setupIdx {
|
for _, si := range self.setupIdx {
|
||||||
stream := self.streams[si]
|
stream := self.streams[si]
|
||||||
if stream.CodecData == nil {
|
if stream.CodecData == nil {
|
||||||
return false
|
return false
|
||||||
@ -268,7 +268,7 @@ func (self *Client) parseBlockHeader(h []byte) (length int, no int, valid bool)
|
|||||||
timestamp -= stream.firsttimestamp
|
timestamp -= stream.firsttimestamp
|
||||||
if timestamp < stream.timestamp {
|
if timestamp < stream.timestamp {
|
||||||
return
|
return
|
||||||
} else if timestamp - stream.timestamp > uint32(stream.timeScale()*60*60) {
|
} else if timestamp-stream.timestamp > uint32(stream.timeScale()*60*60) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,7 +373,7 @@ func (self *Client) handle401(res *Response) (err error) {
|
|||||||
|
|
||||||
func (self *Client) findRTSP() (block []byte, data []byte, err error) {
|
func (self *Client) findRTSP() (block []byte, data []byte, err error) {
|
||||||
const (
|
const (
|
||||||
R = iota+1
|
R = iota + 1
|
||||||
T
|
T
|
||||||
S
|
S
|
||||||
Header
|
Header
|
||||||
@ -383,7 +383,7 @@ func (self *Client) findRTSP() (block []byte, data []byte, err error) {
|
|||||||
peek := _peek[0:0]
|
peek := _peek[0:0]
|
||||||
stat := 0
|
stat := 0
|
||||||
|
|
||||||
for i := 0;; i++ {
|
for i := 0; ; i++ {
|
||||||
var b byte
|
var b byte
|
||||||
if b, err = self.brconn.ReadByte(); err != nil {
|
if b, err = self.brconn.ReadByte(); err != nil {
|
||||||
return
|
return
|
||||||
@ -434,7 +434,7 @@ func (self *Client) findRTSP() (block []byte, data []byte, err error) {
|
|||||||
fmt.Println("rtsp: dollar at", i, len(peek))
|
fmt.Println("rtsp: dollar at", i, len(peek))
|
||||||
}
|
}
|
||||||
if blocklen, _, ok := self.parseBlockHeader(peek); ok {
|
if blocklen, _, ok := self.parseBlockHeader(peek); ok {
|
||||||
left := blocklen+4-len(peek)
|
left := blocklen + 4 - len(peek)
|
||||||
block = append(peek, make([]byte, left)...)
|
block = append(peek, make([]byte, left)...)
|
||||||
if _, err = io.ReadFull(self.brconn, block[len(peek):]); err != nil {
|
if _, err = io.ReadFull(self.brconn, block[len(peek):]); err != nil {
|
||||||
return
|
return
|
||||||
@ -451,7 +451,7 @@ func (self *Client) findRTSP() (block []byte, data []byte, err error) {
|
|||||||
|
|
||||||
func (self *Client) readLFLF() (block []byte, data []byte, err error) {
|
func (self *Client) readLFLF() (block []byte, data []byte, err error) {
|
||||||
const (
|
const (
|
||||||
LF = iota+1
|
LF = iota + 1
|
||||||
LFLF
|
LFLF
|
||||||
)
|
)
|
||||||
peek := []byte{}
|
peek := []byte{}
|
||||||
@ -471,7 +471,7 @@ func (self *Client) readLFLF() (block []byte, data []byte, err error) {
|
|||||||
stat = LF
|
stat = LF
|
||||||
lpos = pos
|
lpos = pos
|
||||||
} else if stat == LF {
|
} else if stat == LF {
|
||||||
if pos - lpos <= 2 {
|
if pos-lpos <= 2 {
|
||||||
stat = LFLF
|
stat = LFLF
|
||||||
} else {
|
} else {
|
||||||
lpos = pos
|
lpos = pos
|
||||||
@ -485,9 +485,9 @@ func (self *Client) readLFLF() (block []byte, data []byte, err error) {
|
|||||||
if stat == LFLF {
|
if stat == LFLF {
|
||||||
data = peek
|
data = peek
|
||||||
return
|
return
|
||||||
} else if dollarpos != -1 && dollarpos - pos >= 12 {
|
} else if dollarpos != -1 && dollarpos-pos >= 12 {
|
||||||
hdrlen := dollarpos-pos
|
hdrlen := dollarpos - pos
|
||||||
start := len(peek)-hdrlen
|
start := len(peek) - hdrlen
|
||||||
if blocklen, _, ok := self.parseBlockHeader(peek[start:]); ok {
|
if blocklen, _, ok := self.parseBlockHeader(peek[start:]); ok {
|
||||||
block = append(peek[start:], make([]byte, blocklen+4-hdrlen)...)
|
block = append(peek[start:], make([]byte, blocklen+4-hdrlen)...)
|
||||||
if _, err = io.ReadFull(self.brconn, block[hdrlen:]); err != nil {
|
if _, err = io.ReadFull(self.brconn, block[hdrlen:]); err != nil {
|
||||||
@ -810,7 +810,7 @@ func (self *Stream) handleH264Payload(timestamp uint32, packet []byte) (err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
naluType := packet[0]&0x1f
|
naluType := packet[0] & 0x1f
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Table 7-1 – NAL unit type codes
|
Table 7-1 – NAL unit type codes
|
||||||
@ -830,16 +830,16 @@ func (self *Stream) handleH264Payload(timestamp uint32, packet []byte) (err erro
|
|||||||
*/
|
*/
|
||||||
switch {
|
switch {
|
||||||
case naluType >= 1 && naluType <= 5:
|
case naluType >= 1 && naluType <= 5:
|
||||||
if naluType == 5 {
|
if naluType == 5 {
|
||||||
self.pkt.IsKeyFrame = true
|
self.pkt.IsKeyFrame = true
|
||||||
}
|
}
|
||||||
self.gotpkt = true
|
self.gotpkt = true
|
||||||
// raw nalu to avcc
|
// raw nalu to avcc
|
||||||
b := make([]byte, 4+len(packet))
|
b := make([]byte, 4+len(packet))
|
||||||
pio.PutU32BE(b[0:4], uint32(len(packet)))
|
pio.PutU32BE(b[0:4], uint32(len(packet)))
|
||||||
copy(b[4:], packet)
|
copy(b[4:], packet)
|
||||||
self.pkt.Data = b
|
self.pkt.Data = b
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
|
|
||||||
case naluType == 7: // sps
|
case naluType == 7: // sps
|
||||||
if self.client != nil && self.client.DebugRtp {
|
if self.client != nil && self.client.DebugRtp {
|
||||||
@ -940,30 +940,30 @@ func (self *Stream) handleH264Payload(timestamp uint32, packet []byte) (err erro
|
|||||||
|
|
||||||
case naluType == 24: // STAP-A
|
case naluType == 24: // STAP-A
|
||||||
/*
|
/*
|
||||||
0 1 2 3
|
0 1 2 3
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| RTP Header |
|
| RTP Header |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|STAP-A NAL HDR | NALU 1 Size | NALU 1 HDR |
|
|STAP-A NAL HDR | NALU 1 Size | NALU 1 HDR |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| NALU 1 Data |
|
| NALU 1 Data |
|
||||||
: :
|
: :
|
||||||
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| | NALU 2 Size | NALU 2 HDR |
|
| | NALU 2 Size | NALU 2 HDR |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| NALU 2 Data |
|
| NALU 2 Data |
|
||||||
: :
|
: :
|
||||||
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| :...OPTIONAL RTP padding |
|
| :...OPTIONAL RTP padding |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
Figure 7. An example of an RTP packet including an STAP-A
|
Figure 7. An example of an RTP packet including an STAP-A
|
||||||
containing two single-time aggregation units
|
containing two single-time aggregation units
|
||||||
*/
|
*/
|
||||||
packet = packet[1:]
|
packet = packet[1:]
|
||||||
for len(packet) >= 2 {
|
for len(packet) >= 2 {
|
||||||
size := int(packet[0])<<8|int(packet[1])
|
size := int(packet[0])<<8 | int(packet[1])
|
||||||
if size+2 > len(packet) {
|
if size+2 > len(packet) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1141,7 +1141,7 @@ func (self *Client) handleBlock(block []byte) (pkt av.Packet, ok bool, err error
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := blockno/2
|
i := blockno / 2
|
||||||
if i >= len(self.streams) {
|
if i >= len(self.streams) {
|
||||||
err = fmt.Errorf("rtsp: block no=%d invalid", blockno)
|
err = fmt.Errorf("rtsp: block no=%d invalid", blockno)
|
||||||
return
|
return
|
||||||
@ -1158,11 +1158,11 @@ func (self *Client) handleBlock(block []byte) (pkt av.Packet, ok bool, err error
|
|||||||
|
|
||||||
if stream.gotpkt {
|
if stream.gotpkt {
|
||||||
/*
|
/*
|
||||||
TODO: sync AV by rtcp NTP timestamp
|
TODO: sync AV by rtcp NTP timestamp
|
||||||
TODO: handle timestamp overflow
|
TODO: handle timestamp overflow
|
||||||
https://tools.ietf.org/html/rfc3550
|
https://tools.ietf.org/html/rfc3550
|
||||||
A receiver can then synchronize presentation of the audio and video packets by relating
|
A receiver can then synchronize presentation of the audio and video packets by relating
|
||||||
their RTP timestamps using the timestamp pairs in RTCP SR packets.
|
their RTP timestamps using the timestamp pairs in RTCP SR packets.
|
||||||
*/
|
*/
|
||||||
if stream.firsttimestamp == 0 {
|
if stream.firsttimestamp == 0 {
|
||||||
stream.firsttimestamp = stream.timestamp
|
stream.firsttimestamp = stream.timestamp
|
||||||
@ -1171,10 +1171,10 @@ func (self *Client) handleBlock(block []byte) (pkt av.Packet, ok bool, err error
|
|||||||
|
|
||||||
ok = true
|
ok = true
|
||||||
pkt = stream.pkt
|
pkt = stream.pkt
|
||||||
pkt.Time = time.Duration(stream.timestamp)*time.Second / time.Duration(stream.timeScale())
|
pkt.Time = time.Duration(stream.timestamp) * time.Second / time.Duration(stream.timeScale())
|
||||||
pkt.Idx = int8(self.setupMap[i])
|
pkt.Idx = int8(self.setupMap[i])
|
||||||
|
|
||||||
if pkt.Time < stream.lasttime || pkt.Time - stream.lasttime > time.Minute*30 {
|
if pkt.Time < stream.lasttime || pkt.Time-stream.lasttime > time.Minute*30 {
|
||||||
err = fmt.Errorf("rtp: time invalid stream#%d time=%v lasttime=%v", pkt.Idx, pkt.Time, stream.lasttime)
|
err = fmt.Errorf("rtp: time invalid stream#%d time=%v lasttime=%v", pkt.Idx, pkt.Time, stream.lasttime)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1236,4 +1236,3 @@ func Handler(h *avutil.RegisterHandler) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ type Stream struct {
|
|||||||
spsChanged bool
|
spsChanged bool
|
||||||
ppsChanged bool
|
ppsChanged bool
|
||||||
|
|
||||||
gotpkt bool
|
gotpkt bool
|
||||||
pkt av.Packet
|
pkt av.Packet
|
||||||
timestamp uint32
|
timestamp uint32
|
||||||
firsttimestamp uint32
|
firsttimestamp uint32
|
||||||
|
|
||||||
lasttime time.Duration
|
lasttime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,13 @@ package ts
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/format/ts/tsio"
|
|
||||||
"github.com/datarhei/joy4/codec/aacparser"
|
"github.com/datarhei/joy4/codec/aacparser"
|
||||||
"github.com/datarhei/joy4/codec/h264parser"
|
"github.com/datarhei/joy4/codec/h264parser"
|
||||||
|
"github.com/datarhei/joy4/format/ts/tsio"
|
||||||
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Demuxer struct {
|
type Demuxer struct {
|
||||||
@ -28,7 +28,7 @@ type Demuxer struct {
|
|||||||
func NewDemuxer(r io.Reader) *Demuxer {
|
func NewDemuxer(r io.Reader) *Demuxer {
|
||||||
return &Demuxer{
|
return &Demuxer{
|
||||||
tshdr: make([]byte, 188),
|
tshdr: make([]byte, 188),
|
||||||
r: bufio.NewReaderSize(r, pio.RecommendBufioSize),
|
r: bufio.NewReaderSize(r, pio.RecommendBufioSize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ func (self *Demuxer) initPMT(payload []byte) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.pmt = &tsio.PMT{}
|
self.pmt = &tsio.PMT{}
|
||||||
if _, err = self.pmt.Unmarshal(payload[psihdrlen:psihdrlen+datalen]); err != nil {
|
if _, err = self.pmt.Unmarshal(payload[psihdrlen : psihdrlen+datalen]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ func (self *Demuxer) readTSPacket() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.pat = &tsio.PAT{}
|
self.pat = &tsio.PAT{}
|
||||||
if _, err = self.pat.Unmarshal(payload[psihdrlen:psihdrlen+datalen]); err != nil {
|
if _, err = self.pat.Unmarshal(payload[psihdrlen : psihdrlen+datalen]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,13 +192,13 @@ func (self *Stream) addPacket(payload []byte, timedelta time.Duration) {
|
|||||||
|
|
||||||
demuxer := self.demuxer
|
demuxer := self.demuxer
|
||||||
pkt := av.Packet{
|
pkt := av.Packet{
|
||||||
Idx: int8(self.idx),
|
Idx: int8(self.idx),
|
||||||
IsKeyFrame: self.iskeyframe,
|
IsKeyFrame: self.iskeyframe,
|
||||||
Time: dts+timedelta,
|
Time: dts + timedelta,
|
||||||
Data: payload,
|
Data: payload,
|
||||||
}
|
}
|
||||||
if pts != dts {
|
if pts != dts {
|
||||||
pkt.CompositionTime = pts-dts
|
pkt.CompositionTime = pts - dts
|
||||||
}
|
}
|
||||||
demuxer.pkts = append(demuxer.pkts, pkt)
|
demuxer.pkts = append(demuxer.pkts, pkt)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package ts
|
package ts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/av/avutil"
|
"github.com/datarhei/joy4/av/avutil"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Handler(h *avutil.RegisterHandler) {
|
func Handler(h *avutil.RegisterHandler) {
|
||||||
@ -23,4 +23,3 @@ func Handler(h *avutil.RegisterHandler) {
|
|||||||
|
|
||||||
h.CodecTypes = CodecTypes
|
h.CodecTypes = CodecTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package ts
|
package ts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
"github.com/datarhei/joy4/av"
|
"github.com/datarhei/joy4/av"
|
||||||
"github.com/datarhei/joy4/format/ts/tsio"
|
"github.com/datarhei/joy4/format/ts/tsio"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Stream struct {
|
type Stream struct {
|
||||||
@ -12,16 +12,15 @@ type Stream struct {
|
|||||||
demuxer *Demuxer
|
demuxer *Demuxer
|
||||||
muxer *Muxer
|
muxer *Muxer
|
||||||
|
|
||||||
pid uint16
|
pid uint16
|
||||||
streamId uint8
|
streamId uint8
|
||||||
streamType uint8
|
streamType uint8
|
||||||
|
|
||||||
tsw *tsio.TSWriter
|
tsw *tsio.TSWriter
|
||||||
idx int
|
idx int
|
||||||
|
|
||||||
iskeyframe bool
|
iskeyframe bool
|
||||||
pts, dts time.Duration
|
pts, dts time.Duration
|
||||||
data []byte
|
data []byte
|
||||||
datalen int
|
datalen int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,4 +52,3 @@ func calcCRC32(crc uint32, data []byte) uint32 {
|
|||||||
}
|
}
|
||||||
return crc
|
return crc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
|
|
||||||
package tsio
|
package tsio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/datarhei/joy4/utils/bits/pio"
|
"github.com/datarhei/joy4/utils/bits/pio"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -48,7 +47,7 @@ type PAT struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self PAT) Len() (n int) {
|
func (self PAT) Len() (n int) {
|
||||||
return len(self.Entries)*4
|
return len(self.Entries) * 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self PAT) Marshal(b []byte) (n int) {
|
func (self PAT) Marshal(b []byte) (n int) {
|
||||||
@ -73,10 +72,10 @@ func (self *PAT) Unmarshal(b []byte) (n int, err error) {
|
|||||||
entry.ProgramNumber = pio.U16BE(b[n:])
|
entry.ProgramNumber = pio.U16BE(b[n:])
|
||||||
n += 2
|
n += 2
|
||||||
if entry.ProgramNumber == 0 {
|
if entry.ProgramNumber == 0 {
|
||||||
entry.NetworkPID = pio.U16BE(b[n:])&0x1fff
|
entry.NetworkPID = pio.U16BE(b[n:]) & 0x1fff
|
||||||
n += 2
|
n += 2
|
||||||
} else {
|
} else {
|
||||||
entry.ProgramMapPID = pio.U16BE(b[n:])&0x1fff
|
entry.ProgramMapPID = pio.U16BE(b[n:]) & 0x1fff
|
||||||
n += 2
|
n += 2
|
||||||
}
|
}
|
||||||
self.Entries = append(self.Entries, entry)
|
self.Entries = append(self.Entries, entry)
|
||||||
@ -117,7 +116,7 @@ func (self PMT) Len() (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
for _, desc := range self.ProgramDescriptors {
|
for _, desc := range self.ProgramDescriptors {
|
||||||
n += 2+len(desc.Data)
|
n += 2 + len(desc.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, info := range self.ElementaryStreamInfos {
|
for _, info := range self.ElementaryStreamInfos {
|
||||||
@ -133,7 +132,7 @@ func (self PMT) Len() (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
for _, desc := range info.Descriptors {
|
for _, desc := range info.Descriptors {
|
||||||
n += 2+len(desc.Data)
|
n += 2 + len(desc.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +161,7 @@ func (self PMT) Marshal(b []byte) (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
pos := n
|
pos := n
|
||||||
n += self.fillDescs(b[n:], self.ProgramDescriptors)
|
n += self.fillDescs(b[n:], self.ProgramDescriptors)
|
||||||
desclen := n-pos
|
desclen := n - pos
|
||||||
pio.PutU16BE(b[hold:], uint16(desclen)|0xf<<12)
|
pio.PutU16BE(b[hold:], uint16(desclen)|0xf<<12)
|
||||||
|
|
||||||
for _, info := range self.ElementaryStreamInfos {
|
for _, info := range self.ElementaryStreamInfos {
|
||||||
@ -178,7 +177,7 @@ func (self PMT) Marshal(b []byte) (n int) {
|
|||||||
n += 2
|
n += 2
|
||||||
pos := n
|
pos := n
|
||||||
n += self.fillDescs(b[n:], info.Descriptors)
|
n += self.fillDescs(b[n:], info.Descriptors)
|
||||||
desclen := n-pos
|
desclen := n - pos
|
||||||
pio.PutU16BE(b[hold:], uint16(desclen)|0x3c<<10)
|
pio.PutU16BE(b[hold:], uint16(desclen)|0x3c<<10)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,13 +218,13 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
// 111(3)
|
// 111(3)
|
||||||
// PCRPID(13)
|
// PCRPID(13)
|
||||||
self.PCRPID = pio.U16BE(b[0:2])&0x1fff
|
self.PCRPID = pio.U16BE(b[0:2]) & 0x1fff
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
// Reserved(4)=0xf
|
// Reserved(4)=0xf
|
||||||
// Reserved(2)=0x0
|
// Reserved(2)=0x0
|
||||||
// Program info length(10)
|
// Program info length(10)
|
||||||
desclen := int(pio.U16BE(b[2:4])&0x3ff)
|
desclen := int(pio.U16BE(b[2:4]) & 0x3ff)
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
if desclen > 0 {
|
if desclen > 0 {
|
||||||
@ -233,7 +232,7 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) {
|
|||||||
err = ErrParsePMT
|
err = ErrParsePMT
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if self.ProgramDescriptors, err = self.parseDescs(b[n:n+desclen]); err != nil {
|
if self.ProgramDescriptors, err = self.parseDescs(b[n : n+desclen]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n += desclen
|
n += desclen
|
||||||
@ -251,12 +250,12 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
// Reserved(3)
|
// Reserved(3)
|
||||||
// Elementary PID(13)
|
// Elementary PID(13)
|
||||||
info.ElementaryPID = pio.U16BE(b[n:])&0x1fff
|
info.ElementaryPID = pio.U16BE(b[n:]) & 0x1fff
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
// Reserved(6)
|
// Reserved(6)
|
||||||
// ES Info length(10)
|
// ES Info length(10)
|
||||||
desclen := int(pio.U16BE(b[n:])&0x3ff)
|
desclen := int(pio.U16BE(b[n:]) & 0x3ff)
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
if desclen > 0 {
|
if desclen > 0 {
|
||||||
@ -264,7 +263,7 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) {
|
|||||||
err = ErrParsePMT
|
err = ErrParsePMT
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if info.Descriptors, err = self.parseDescs(b[n:n+desclen]); err != nil {
|
if info.Descriptors, err = self.parseDescs(b[n : n+desclen]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n += desclen
|
n += desclen
|
||||||
@ -345,7 +344,7 @@ func FillPSI(h []byte, tableid uint8, tableext uint16, datalen int) (n int) {
|
|||||||
n++
|
n++
|
||||||
|
|
||||||
// section_syntax_indicator(1)=1,private_bit(1)=0,reserved(2)=3,unused(2)=0,section_length(10)
|
// section_syntax_indicator(1)=1,private_bit(1)=0,reserved(2)=3,unused(2)=0,section_length(10)
|
||||||
pio.PutU16BE(h[n:], uint16(0xa<<12 | 2+3+4+datalen))
|
pio.PutU16BE(h[n:], uint16(0xa<<12|2+3+4+datalen))
|
||||||
n += 2
|
n += 2
|
||||||
|
|
||||||
// Table ID extension(16)
|
// Table ID extension(16)
|
||||||
@ -375,7 +374,7 @@ func FillPSI(h []byte, tableid uint8, tableext uint16, datalen int) (n int) {
|
|||||||
|
|
||||||
func TimeToPCR(tm time.Duration) (pcr uint64) {
|
func TimeToPCR(tm time.Duration) (pcr uint64) {
|
||||||
// base(33)+resverd(6)+ext(9)
|
// base(33)+resverd(6)+ext(9)
|
||||||
ts := uint64(tm*PCR_HZ/time.Second)
|
ts := uint64(tm * PCR_HZ / time.Second)
|
||||||
base := ts / 300
|
base := ts / 300
|
||||||
ext := ts % 300
|
ext := ts % 300
|
||||||
pcr = base<<15 | 0x3f<<9 | ext
|
pcr = base<<15 | 0x3f<<9 | ext
|
||||||
@ -386,12 +385,12 @@ func PCRToTime(pcr uint64) (tm time.Duration) {
|
|||||||
base := pcr >> 15
|
base := pcr >> 15
|
||||||
ext := pcr & 0x1ff
|
ext := pcr & 0x1ff
|
||||||
ts := base*300 + ext
|
ts := base*300 + ext
|
||||||
tm = time.Duration(ts)*time.Second/time.Duration(PCR_HZ)
|
tm = time.Duration(ts) * time.Second / time.Duration(PCR_HZ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TimeToTs(tm time.Duration) (v uint64) {
|
func TimeToTs(tm time.Duration) (v uint64) {
|
||||||
ts := uint64(tm*PTS_HZ/time.Second)
|
ts := uint64(tm * PTS_HZ / time.Second)
|
||||||
// 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1
|
// 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1
|
||||||
v = ((ts>>30)&0x7)<<33 | ((ts>>15)&0x7fff)<<17 | (ts&0x7fff)<<1 | 0x100010001
|
v = ((ts>>30)&0x7)<<33 | ((ts>>15)&0x7fff)<<17 | (ts&0x7fff)<<1 | 0x100010001
|
||||||
return
|
return
|
||||||
@ -399,8 +398,8 @@ func TimeToTs(tm time.Duration) (v uint64) {
|
|||||||
|
|
||||||
func TsToTime(v uint64) (tm time.Duration) {
|
func TsToTime(v uint64) (tm time.Duration) {
|
||||||
// 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1
|
// 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1
|
||||||
ts := (((v>>33)&0x7)<<30) | (((v>>17)&0x7fff) << 15) | ((v>>1)&0x7fff)
|
ts := (((v >> 33) & 0x7) << 30) | (((v >> 17) & 0x7fff) << 15) | ((v >> 1) & 0x7fff)
|
||||||
tm = time.Duration(ts)*time.Second/time.Duration(PTS_HZ)
|
tm = time.Duration(ts) * time.Second / time.Duration(PTS_HZ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,11 +416,11 @@ func ParsePESHeader(h []byte) (hdrlen int, streamid uint8, datalen int, pts, dts
|
|||||||
streamid = h[3]
|
streamid = h[3]
|
||||||
|
|
||||||
flags := h[7]
|
flags := h[7]
|
||||||
hdrlen = int(h[8])+9
|
hdrlen = int(h[8]) + 9
|
||||||
|
|
||||||
datalen = int(pio.U16BE(h[4:6]))
|
datalen = int(pio.U16BE(h[4:6]))
|
||||||
if datalen > 0 {
|
if datalen > 0 {
|
||||||
datalen -= int(h[8])+3
|
datalen -= int(h[8]) + 3
|
||||||
}
|
}
|
||||||
|
|
||||||
const PTS = 1 << 7
|
const PTS = 1 << 7
|
||||||
@ -479,7 +478,7 @@ func FillPESHeader(h []byte, streamid uint8, datalen int, pts, dts time.Duration
|
|||||||
}
|
}
|
||||||
pio.PutU16BE(h[4:6], pktlen)
|
pio.PutU16BE(h[4:6], pktlen)
|
||||||
|
|
||||||
h[6] = 2<<6|1 // resverd(6,2)=2,original_or_copy(0,1)=1
|
h[6] = 2<<6 | 1 // resverd(6,2)=2,original_or_copy(0,1)=1
|
||||||
h[7] = flags
|
h[7] = flags
|
||||||
h[8] = uint8(n)
|
h[8] = uint8(n)
|
||||||
|
|
||||||
@ -499,9 +498,9 @@ func FillPESHeader(h []byte, streamid uint8, datalen int, pts, dts time.Duration
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TSWriter struct {
|
type TSWriter struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
ContinuityCounter uint
|
ContinuityCounter uint
|
||||||
tshdr []byte
|
tshdr []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTSWriter(pid uint16) *TSWriter {
|
func NewTSWriter(pid uint16) *TSWriter {
|
||||||
@ -521,21 +520,21 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio
|
|||||||
writepos := 0
|
writepos := 0
|
||||||
|
|
||||||
for writepos < datavlen {
|
for writepos < datavlen {
|
||||||
self.tshdr[1] = self.tshdr[1]&0x1f
|
self.tshdr[1] = self.tshdr[1] & 0x1f
|
||||||
self.tshdr[3] = byte(self.ContinuityCounter)&0xf|0x30
|
self.tshdr[3] = byte(self.ContinuityCounter)&0xf | 0x30
|
||||||
self.tshdr[5] = 0 // flags
|
self.tshdr[5] = 0 // flags
|
||||||
hdrlen := 6
|
hdrlen := 6
|
||||||
self.ContinuityCounter++
|
self.ContinuityCounter++
|
||||||
|
|
||||||
if writepos == 0 {
|
if writepos == 0 {
|
||||||
self.tshdr[1] = 0x40|self.tshdr[1] // Payload Unit Start Indicator
|
self.tshdr[1] = 0x40 | self.tshdr[1] // Payload Unit Start Indicator
|
||||||
if pcr != 0 {
|
if pcr != 0 {
|
||||||
hdrlen += 6
|
hdrlen += 6
|
||||||
self.tshdr[5] = 0x10|self.tshdr[5] // PCR flag (Discontinuity indicator 0x80)
|
self.tshdr[5] = 0x10 | self.tshdr[5] // PCR flag (Discontinuity indicator 0x80)
|
||||||
pio.PutU48BE(self.tshdr[6:12], TimeToPCR(pcr))
|
pio.PutU48BE(self.tshdr[6:12], TimeToPCR(pcr))
|
||||||
}
|
}
|
||||||
if sync {
|
if sync {
|
||||||
self.tshdr[5] = 0x40|self.tshdr[5] // Random Access indicator
|
self.tshdr[5] = 0x40 | self.tshdr[5] // Random Access indicator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +550,7 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio
|
|||||||
}
|
}
|
||||||
n := pio.VecSliceTo(datav, writev, writepos, end)
|
n := pio.VecSliceTo(datav, writev, writepos, end)
|
||||||
|
|
||||||
self.tshdr[4] = byte(hdrlen)-5 // length
|
self.tshdr[4] = byte(hdrlen) - 5 // length
|
||||||
if _, err = w.Write(self.tshdr[:hdrlen]); err != nil {
|
if _, err = w.Write(self.tshdr[:hdrlen]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -561,7 +560,7 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if padtail > 0 {
|
if padtail > 0 {
|
||||||
if _, err = w.Write(self.tshdr[188-padtail:188]); err != nil {
|
if _, err = w.Write(self.tshdr[188-padtail : 188]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -578,13 +577,12 @@ func ParseTSHeader(tshdr []byte) (pid uint16, start bool, iskeyframe bool, hdrle
|
|||||||
err = fmt.Errorf("tshdr sync invalid")
|
err = fmt.Errorf("tshdr sync invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pid = uint16((tshdr[1]&0x1f))<<8|uint16(tshdr[2])
|
pid = uint16((tshdr[1]&0x1f))<<8 | uint16(tshdr[2])
|
||||||
start = tshdr[1]&0x40 != 0
|
start = tshdr[1]&0x40 != 0
|
||||||
hdrlen += 4
|
hdrlen += 4
|
||||||
if tshdr[3]&0x20 != 0 {
|
if tshdr[3]&0x20 != 0 {
|
||||||
hdrlen += int(tshdr[4])+1
|
hdrlen += int(tshdr[4]) + 1
|
||||||
iskeyframe = tshdr[5]&0x40 != 0
|
iskeyframe = tshdr[5]&0x40 != 0
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,13 +6,13 @@ import (
|
|||||||
|
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
buf [][]byte
|
buf [][]byte
|
||||||
R io.ReadSeeker
|
R io.ReadSeeker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReaderSize(r io.ReadSeeker, size int) *Reader {
|
func NewReaderSize(r io.ReadSeeker, size int) *Reader {
|
||||||
buf := make([]byte, size*2)
|
buf := make([]byte, size*2)
|
||||||
return &Reader{
|
return &Reader{
|
||||||
R: r,
|
R: r,
|
||||||
buf: [][]byte{buf[0:size], buf[size:]},
|
buf: [][]byte{buf[0:size], buf[size:]},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,4 +20,3 @@ func NewReaderSize(r io.ReadSeeker, size int) *Reader {
|
|||||||
func (self *Reader) ReadAt(b []byte, off int64) (n int, err error) {
|
func (self *Reader) ReadAt(b []byte, off int64) (n int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
package pio
|
package pio
|
||||||
|
|
||||||
var RecommendBufioSize = 1024*64
|
var RecommendBufioSize = 1024 * 64
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package pio
|
package pio
|
||||||
|
|
||||||
func U8(b []byte) (i uint8) {
|
func U8(b []byte) (i uint8) {
|
||||||
@ -7,85 +6,116 @@ func U8(b []byte) (i uint8) {
|
|||||||
|
|
||||||
func U16BE(b []byte) (i uint16) {
|
func U16BE(b []byte) (i uint16) {
|
||||||
i = uint16(b[0])
|
i = uint16(b[0])
|
||||||
i <<= 8; i |= uint16(b[1])
|
i <<= 8
|
||||||
|
i |= uint16(b[1])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func I16BE(b []byte) (i int16) {
|
func I16BE(b []byte) (i int16) {
|
||||||
i = int16(b[0])
|
i = int16(b[0])
|
||||||
i <<= 8; i |= int16(b[1])
|
i <<= 8
|
||||||
|
i |= int16(b[1])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func I24BE(b []byte) (i int32) {
|
func I24BE(b []byte) (i int32) {
|
||||||
i = int32(int8(b[0]))
|
i = int32(int8(b[0]))
|
||||||
i <<= 8; i |= int32(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= int32(b[2])
|
i |= int32(b[1])
|
||||||
|
i <<= 8
|
||||||
|
i |= int32(b[2])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func U24BE(b []byte) (i uint32) {
|
func U24BE(b []byte) (i uint32) {
|
||||||
i = uint32(b[0])
|
i = uint32(b[0])
|
||||||
i <<= 8; i |= uint32(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= uint32(b[2])
|
i |= uint32(b[1])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint32(b[2])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func I32BE(b []byte) (i int32) {
|
func I32BE(b []byte) (i int32) {
|
||||||
i = int32(int8(b[0]))
|
i = int32(int8(b[0]))
|
||||||
i <<= 8; i |= int32(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= int32(b[2])
|
i |= int32(b[1])
|
||||||
i <<= 8; i |= int32(b[3])
|
i <<= 8
|
||||||
|
i |= int32(b[2])
|
||||||
|
i <<= 8
|
||||||
|
i |= int32(b[3])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func U32LE(b []byte) (i uint32) {
|
func U32LE(b []byte) (i uint32) {
|
||||||
i = uint32(b[3])
|
i = uint32(b[3])
|
||||||
i <<= 8; i |= uint32(b[2])
|
i <<= 8
|
||||||
i <<= 8; i |= uint32(b[1])
|
i |= uint32(b[2])
|
||||||
i <<= 8; i |= uint32(b[0])
|
i <<= 8
|
||||||
|
i |= uint32(b[1])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint32(b[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func U32BE(b []byte) (i uint32) {
|
func U32BE(b []byte) (i uint32) {
|
||||||
i = uint32(b[0])
|
i = uint32(b[0])
|
||||||
i <<= 8; i |= uint32(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= uint32(b[2])
|
i |= uint32(b[1])
|
||||||
i <<= 8; i |= uint32(b[3])
|
i <<= 8
|
||||||
|
i |= uint32(b[2])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint32(b[3])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func U40BE(b []byte) (i uint64) {
|
func U40BE(b []byte) (i uint64) {
|
||||||
i = uint64(b[0])
|
i = uint64(b[0])
|
||||||
i <<= 8; i |= uint64(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= uint64(b[2])
|
i |= uint64(b[1])
|
||||||
i <<= 8; i |= uint64(b[3])
|
i <<= 8
|
||||||
i <<= 8; i |= uint64(b[4])
|
i |= uint64(b[2])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint64(b[3])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint64(b[4])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func U64BE(b []byte) (i uint64) {
|
func U64BE(b []byte) (i uint64) {
|
||||||
i = uint64(b[0])
|
i = uint64(b[0])
|
||||||
i <<= 8; i |= uint64(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= uint64(b[2])
|
i |= uint64(b[1])
|
||||||
i <<= 8; i |= uint64(b[3])
|
i <<= 8
|
||||||
i <<= 8; i |= uint64(b[4])
|
i |= uint64(b[2])
|
||||||
i <<= 8; i |= uint64(b[5])
|
i <<= 8
|
||||||
i <<= 8; i |= uint64(b[6])
|
i |= uint64(b[3])
|
||||||
i <<= 8; i |= uint64(b[7])
|
i <<= 8
|
||||||
|
i |= uint64(b[4])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint64(b[5])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint64(b[6])
|
||||||
|
i <<= 8
|
||||||
|
i |= uint64(b[7])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func I64BE(b []byte) (i int64) {
|
func I64BE(b []byte) (i int64) {
|
||||||
i = int64(int8(b[0]))
|
i = int64(int8(b[0]))
|
||||||
i <<= 8; i |= int64(b[1])
|
i <<= 8
|
||||||
i <<= 8; i |= int64(b[2])
|
i |= int64(b[1])
|
||||||
i <<= 8; i |= int64(b[3])
|
i <<= 8
|
||||||
i <<= 8; i |= int64(b[4])
|
i |= int64(b[2])
|
||||||
i <<= 8; i |= int64(b[5])
|
i <<= 8
|
||||||
i <<= 8; i |= int64(b[6])
|
i |= int64(b[3])
|
||||||
i <<= 8; i |= int64(b[7])
|
i <<= 8
|
||||||
|
i |= int64(b[4])
|
||||||
|
i <<= 8
|
||||||
|
i |= int64(b[5])
|
||||||
|
i <<= 8
|
||||||
|
i |= int64(b[6])
|
||||||
|
i <<= 8
|
||||||
|
i |= int64(b[7])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ func VecSliceTo(in [][]byte, out [][]byte, s int, e int) (n int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for e != 0 && i < len(in) {
|
for e != 0 && i < len(in) {
|
||||||
left := len(in[i])-off
|
left := len(in[i]) - off
|
||||||
read := left
|
read := left
|
||||||
if e > 0 && e < read {
|
if e > 0 && e < read {
|
||||||
read = e
|
read = e
|
||||||
}
|
}
|
||||||
out[n] = in[i][off:off+read]
|
out[n] = in[i][off : off+read]
|
||||||
n++
|
n++
|
||||||
left -= read
|
left -= read
|
||||||
e -= read
|
e -= read
|
||||||
@ -66,4 +66,3 @@ func VecSlice(in [][]byte, s int, e int) (out [][]byte) {
|
|||||||
out = out[:n]
|
out = out[:n]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package pio
|
package pio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ExampleVec() {
|
func ExampleVec() {
|
||||||
vec := [][]byte{[]byte{1,2,3}, []byte{4,5,6,7,8,9}, []byte{10,11,12,13}}
|
vec := [][]byte{[]byte{1, 2, 3}, []byte{4, 5, 6, 7, 8, 9}, []byte{10, 11, 12, 13}}
|
||||||
println(VecLen(vec))
|
println(VecLen(vec))
|
||||||
|
|
||||||
vec = VecSlice(vec, 1, -1)
|
vec = VecSlice(vec, 1, -1)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package pio
|
package pio
|
||||||
|
|
||||||
func PutU8(b []byte, v uint8) {
|
func PutU8(b []byte, v uint8) {
|
||||||
@ -6,84 +5,83 @@ func PutU8(b []byte, v uint8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PutI16BE(b []byte, v int16) {
|
func PutI16BE(b []byte, v int16) {
|
||||||
b[0] = byte(v>>8)
|
b[0] = byte(v >> 8)
|
||||||
b[1] = byte(v)
|
b[1] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU16BE(b []byte, v uint16) {
|
func PutU16BE(b []byte, v uint16) {
|
||||||
b[0] = byte(v>>8)
|
b[0] = byte(v >> 8)
|
||||||
b[1] = byte(v)
|
b[1] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutI24BE(b []byte, v int32) {
|
func PutI24BE(b []byte, v int32) {
|
||||||
b[0] = byte(v>>16)
|
b[0] = byte(v >> 16)
|
||||||
b[1] = byte(v>>8)
|
b[1] = byte(v >> 8)
|
||||||
b[2] = byte(v)
|
b[2] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU24BE(b []byte, v uint32) {
|
func PutU24BE(b []byte, v uint32) {
|
||||||
b[0] = byte(v>>16)
|
b[0] = byte(v >> 16)
|
||||||
b[1] = byte(v>>8)
|
b[1] = byte(v >> 8)
|
||||||
b[2] = byte(v)
|
b[2] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutI32BE(b []byte, v int32) {
|
func PutI32BE(b []byte, v int32) {
|
||||||
b[0] = byte(v>>24)
|
b[0] = byte(v >> 24)
|
||||||
b[1] = byte(v>>16)
|
b[1] = byte(v >> 16)
|
||||||
b[2] = byte(v>>8)
|
b[2] = byte(v >> 8)
|
||||||
b[3] = byte(v)
|
b[3] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU32BE(b []byte, v uint32) {
|
func PutU32BE(b []byte, v uint32) {
|
||||||
b[0] = byte(v>>24)
|
b[0] = byte(v >> 24)
|
||||||
b[1] = byte(v>>16)
|
b[1] = byte(v >> 16)
|
||||||
b[2] = byte(v>>8)
|
b[2] = byte(v >> 8)
|
||||||
b[3] = byte(v)
|
b[3] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU32LE(b []byte, v uint32) {
|
func PutU32LE(b []byte, v uint32) {
|
||||||
b[3] = byte(v>>24)
|
b[3] = byte(v >> 24)
|
||||||
b[2] = byte(v>>16)
|
b[2] = byte(v >> 16)
|
||||||
b[1] = byte(v>>8)
|
b[1] = byte(v >> 8)
|
||||||
b[0] = byte(v)
|
b[0] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU40BE(b []byte, v uint64) {
|
func PutU40BE(b []byte, v uint64) {
|
||||||
b[0] = byte(v>>32)
|
b[0] = byte(v >> 32)
|
||||||
b[1] = byte(v>>24)
|
b[1] = byte(v >> 24)
|
||||||
b[2] = byte(v>>16)
|
b[2] = byte(v >> 16)
|
||||||
b[3] = byte(v>>8)
|
b[3] = byte(v >> 8)
|
||||||
b[4] = byte(v)
|
b[4] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU48BE(b []byte, v uint64) {
|
func PutU48BE(b []byte, v uint64) {
|
||||||
b[0] = byte(v>>40)
|
b[0] = byte(v >> 40)
|
||||||
b[1] = byte(v>>32)
|
b[1] = byte(v >> 32)
|
||||||
b[2] = byte(v>>24)
|
b[2] = byte(v >> 24)
|
||||||
b[3] = byte(v>>16)
|
b[3] = byte(v >> 16)
|
||||||
b[4] = byte(v>>8)
|
b[4] = byte(v >> 8)
|
||||||
b[5] = byte(v)
|
b[5] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutU64BE(b []byte, v uint64) {
|
func PutU64BE(b []byte, v uint64) {
|
||||||
b[0] = byte(v>>56)
|
b[0] = byte(v >> 56)
|
||||||
b[1] = byte(v>>48)
|
b[1] = byte(v >> 48)
|
||||||
b[2] = byte(v>>40)
|
b[2] = byte(v >> 40)
|
||||||
b[3] = byte(v>>32)
|
b[3] = byte(v >> 32)
|
||||||
b[4] = byte(v>>24)
|
b[4] = byte(v >> 24)
|
||||||
b[5] = byte(v>>16)
|
b[5] = byte(v >> 16)
|
||||||
b[6] = byte(v>>8)
|
b[6] = byte(v >> 8)
|
||||||
b[7] = byte(v)
|
b[7] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutI64BE(b []byte, v int64) {
|
func PutI64BE(b []byte, v int64) {
|
||||||
b[0] = byte(v>>56)
|
b[0] = byte(v >> 56)
|
||||||
b[1] = byte(v>>48)
|
b[1] = byte(v >> 48)
|
||||||
b[2] = byte(v>>40)
|
b[2] = byte(v >> 40)
|
||||||
b[3] = byte(v>>32)
|
b[3] = byte(v >> 32)
|
||||||
b[4] = byte(v>>24)
|
b[4] = byte(v >> 24)
|
||||||
b[5] = byte(v>>16)
|
b[5] = byte(v >> 16)
|
||||||
b[6] = byte(v>>8)
|
b[6] = byte(v >> 8)
|
||||||
b[7] = byte(v)
|
b[7] = byte(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user