mirror of
https://github.com/bluenviron/mediamtx.git
synced 2026-01-26 21:39:16 -08:00
move pmp4 package into mediacommon (#3367)
This commit is contained in:
parent
af9792b44e
commit
425b7fa4fb
8 changed files with 9 additions and 1617 deletions
2
go.mod
2
go.mod
|
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/alecthomas/kong v0.9.0
|
||||
github.com/bluenviron/gohlslib v1.3.2
|
||||
github.com/bluenviron/gortsplib/v4 v4.9.1-0.20240515082130-f283abc2e7cd
|
||||
github.com/bluenviron/mediacommon v1.10.0
|
||||
github.com/bluenviron/mediacommon v1.10.1-0.20240518092051-bab50c4ba9c5
|
||||
github.com/datarhei/gosrt v0.6.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -24,8 +24,8 @@ github.com/bluenviron/gohlslib v1.3.2 h1:xRiPfMIeYCkspL6jYa7Qrl4pIY+1w7IvFjx49Cs
|
|||
github.com/bluenviron/gohlslib v1.3.2/go.mod h1:1/m7A2o5IWyBdZeauXe2bViu2l1mL2l8DMQl9302A2U=
|
||||
github.com/bluenviron/gortsplib/v4 v4.9.1-0.20240515082130-f283abc2e7cd h1:w1Uml4bXdixu7cArQ3JyiZTpaKzZ31eP9+bWoPPkWcY=
|
||||
github.com/bluenviron/gortsplib/v4 v4.9.1-0.20240515082130-f283abc2e7cd/go.mod h1:iLJ1tmwGMbaN04ZYh/KRlAHsCbz9Rycn7cPAvdR+Vkc=
|
||||
github.com/bluenviron/mediacommon v1.10.0 h1:ffIWaS+1vYpPLV6QOt4VEvIlb/OKtodzagzsY6EDOnw=
|
||||
github.com/bluenviron/mediacommon v1.10.0/go.mod h1:HDyW2CzjvhYJXtdxstdFPio3G0qSocPhqkhUt/qffec=
|
||||
github.com/bluenviron/mediacommon v1.10.1-0.20240518092051-bab50c4ba9c5 h1:fZL+8Bz8wT0ljvt+ZyGGzirT1jQxH1wgqOiyRifAL60=
|
||||
github.com/bluenviron/mediacommon v1.10.1-0.20240518092051-bab50c4ba9c5/go.mod h1:HDyW2CzjvhYJXtdxstdFPio3G0qSocPhqkhUt/qffec=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
package mp4
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/abema/go-mp4"
|
||||
)
|
||||
|
||||
type mp4Writer struct {
|
||||
w *mp4.Writer
|
||||
}
|
||||
|
||||
func newMP4Writer(w io.WriteSeeker) *mp4Writer {
|
||||
return &mp4Writer{
|
||||
w: mp4.NewWriter(w),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *mp4Writer) writeBoxStart(box mp4.IImmutableBox) (int, error) {
|
||||
bi := &mp4.BoxInfo{
|
||||
Type: box.GetType(),
|
||||
}
|
||||
var err error
|
||||
bi, err = w.w.StartBox(bi)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
_, err = mp4.Marshal(w.w, box, mp4.Context{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(bi.Offset), nil
|
||||
}
|
||||
|
||||
func (w *mp4Writer) writeBoxEnd() error {
|
||||
_, err := w.w.EndBox()
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *mp4Writer) writeBox(box mp4.IImmutableBox) (int, error) {
|
||||
off, err := w.writeBoxStart(box)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = w.writeBoxEnd()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (w *mp4Writer) rewriteBox(off int, box mp4.IImmutableBox) error {
|
||||
prevOff, err := w.w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.w.Seek(int64(off), io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(box)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.writeBoxEnd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.w.Seek(prevOff, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
// Package mp4 contains a MP4 muxer.
|
||||
package mp4
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/abema/go-mp4"
|
||||
"github.com/bluenviron/mediacommon/pkg/formats/fmp4/seekablebuffer"
|
||||
)
|
||||
|
||||
const (
|
||||
globalTimescale = 1000
|
||||
)
|
||||
|
||||
func durationMp4ToGo(v int64, timeScale uint32) time.Duration {
|
||||
timeScale64 := int64(timeScale)
|
||||
secs := v / timeScale64
|
||||
dec := v % timeScale64
|
||||
return time.Duration(secs)*time.Second + time.Duration(dec)*time.Second/time.Duration(timeScale64)
|
||||
}
|
||||
|
||||
// Presentation is timed sequence of video/audio samples.
|
||||
type Presentation struct {
|
||||
Tracks []*Track
|
||||
}
|
||||
|
||||
// Marshal encodes a Presentation.
|
||||
func (p *Presentation) Marshal(w io.Writer) error {
|
||||
/*
|
||||
|ftyp|
|
||||
|moov|
|
||||
| |mvhd|
|
||||
| |trak|
|
||||
| |trak|
|
||||
| |....|
|
||||
|mdat|
|
||||
*/
|
||||
|
||||
dataSize, sortedSamples := p.sortSamples()
|
||||
|
||||
err := p.marshalFtypAndMoov(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.marshalMdat(w, dataSize, sortedSamples)
|
||||
}
|
||||
|
||||
func (p *Presentation) sortSamples() (uint32, []*Sample) {
|
||||
sampleCount := 0
|
||||
for _, track := range p.Tracks {
|
||||
sampleCount += len(track.Samples)
|
||||
}
|
||||
|
||||
processedSamples := make([]int, len(p.Tracks))
|
||||
elapsed := make([]int64, len(p.Tracks))
|
||||
offset := uint32(0)
|
||||
sortedSamples := make([]*Sample, sampleCount)
|
||||
pos := 0
|
||||
|
||||
for i, track := range p.Tracks {
|
||||
elapsed[i] = int64(track.TimeOffset)
|
||||
}
|
||||
|
||||
for {
|
||||
bestTrack := -1
|
||||
var bestElapsed time.Duration
|
||||
|
||||
for i, track := range p.Tracks {
|
||||
if processedSamples[i] < len(track.Samples) {
|
||||
elapsedGo := durationMp4ToGo(elapsed[i], track.TimeScale)
|
||||
|
||||
if bestTrack == -1 || elapsedGo < bestElapsed {
|
||||
bestTrack = i
|
||||
bestElapsed = elapsedGo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bestTrack == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
sample := p.Tracks[bestTrack].Samples[processedSamples[bestTrack]]
|
||||
sample.offset = offset
|
||||
|
||||
processedSamples[bestTrack]++
|
||||
elapsed[bestTrack] += int64(sample.Duration)
|
||||
offset += sample.PayloadSize
|
||||
sortedSamples[pos] = sample
|
||||
pos++
|
||||
}
|
||||
|
||||
return offset, sortedSamples
|
||||
}
|
||||
|
||||
func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
|
||||
var outBuf seekablebuffer.Buffer
|
||||
mw := newMP4Writer(&outBuf)
|
||||
|
||||
_, err := mw.writeBox(&mp4.Ftyp{ // <ftyp/>
|
||||
MajorBrand: [4]byte{'i', 's', 'o', 'm'},
|
||||
MinorVersion: 1,
|
||||
CompatibleBrands: []mp4.CompatibleBrandElem{
|
||||
{CompatibleBrand: [4]byte{'i', 's', 'o', 'm'}},
|
||||
{CompatibleBrand: [4]byte{'i', 's', 'o', '2'}},
|
||||
{CompatibleBrand: [4]byte{'m', 'p', '4', '1'}},
|
||||
{CompatibleBrand: [4]byte{'m', 'p', '4', '2'}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = mw.writeBoxStart(&mp4.Moov{}) // <moov>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mvhd := &mp4.Mvhd{ // <mvhd/>
|
||||
Timescale: globalTimescale,
|
||||
Rate: 65536,
|
||||
Volume: 256,
|
||||
Matrix: [9]int32{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000},
|
||||
NextTrackID: uint32(len(p.Tracks) + 1),
|
||||
}
|
||||
mvhdOffset, err := mw.writeBox(mvhd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stcos := make([]*mp4.Stco, len(p.Tracks))
|
||||
stcosOffsets := make([]int, len(p.Tracks))
|
||||
|
||||
for i, track := range p.Tracks {
|
||||
var res *headerTrackMarshalResult
|
||||
res, err = track.marshal(mw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stcos[i] = res.stco
|
||||
stcosOffsets[i] = res.stcoOffset
|
||||
|
||||
if res.presentationDuration > mvhd.DurationV0 {
|
||||
mvhd.DurationV0 = res.presentationDuration
|
||||
}
|
||||
}
|
||||
|
||||
err = mw.rewriteBox(mvhdOffset, mvhd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mw.writeBoxEnd() // </moov>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
moovEndOffset, err := outBuf.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataOffset := moovEndOffset + 8
|
||||
|
||||
for i := range p.Tracks {
|
||||
for j := range stcos[i].ChunkOffset {
|
||||
stcos[i].ChunkOffset[j] += uint32(dataOffset)
|
||||
}
|
||||
|
||||
err = mw.rewriteBox(stcosOffsets[i], stcos[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = w.Write(outBuf.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Presentation) marshalMdat(w io.Writer, dataSize uint32, sortedSamples []*Sample) error {
|
||||
mdatSize := uint32(8) + dataSize
|
||||
|
||||
_, err := w.Write([]byte{byte(mdatSize >> 24), byte(mdatSize >> 16), byte(mdatSize >> 8), byte(mdatSize)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte{'m', 'd', 'a', 't'})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sa := range sortedSamples {
|
||||
pl, err := sa.GetPayload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(pl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
package mp4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/bluenviron/mediacommon/pkg/formats/fmp4"
|
||||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var casesPresentation = []struct {
|
||||
name string
|
||||
dec Presentation
|
||||
enc []byte
|
||||
}{
|
||||
{
|
||||
"standard",
|
||||
Presentation{
|
||||
Tracks: []*Track{
|
||||
{
|
||||
ID: 1,
|
||||
TimeScale: 90000,
|
||||
TimeOffset: -90000,
|
||||
Codec: &fmp4.CodecH264{
|
||||
SPS: test.FormatH264.SPS,
|
||||
PPS: test.FormatH264.PPS,
|
||||
},
|
||||
Samples: []*Sample{
|
||||
{
|
||||
Duration: 90000,
|
||||
PTSOffset: -45000,
|
||||
PayloadSize: 2,
|
||||
GetPayload: func() ([]byte, error) {
|
||||
return []byte{1, 2}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Duration: 90000,
|
||||
PayloadSize: 2,
|
||||
GetPayload: func() ([]byte, error) {
|
||||
return []byte{3, 4}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Duration: 90000,
|
||||
PTSOffset: -45000,
|
||||
PayloadSize: 2,
|
||||
GetPayload: func() ([]byte, error) {
|
||||
return []byte{5, 6}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]byte{
|
||||
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70,
|
||||
0x69, 0x73, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x01,
|
||||
0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32,
|
||||
0x6d, 0x70, 0x34, 0x31, 0x6d, 0x70, 0x34, 0x32,
|
||||
0x00, 0x00, 0x02, 0xbf, 0x6d, 0x6f, 0x6f, 0x76,
|
||||
0x00, 0x00, 0x00, 0x6c, 0x6d, 0x76, 0x68, 0x64,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8,
|
||||
0x00, 0x00, 0x07, 0xd0, 0x00, 0x01, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x4b,
|
||||
0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c,
|
||||
0x74, 0x6b, 0x68, 0x64, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x07, 0x80, 0x00, 0x00, 0x04, 0x38, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x24, 0x65, 0x64, 0x74, 0x73,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x65, 0x6c, 0x73, 0x74,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x0f, 0xa0, 0x00, 0x01, 0x5f, 0x90,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc3,
|
||||
0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20,
|
||||
0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x5f, 0x90, 0x00, 0x02, 0xbf, 0x20,
|
||||
0x55, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
|
||||
0x68, 0x64, 0x6c, 0x72, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x64, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65,
|
||||
0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72,
|
||||
0x00, 0x00, 0x00, 0x01, 0x6e, 0x6d, 0x69, 0x6e,
|
||||
0x66, 0x00, 0x00, 0x00, 0x14, 0x76, 0x6d, 0x68,
|
||||
0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x64, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x75, 0x72, 0x6c, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x01, 0x2e, 0x73, 0x74, 0x62,
|
||||
0x6c, 0x00, 0x00, 0x00, 0x96, 0x73, 0x74, 0x73,
|
||||
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x86, 0x61, 0x76, 0x63,
|
||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x80, 0x04, 0x38, 0x00, 0x48, 0x00,
|
||||
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0x00,
|
||||
0x00, 0x00, 0x30, 0x61, 0x76, 0x63, 0x43, 0x01,
|
||||
0x42, 0xc0, 0x28, 0x03, 0x01, 0x00, 0x19, 0x67,
|
||||
0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, 0x27,
|
||||
0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||||
0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 0x20,
|
||||
0x01, 0x00, 0x04, 0x08, 0x06, 0x07, 0x08, 0x00,
|
||||
0x00, 0x00, 0x18, 0x73, 0x74, 0x74, 0x73, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x01, 0x5f, 0x90, 0x00,
|
||||
0x00, 0x00, 0x28, 0x63, 0x74, 0x74, 0x73, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x01, 0xff, 0xff, 0x50, 0x38, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0xff, 0xff, 0x50, 0x38, 0x00,
|
||||
0x00, 0x00, 0x1c, 0x73, 0x74, 0x73, 0x63, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x73,
|
||||
0x74, 0x73, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x73,
|
||||
0x74, 0x63, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xe7, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x6d, 0x64, 0x61, 0x74, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestPresentationMarshal(t *testing.T) {
|
||||
for _, ca := range casesPresentation {
|
||||
t.Run(ca.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := ca.dec.Marshal(&buf)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ca.enc, buf.Bytes())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package mp4
|
||||
|
||||
// Sample is a sample of a Track.
|
||||
type Sample struct {
|
||||
Duration uint32
|
||||
PTSOffset int32
|
||||
IsNonSyncSample bool
|
||||
PayloadSize uint32
|
||||
GetPayload func() ([]byte, error)
|
||||
|
||||
offset uint32 // filled by sortSamples
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,11 +4,11 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/bluenviron/mediacommon/pkg/formats/fmp4"
|
||||
"github.com/bluenviron/mediamtx/internal/playback/mp4"
|
||||
"github.com/bluenviron/mediacommon/pkg/formats/pmp4"
|
||||
)
|
||||
|
||||
type muxerMP4Track struct {
|
||||
mp4.Track
|
||||
pmp4.Track
|
||||
lastDTS int64
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ func (w *muxerMP4) writeInit(init *fmp4.Init) {
|
|||
|
||||
for i, track := range init.Tracks {
|
||||
w.tracks[i] = &muxerMP4Track{
|
||||
Track: mp4.Track{
|
||||
Track: pmp4.Track{
|
||||
ID: track.ID,
|
||||
TimeScale: track.TimeScale,
|
||||
Codec: track.Codec,
|
||||
|
|
@ -73,7 +73,7 @@ func (w *muxerMP4) writeSample(
|
|||
ptsOffset = 0
|
||||
}
|
||||
|
||||
w.curTrack.Samples = append(w.curTrack.Samples, &mp4.Sample{
|
||||
w.curTrack.Samples = append(w.curTrack.Samples, &pmp4.Sample{
|
||||
PTSOffset: ptsOffset,
|
||||
IsNonSyncSample: isNonSyncSample,
|
||||
PayloadSize: payloadSize,
|
||||
|
|
@ -93,8 +93,8 @@ func (w *muxerMP4) writeFinalDTS(dts int64) {
|
|||
}
|
||||
|
||||
func (w *muxerMP4) flush() error {
|
||||
h := mp4.Presentation{
|
||||
Tracks: make([]*mp4.Track, len(w.tracks)),
|
||||
h := pmp4.Presentation{
|
||||
Tracks: make([]*pmp4.Track, len(w.tracks)),
|
||||
}
|
||||
|
||||
for i, track := range w.tracks {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue