diff --git a/internal/hls/mp4writer.go b/internal/hls/mp4writer.go
deleted file mode 100644
index f964739b..00000000
--- a/internal/hls/mp4writer.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package hls
-
-import (
- "io"
-
- "github.com/abema/go-mp4"
- "github.com/orcaman/writerseeker"
-)
-
-type mp4Writer struct {
- buf *writerseeker.WriterSeeker
- w *mp4.Writer
-}
-
-func newMP4Writer() *mp4Writer {
- w := &mp4Writer{
- buf: &writerseeker.WriterSeeker{},
- }
-
- w.w = mp4.NewWriter(w.buf)
-
- return 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
-}
-
-func (w *mp4Writer) bytes() []byte {
- return w.buf.Bytes()
-}
diff --git a/internal/hls/muxer_variant_fmp4_init.go b/internal/hls/muxer_variant_fmp4_init.go
index c276ad01..b2c67705 100644
--- a/internal/hls/muxer_variant_fmp4_init.go
+++ b/internal/hls/muxer_variant_fmp4_init.go
@@ -1,26 +1,28 @@
package hls
import (
- "github.com/abema/go-mp4"
+ gomp4 "github.com/abema/go-mp4"
"github.com/aler9/gortsplib"
"github.com/aler9/gortsplib/pkg/aac"
"github.com/aler9/gortsplib/pkg/h264"
+
+ "github.com/aler9/rtsp-simple-server/internal/mp4"
)
type myEsds struct {
- mp4.FullBox `mp4:"0,extend"`
- Data []byte `mp4:"1,size=8"`
+ gomp4.FullBox `mp4:"0,extend"`
+ Data []byte `mp4:"1,size=8"`
}
-func (*myEsds) GetType() mp4.BoxType {
- return mp4.StrToBoxType("esds")
+func (*myEsds) GetType() gomp4.BoxType {
+ return gomp4.StrToBoxType("esds")
}
func init() { //nolint:gochecknoinits
- mp4.AddBoxDef(&myEsds{}, 0)
+ gomp4.AddBoxDef(&myEsds{}, 0)
}
-func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.TrackH264) error {
+func mp4InitGenerateVideoTrack(w *mp4.Writer, trackID int, videoTrack *gortsplib.TrackH264) error {
/*
trak
- tkhd
@@ -44,7 +46,7 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
- stco
*/
- _, err := w.writeBoxStart(&mp4.Trak{}) //
+ _, err := w.WriteBoxStart(&gomp4.Trak{}) //
if err != nil {
return err
}
@@ -61,8 +63,8 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
width := spsp.Width()
height := spsp.Height()
- _, err = w.writeBox(&mp4.Tkhd{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tkhd{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
TrackID: uint32(trackID),
@@ -74,12 +76,12 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBoxStart(&mp4.Mdia{}) //
+ _, err = w.WriteBoxStart(&gomp4.Mdia{}) //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Mdhd{ //
+ _, err = w.WriteBox(&gomp4.Mdhd{ //
Timescale: fmp4VideoTimescale, // the number of time units that pass per second
Language: [3]byte{'u', 'n', 'd'},
})
@@ -87,7 +89,7 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBox(&mp4.Hdlr{ //
+ _, err = w.WriteBox(&gomp4.Hdlr{ //
HandlerType: [4]byte{'v', 'i', 'd', 'e'},
Name: "VideoHandler",
})
@@ -95,13 +97,13 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBoxStart(&mp4.Minf{}) //
+ _, err = w.WriteBoxStart(&gomp4.Minf{}) //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Vmhd{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Vmhd{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
})
@@ -109,20 +111,20 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBoxStart(&mp4.Dinf{}) //
+ _, err = w.WriteBoxStart(&gomp4.Dinf{}) //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Dref{ //
+ _, err = w.WriteBoxStart(&gomp4.Dref{ //
EntryCount: 1,
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Url{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Url{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
})
@@ -130,32 +132,32 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Stbl{}) //
+ _, err = w.WriteBoxStart(&gomp4.Stbl{}) //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Stsd{ //
+ _, err = w.WriteBoxStart(&gomp4.Stsd{ //
EntryCount: 1,
})
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.VisualSampleEntry{ //
- SampleEntry: mp4.SampleEntry{
- AnyTypeBox: mp4.AnyTypeBox{
- Type: mp4.BoxTypeAvc1(),
+ _, err = w.WriteBoxStart(&gomp4.VisualSampleEntry{ //
+ SampleEntry: gomp4.SampleEntry{
+ AnyTypeBox: gomp4.AnyTypeBox{
+ Type: gomp4.BoxTypeAvc1(),
},
DataReferenceIndex: 1,
},
@@ -171,9 +173,9 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBox(&mp4.AVCDecoderConfiguration{ //
- AnyTypeBox: mp4.AnyTypeBox{
- Type: mp4.BoxTypeAvcC(),
+ _, err = w.WriteBox(&gomp4.AVCDecoderConfiguration{ //
+ AnyTypeBox: gomp4.AnyTypeBox{
+ Type: gomp4.BoxTypeAvcC(),
},
ConfigurationVersion: 1,
Profile: spsp.ProfileIdc,
@@ -181,14 +183,14 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
Level: spsp.LevelIdc,
LengthSizeMinusOne: 3,
NumOfSequenceParameterSets: 1,
- SequenceParameterSets: []mp4.AVCParameterSet{
+ SequenceParameterSets: []gomp4.AVCParameterSet{
{
Length: uint16(len(sps)),
NALUnit: sps,
},
},
NumOfPictureParameterSets: 1,
- PictureParameterSets: []mp4.AVCParameterSet{
+ PictureParameterSets: []gomp4.AVCParameterSet{
{
Length: uint16(len(pps)),
NALUnit: pps,
@@ -199,7 +201,7 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- _, err = w.writeBox(&mp4.Btrt{ //
+ _, err = w.WriteBox(&gomp4.Btrt{ //
MaxBitrate: 1000000,
AvgBitrate: 1000000,
})
@@ -207,56 +209,56 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stts{ //
+ _, err = w.WriteBox(&gomp4.Stts{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stsc{ //
+ _, err = w.WriteBox(&gomp4.Stsc{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stsz{ //
+ _, err = w.WriteBox(&gomp4.Stsz{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stco{ //
+ _, err = w.WriteBox(&gomp4.Stco{ //
})
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
@@ -264,7 +266,7 @@ func mp4InitGenerateVideoTrack(w *mp4Writer, trackID int, videoTrack *gortsplib.
return nil
}
-func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.TrackAAC) error {
+func mp4InitGenerateAudioTrack(w *mp4.Writer, trackID int, audioTrack *gortsplib.TrackAAC) error {
/*
trak
- tkhd
@@ -287,13 +289,13 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
- stco
*/
- _, err := w.writeBoxStart(&mp4.Trak{}) //
+ _, err := w.WriteBoxStart(&gomp4.Trak{}) //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Tkhd{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tkhd{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
TrackID: uint32(trackID),
@@ -305,12 +307,12 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
return err
}
- _, err = w.writeBoxStart(&mp4.Mdia{}) //
+ _, err = w.WriteBoxStart(&gomp4.Mdia{}) //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Mdhd{ //
+ _, err = w.WriteBox(&gomp4.Mdhd{ //
Timescale: uint32(audioTrack.ClockRate()),
Language: [3]byte{'u', 'n', 'd'},
})
@@ -318,7 +320,7 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
return err
}
- _, err = w.writeBox(&mp4.Hdlr{ //
+ _, err = w.WriteBox(&gomp4.Hdlr{ //
HandlerType: [4]byte{'s', 'o', 'u', 'n'},
Name: "SoundHandler",
})
@@ -326,31 +328,31 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
return err
}
- _, err = w.writeBoxStart(&mp4.Minf{}) //
+ _, err = w.WriteBoxStart(&gomp4.Minf{}) //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Smhd{ //
+ _, err = w.WriteBox(&gomp4.Smhd{ //
})
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Dinf{}) //
+ _, err = w.WriteBoxStart(&gomp4.Dinf{}) //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Dref{ //
+ _, err = w.WriteBoxStart(&gomp4.Dref{ //
EntryCount: 1,
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Url{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Url{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
})
@@ -358,32 +360,32 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Stbl{}) //
+ _, err = w.WriteBoxStart(&gomp4.Stbl{}) //
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.Stsd{ //
+ _, err = w.WriteBoxStart(&gomp4.Stsd{ //
EntryCount: 1,
})
if err != nil {
return err
}
- _, err = w.writeBoxStart(&mp4.AudioSampleEntry{ //
- SampleEntry: mp4.SampleEntry{
- AnyTypeBox: mp4.AnyTypeBox{
- Type: mp4.BoxTypeMp4a(),
+ _, err = w.WriteBoxStart(&gomp4.AudioSampleEntry{ //
+ SampleEntry: gomp4.SampleEntry{
+ AnyTypeBox: gomp4.AnyTypeBox{
+ Type: gomp4.BoxTypeMp4a(),
},
DataReferenceIndex: 1,
},
@@ -406,14 +408,14 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
decSpecificInfoTagSize := uint8(len(conf))
decSpecificInfoTag := append(
[]byte{
- mp4.DecSpecificInfoTag,
+ gomp4.DecSpecificInfoTag,
0x80, 0x80, 0x80, decSpecificInfoTagSize, // size
},
conf...,
)
esDescrTag := []byte{
- mp4.ESDescrTag,
+ gomp4.ESDescrTag,
0x80, 0x80, 0x80, 32 + decSpecificInfoTagSize, // size
0x00,
byte(trackID), // ES_ID
@@ -421,7 +423,7 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
}
decoderConfigDescrTag := []byte{
- mp4.DecoderConfigDescrTag,
+ gomp4.DecoderConfigDescrTag,
0x80, 0x80, 0x80, 18 + decSpecificInfoTagSize, // size
0x40, // object type indicator (MPEG-4 Audio)
0x15, 0x00,
@@ -431,7 +433,7 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
}
slConfigDescrTag := []byte{
- mp4.SLConfigDescrTag,
+ gomp4.SLConfigDescrTag,
0x80, 0x80, 0x80, 0x01, // size (1)
0x02,
}
@@ -444,14 +446,14 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
pos += copy(data[pos:], decSpecificInfoTag)
copy(data[pos:], slConfigDescrTag)
- _, err = w.writeBox(&myEsds{ //
+ _, err = w.WriteBox(&myEsds{ //
Data: data,
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Btrt{ //
+ _, err = w.WriteBox(&gomp4.Btrt{ //
MaxBitrate: 128825,
AvgBitrate: 128825,
})
@@ -459,56 +461,56 @@ func mp4InitGenerateAudioTrack(w *mp4Writer, trackID int, audioTrack *gortsplib.
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stts{ //
+ _, err = w.WriteBox(&gomp4.Stts{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stsc{ //
+ _, err = w.WriteBox(&gomp4.Stsc{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stsz{ //
+ _, err = w.WriteBox(&gomp4.Stsz{ //
})
if err != nil {
return err
}
- _, err = w.writeBox(&mp4.Stco{ //
+ _, err = w.WriteBox(&gomp4.Stco{ //
})
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return err
}
@@ -528,12 +530,12 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
- trex (audio)
*/
- w := newMP4Writer()
+ w := mp4.NewWriter()
- _, err := w.writeBox(&mp4.Ftyp{ //
+ _, err := w.WriteBox(&gomp4.Ftyp{ //
MajorBrand: [4]byte{'m', 'p', '4', '2'},
MinorVersion: 1,
- CompatibleBrands: []mp4.CompatibleBrandElem{
+ CompatibleBrands: []gomp4.CompatibleBrandElem{
{CompatibleBrand: [4]byte{'m', 'p', '4', '1'}},
{CompatibleBrand: [4]byte{'m', 'p', '4', '2'}},
{CompatibleBrand: [4]byte{'i', 's', 'o', 'm'}},
@@ -544,12 +546,12 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
return nil, err
}
- _, err = w.writeBoxStart(&mp4.Moov{}) //
+ _, err = w.WriteBoxStart(&gomp4.Moov{}) //
if err != nil {
return nil, err
}
- _, err = w.writeBox(&mp4.Mvhd{ //
+ _, err = w.WriteBox(&gomp4.Mvhd{ //
Timescale: 1000,
Rate: 65536,
Volume: 256,
@@ -578,7 +580,7 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
}
}
- _, err = w.writeBoxStart(&mp4.Mvex{}) //
+ _, err = w.WriteBoxStart(&gomp4.Mvex{}) //
if err != nil {
return nil, err
}
@@ -586,7 +588,7 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
trackID = 1
if videoTrack != nil {
- _, err = w.writeBox(&mp4.Trex{ //
+ _, err = w.WriteBox(&gomp4.Trex{ //
TrackID: uint32(trackID),
DefaultSampleDescriptionIndex: 1,
})
@@ -598,7 +600,7 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
}
if audioTrack != nil {
- _, err = w.writeBox(&mp4.Trex{ //
+ _, err = w.WriteBox(&gomp4.Trex{ //
TrackID: uint32(trackID),
DefaultSampleDescriptionIndex: 1,
})
@@ -607,15 +609,15 @@ func mp4InitGenerate(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.Trac
}
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return nil, err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return nil, err
}
- return w.bytes(), nil
+ return w.Bytes(), nil
}
diff --git a/internal/hls/muxer_variant_fmp4_part.go b/internal/hls/muxer_variant_fmp4_part.go
index 950c807d..d5c25cee 100644
--- a/internal/hls/muxer_variant_fmp4_part.go
+++ b/internal/hls/muxer_variant_fmp4_part.go
@@ -7,9 +7,11 @@ import (
"strconv"
"time"
- "github.com/abema/go-mp4"
+ gomp4 "github.com/abema/go-mp4"
"github.com/aler9/gortsplib"
"github.com/aler9/gortsplib/pkg/aac"
+
+ "github.com/aler9/rtsp-simple-server/internal/mp4"
)
func durationGoToMp4(v time.Duration, timescale time.Duration) int64 {
@@ -17,10 +19,10 @@ func durationGoToMp4(v time.Duration, timescale time.Duration) int64 {
}
func mp4PartGenerateVideoTraf(
- w *mp4Writer,
+ w *mp4.Writer,
trackID int,
videoSamples []*fmp4VideoSample,
-) (*mp4.Trun, int, error) {
+) (*gomp4.Trun, int, error) {
/*
traf
- tfhd
@@ -28,15 +30,15 @@ func mp4PartGenerateVideoTraf(
- trun
*/
- _, err := w.writeBoxStart(&mp4.Traf{}) //
+ _, err := w.WriteBoxStart(&gomp4.Traf{}) //
if err != nil {
return nil, 0, err
}
flags := 0
- _, err = w.writeBox(&mp4.Tfhd{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tfhd{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{2, byte(flags >> 8), byte(flags)},
},
TrackID: uint32(trackID),
@@ -45,8 +47,8 @@ func mp4PartGenerateVideoTraf(
return nil, 0, err
}
- _, err = w.writeBox(&mp4.Tfdt{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tfdt{ //
+ FullBox: gomp4.FullBox{
Version: 1,
},
// sum of decode durations of all earlier samples
@@ -63,8 +65,8 @@ func mp4PartGenerateVideoTraf(
flags |= 0x400 // sample flags present
flags |= 0x800 // sample composition time offset present or v1
- trun := &mp4.Trun{ //
- FullBox: mp4.FullBox{
+ trun := &gomp4.Trun{ //
+ FullBox: gomp4.FullBox{
Version: 1,
Flags: [3]byte{0, byte(flags >> 8), byte(flags)},
},
@@ -79,7 +81,7 @@ func mp4PartGenerateVideoTraf(
flags |= 1 << 16 // sample_is_non_sync_sample
}
- trun.Entries = append(trun.Entries, mp4.TrunEntry{
+ trun.Entries = append(trun.Entries, gomp4.TrunEntry{
SampleDuration: uint32(durationGoToMp4(e.duration(), fmp4VideoTimescale)),
SampleSize: uint32(len(e.avcc)),
SampleFlags: flags,
@@ -87,12 +89,12 @@ func mp4PartGenerateVideoTraf(
})
}
- trunOffset, err := w.writeBox(trun)
+ trunOffset, err := w.WriteBox(trun)
if err != nil {
return nil, 0, err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return nil, 0, err
}
@@ -101,11 +103,11 @@ func mp4PartGenerateVideoTraf(
}
func mp4PartGenerateAudioTraf(
- w *mp4Writer,
+ w *mp4.Writer,
trackID int,
audioTrack *gortsplib.TrackAAC,
audioSamples []*fmp4AudioSample,
-) (*mp4.Trun, int, error) {
+) (*gomp4.Trun, int, error) {
/*
traf
- tfhd
@@ -117,15 +119,15 @@ func mp4PartGenerateAudioTraf(
return nil, 0, nil
}
- _, err := w.writeBoxStart(&mp4.Traf{}) //
+ _, err := w.WriteBoxStart(&gomp4.Traf{}) //
if err != nil {
return nil, 0, err
}
flags := 0
- _, err = w.writeBox(&mp4.Tfhd{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tfhd{ //
+ FullBox: gomp4.FullBox{
Flags: [3]byte{2, byte(flags >> 8), byte(flags)},
},
TrackID: uint32(trackID),
@@ -134,8 +136,8 @@ func mp4PartGenerateAudioTraf(
return nil, 0, err
}
- _, err = w.writeBox(&mp4.Tfdt{ //
- FullBox: mp4.FullBox{
+ _, err = w.WriteBox(&gomp4.Tfdt{ //
+ FullBox: gomp4.FullBox{
Version: 1,
},
// sum of decode durations of all earlier samples
@@ -150,8 +152,8 @@ func mp4PartGenerateAudioTraf(
flags |= 0x100 // sample duration present
flags |= 0x200 // sample size present
- trun := &mp4.Trun{ //
- FullBox: mp4.FullBox{
+ trun := &gomp4.Trun{ //
+ FullBox: gomp4.FullBox{
Version: 0,
Flags: [3]byte{0, byte(flags >> 8), byte(flags)},
},
@@ -159,18 +161,18 @@ func mp4PartGenerateAudioTraf(
}
for _, e := range audioSamples {
- trun.Entries = append(trun.Entries, mp4.TrunEntry{
+ trun.Entries = append(trun.Entries, gomp4.TrunEntry{
SampleDuration: uint32(durationGoToMp4(e.duration(), time.Duration(audioTrack.ClockRate()))),
SampleSize: uint32(len(e.au)),
})
}
- trunOffset, err := w.writeBox(trun)
+ trunOffset, err := w.WriteBox(trun)
if err != nil {
return nil, 0, err
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return nil, 0, err
}
@@ -192,14 +194,14 @@ func mp4PartGenerate(
mdat
*/
- w := newMP4Writer()
+ w := mp4.NewWriter()
- moofOffset, err := w.writeBoxStart(&mp4.Moof{}) //
+ moofOffset, err := w.WriteBoxStart(&gomp4.Moof{}) //
if err != nil {
return nil, err
}
- _, err = w.writeBox(&mp4.Mfhd{ //
+ _, err = w.WriteBox(&gomp4.Mfhd{ //
SequenceNumber: 0,
})
if err != nil {
@@ -208,7 +210,7 @@ func mp4PartGenerate(
trackID := 1
- var videoTrun *mp4.Trun
+ var videoTrun *gomp4.Trun
var videoTrunOffset int
if videoTrack != nil {
var err error
@@ -221,7 +223,7 @@ func mp4PartGenerate(
trackID++
}
- var audioTrun *mp4.Trun
+ var audioTrun *gomp4.Trun
var audioTrunOffset int
if audioTrack != nil {
var err error
@@ -231,12 +233,12 @@ func mp4PartGenerate(
}
}
- err = w.writeBoxEnd() //
+ err = w.WriteBoxEnd() //
if err != nil {
return nil, err
}
- mdat := &mp4.Mdat{} //
+ mdat := &gomp4.Mdat{} //
dataSize := 0
videoDataSize := 0
@@ -269,14 +271,14 @@ func mp4PartGenerate(
}
}
- mdatOffset, err := w.writeBox(mdat)
+ mdatOffset, err := w.WriteBox(mdat)
if err != nil {
return nil, err
}
if videoTrack != nil {
videoTrun.DataOffset = int32(mdatOffset - moofOffset + 8)
- err = w.rewriteBox(videoTrunOffset, videoTrun)
+ err = w.RewriteBox(videoTrunOffset, videoTrun)
if err != nil {
return nil, err
}
@@ -284,13 +286,13 @@ func mp4PartGenerate(
if audioTrack != nil && audioTrun != nil {
audioTrun.DataOffset = int32(videoDataSize + mdatOffset - moofOffset + 8)
- err = w.rewriteBox(audioTrunOffset, audioTrun)
+ err = w.RewriteBox(audioTrunOffset, audioTrun)
if err != nil {
return nil, err
}
}
- return w.bytes(), nil
+ return w.Bytes(), nil
}
func fmp4PartName(id uint64) string {
diff --git a/internal/mp4/writer.go b/internal/mp4/writer.go
new file mode 100644
index 00000000..906d78d1
--- /dev/null
+++ b/internal/mp4/writer.go
@@ -0,0 +1,100 @@
+package mp4
+
+import (
+ "io"
+
+ gomp4 "github.com/abema/go-mp4"
+ "github.com/orcaman/writerseeker"
+)
+
+// Writer is a MP4 writer.
+type Writer struct {
+ buf *writerseeker.WriterSeeker
+ w *gomp4.Writer
+}
+
+// NewWriter allocates a Writer.
+func NewWriter() *Writer {
+ w := &Writer{
+ buf: &writerseeker.WriterSeeker{},
+ }
+
+ w.w = gomp4.NewWriter(w.buf)
+
+ return w
+}
+
+// WriteBoxStart writes a box start.
+func (w *Writer) WriteBoxStart(box gomp4.IImmutableBox) (int, error) {
+ bi := &gomp4.BoxInfo{
+ Type: box.GetType(),
+ }
+ var err error
+ bi, err = w.w.StartBox(bi)
+ if err != nil {
+ return 0, err
+ }
+
+ _, err = gomp4.Marshal(w.w, box, gomp4.Context{})
+ if err != nil {
+ return 0, err
+ }
+
+ return int(bi.Offset), nil
+}
+
+// WriteBoxEnd writes a box end.
+func (w *Writer) WriteBoxEnd() error {
+ _, err := w.w.EndBox()
+ return err
+}
+
+// WriteBox writes a self-closing box.
+func (w *Writer) WriteBox(box gomp4.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
+}
+
+// RewriteBox rewrites a box.
+func (w *Writer) RewriteBox(off int, box gomp4.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
+}
+
+// Bytes returns the MP4 content.
+func (w *Writer) Bytes() []byte {
+ return w.buf.Bytes()
+}