move shared MP4 entities inside internal/mp4 (#201)

This commit is contained in:
Alessandro Ros
2025-05-21 18:40:13 +02:00
committed by GitHub
parent 27b8b3d506
commit 5218285d45
11 changed files with 291 additions and 371 deletions

View File

@@ -6,6 +6,7 @@ import (
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/av1"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
@@ -13,21 +14,6 @@ import (
"github.com/bluenviron/mediacommon/v2/pkg/formats/mp4"
)
// Specification: ISO 14496-1, Table 5
const (
objectTypeIndicationVisualISO14496part2 = 0x20
objectTypeIndicationAudioISO14496part3 = 0x40
objectTypeIndicationVisualISO1318part2Main = 0x61
objectTypeIndicationAudioISO11172part3 = 0x6B
objectTypeIndicationVisualISO10918part1 = 0x6C
)
// Specification: ISO 14496-1, Table 6
const (
streamTypeVisualStream = 0x04
streamTypeAudioStream = 0x05
)
func av1FindSequenceHeader(buf []byte) ([]byte, error) {
var tu av1.Bitstream
err := tu.Unmarshal(buf)
@@ -441,7 +427,7 @@ func (i *Init) Unmarshal(r io.ReadSeeker) error {
switch state {
case waitingVideoEsds:
switch conf.ObjectTypeIndication {
case objectTypeIndicationVisualISO14496part2:
case imp4.ObjectTypeIndicationVisualISO14496part2:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -451,7 +437,7 @@ func (i *Init) Unmarshal(r io.ReadSeeker) error {
Config: spec,
}
case objectTypeIndicationVisualISO1318part2Main:
case imp4.ObjectTypeIndicationVisualISO1318part2Main:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -461,7 +447,7 @@ func (i *Init) Unmarshal(r io.ReadSeeker) error {
Config: spec,
}
case objectTypeIndicationVisualISO10918part1:
case imp4.ObjectTypeIndicationVisualISO10918part1:
if width == 0 || height == 0 {
return nil, fmt.Errorf("M-JPEG parameters not provided")
}
@@ -479,7 +465,7 @@ func (i *Init) Unmarshal(r io.ReadSeeker) error {
case waitingAudioEsds:
switch conf.ObjectTypeIndication {
case objectTypeIndicationAudioISO14496part3:
case imp4.ObjectTypeIndicationAudioISO14496part3:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -495,7 +481,7 @@ func (i *Init) Unmarshal(r io.ReadSeeker) error {
Config: c,
}
case objectTypeIndicationAudioISO11172part3:
case imp4.ObjectTypeIndicationAudioISO11172part3:
curTrack.Codec = &mp4.CodecMPEG1Audio{
SampleRate: sampleRate,
ChannelCount: channelCount,
@@ -619,9 +605,10 @@ func (i *Init) Marshal(w io.WriteSeeker) error {
| | |....|
*/
mw := newMP4Writer(w)
mw := &imp4.Writer{W: w}
mw.Initialize()
_, err := mw.writeBox(&amp4.Ftyp{ // <ftyp/>
_, err := mw.WriteBox(&amp4.Ftyp{ // <ftyp/>
MajorBrand: [4]byte{'m', 'p', '4', '2'},
MinorVersion: 1,
CompatibleBrands: []amp4.CompatibleBrandElem{
@@ -635,12 +622,12 @@ func (i *Init) Marshal(w io.WriteSeeker) error {
return err
}
_, err = mw.writeBoxStart(&amp4.Moov{}) // <moov>
_, err = mw.WriteBoxStart(&amp4.Moov{}) // <moov>
if err != nil {
return err
}
_, err = mw.writeBox(&amp4.Mvhd{ // <mvhd/>
_, err = mw.WriteBox(&amp4.Mvhd{ // <mvhd/>
Timescale: 1000,
Rate: 65536,
Volume: 256,
@@ -658,13 +645,13 @@ func (i *Init) Marshal(w io.WriteSeeker) error {
}
}
_, err = mw.writeBoxStart(&amp4.Mvex{}) // <mvex>
_, err = mw.WriteBoxStart(&amp4.Mvex{}) // <mvex>
if err != nil {
return err
}
for _, track := range i.Tracks {
_, err = mw.writeBox(&amp4.Trex{ // <trex/>
_, err = mw.WriteBox(&amp4.Trex{ // <trex/>
TrackID: uint32(track.ID),
DefaultSampleDescriptionIndex: 1,
})
@@ -673,12 +660,12 @@ func (i *Init) Marshal(w io.WriteSeeker) error {
}
}
err = mw.writeBoxEnd() // </mvex>
err = mw.WriteBoxEnd() // </mvex>
if err != nil {
return err
}
err = mw.writeBoxEnd() // </moov>
err = mw.WriteBoxEnd() // </moov>
if err != nil {
return err
}

View File

@@ -5,6 +5,7 @@ import (
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/av1"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
@@ -38,7 +39,7 @@ type InitTrack struct {
Codec mp4.Codec
}
func (it *InitTrack) marshal(w *mp4Writer) error {
func (it *InitTrack) marshal(w *imp4.Writer) error {
/*
|trak|
| |tkhd|
@@ -86,7 +87,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
| | | | |stco|
*/
_, err := w.writeBoxStart(&amp4.Trak{}) // <trak>
_, err := w.WriteBoxStart(&amp4.Trak{}) // <trak>
if err != nil {
return err
}
@@ -173,7 +174,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
if it.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Tkhd{ // <tkhd/>
_, err = w.WriteBox(&amp4.Tkhd{ // <tkhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
@@ -186,7 +187,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
} else {
_, err = w.writeBox(&amp4.Tkhd{ // <tkhd/>
_, err = w.WriteBox(&amp4.Tkhd{ // <tkhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
@@ -200,12 +201,12 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
}
_, err = w.writeBoxStart(&amp4.Mdia{}) // <mdia>
_, err = w.WriteBoxStart(&amp4.Mdia{}) // <mdia>
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Mdhd{ // <mdhd/>
_, err = w.WriteBox(&amp4.Mdhd{ // <mdhd/>
Timescale: it.TimeScale,
Language: [3]byte{'u', 'n', 'd'},
})
@@ -214,7 +215,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
if it.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Hdlr{ // <hdlr/>
_, err = w.WriteBox(&amp4.Hdlr{ // <hdlr/>
HandlerType: [4]byte{'v', 'i', 'd', 'e'},
Name: "VideoHandler",
})
@@ -222,7 +223,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
} else {
_, err = w.writeBox(&amp4.Hdlr{ // <hdlr/>
_, err = w.WriteBox(&amp4.Hdlr{ // <hdlr/>
HandlerType: [4]byte{'s', 'o', 'u', 'n'},
Name: "SoundHandler",
})
@@ -231,13 +232,13 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
}
_, err = w.writeBoxStart(&amp4.Minf{}) // <minf>
_, err = w.WriteBoxStart(&amp4.Minf{}) // <minf>
if err != nil {
return err
}
if it.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Vmhd{ // <vmhd/>
_, err = w.WriteBox(&amp4.Vmhd{ // <vmhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
@@ -246,25 +247,25 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
} else {
_, err = w.writeBox(&amp4.Smhd{}) // <smhd/>
_, err = w.WriteBox(&amp4.Smhd{}) // <smhd/>
if err != nil {
return err
}
}
_, err = w.writeBoxStart(&amp4.Dinf{}) // <dinf>
_, err = w.WriteBoxStart(&amp4.Dinf{}) // <dinf>
if err != nil {
return err
}
_, err = w.writeBoxStart(&amp4.Dref{ // <dref>
_, err = w.WriteBoxStart(&amp4.Dref{ // <dref>
EntryCount: 1,
})
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Url{ // <url/>
_, err = w.WriteBox(&amp4.Url{ // <url/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
@@ -273,22 +274,22 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
err = w.writeBoxEnd() // </dref>
err = w.WriteBoxEnd() // </dref>
if err != nil {
return err
}
err = w.writeBoxEnd() // </dinf>
err = w.WriteBoxEnd() // </dinf>
if err != nil {
return err
}
_, err = w.writeBoxStart(&amp4.Stbl{}) // <stbl>
_, err = w.WriteBoxStart(&amp4.Stbl{}) // <stbl>
if err != nil {
return err
}
_, err = w.writeBoxStart(&amp4.Stsd{ // <stsd>
_, err = w.WriteBoxStart(&amp4.Stsd{ // <stsd>
EntryCount: 1,
})
if err != nil {
@@ -315,7 +316,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
switch codec := it.Codec.(type) {
case *mp4.CodecAV1:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <av01>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <av01>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAv01(),
@@ -340,7 +341,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Av1C{ // <av1C/>
_, err = w.WriteBox(&amp4.Av1C{ // <av1C/>
Marker: 1,
Version: 1,
SeqProfile: av1SequenceHeader.SeqProfile,
@@ -359,7 +360,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecVP9:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <vp09>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <vp09>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeVp09(),
@@ -378,7 +379,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.VpcC{ // <vpcC/>
_, err = w.WriteBox(&amp4.VpcC{ // <vpcC/>
FullBox: amp4.FullBox{
Version: 1,
},
@@ -393,7 +394,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecH265:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <hev1>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <hev1>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeHev1(),
@@ -412,7 +413,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.HvcC{ // <hvcC/>
_, err = w.WriteBox(&amp4.HvcC{ // <hvcC/>
ConfigurationVersion: 1,
GeneralProfileIdc: h265SPS.ProfileTierLevel.GeneralProfileIdc,
GeneralProfileCompatibility: h265SPS.ProfileTierLevel.GeneralProfileCompatibilityFlag,
@@ -464,7 +465,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecH264:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <avc1>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <avc1>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAvc1(),
@@ -483,7 +484,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.AVCDecoderConfiguration{ // <avcc/>
_, err = w.WriteBox(&amp4.AVCDecoderConfiguration{ // <avcc/>
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAvcC(),
},
@@ -512,7 +513,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecMPEG4Video: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -531,7 +532,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -544,8 +545,8 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(codec.Config)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO14496part2,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO14496part2,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
@@ -568,7 +569,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecMPEG1Video: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -587,7 +588,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -600,8 +601,8 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(codec.Config)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO1318part2Main,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO1318part2Main,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
@@ -624,7 +625,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecMJPEG: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -643,7 +644,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -656,8 +657,8 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
Tag: amp4.DecoderConfigDescrTag,
Size: 13,
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO10918part1,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO10918part1,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
@@ -675,7 +676,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecOpus:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <Opus>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <Opus>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeOpus(),
@@ -690,7 +691,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.DOps{ // <dOps/>
_, err = w.WriteBox(&amp4.DOps{ // <dOps/>
OutputChannelCount: uint8(codec.ChannelCount),
PreSkip: 312,
InputSampleRate: 48000,
@@ -700,7 +701,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecMPEG4Audio:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4a(),
@@ -717,7 +718,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
enc, _ := codec.Config.Marshal()
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -730,8 +731,8 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(enc)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationAudioISO14496part3,
StreamType: streamTypeAudioStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationAudioISO14496part3,
StreamType: imp4.StreamTypeAudioStream,
Reserved: true,
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
@@ -754,7 +755,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecMPEG1Audio:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4a(),
@@ -769,7 +770,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -782,8 +783,8 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
Tag: amp4.DecoderConfigDescrTag,
Size: 13,
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationAudioISO11172part3,
StreamType: streamTypeAudioStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationAudioISO11172part3,
StreamType: imp4.StreamTypeAudioStream,
Reserved: true,
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
@@ -801,7 +802,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecAC3:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <ac-3>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <ac-3>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAC3(),
@@ -816,7 +817,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.Dac3{ // <dac3/>
_, err = w.WriteBox(&amp4.Dac3{ // <dac3/>
Fscod: codec.Fscod,
Bsid: codec.Bsid,
Bsmod: codec.Bsmod,
@@ -834,7 +835,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
case *mp4.CodecLPCM:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <ipcm>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <ipcm>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeIpcm(),
@@ -849,7 +850,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
_, err = w.writeBox(&amp4.PcmC{ // <pcmC/>
_, err = w.WriteBox(&amp4.PcmC{ // <pcmC/>
FormatFlags: func() uint8 {
if codec.LittleEndian {
return 1
@@ -863,7 +864,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
}
}
_, err = w.writeBox(&amp4.Btrt{ // <btrt/>
_, err = w.WriteBox(&amp4.Btrt{ // <btrt/>
MaxBitrate: maxBitrate,
AvgBitrate: avgBitrate,
})
@@ -871,56 +872,56 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
return err
}
err = w.writeBoxEnd() // </*>
err = w.WriteBoxEnd() // </*>
if err != nil {
return err
}
err = w.writeBoxEnd() // </stsd>
err = w.WriteBoxEnd() // </stsd>
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Stts{ // <stts/>
_, err = w.WriteBox(&amp4.Stts{ // <stts/>
})
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Stsc{ // <stsc/>
_, err = w.WriteBox(&amp4.Stsc{ // <stsc/>
})
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Stsz{ // <stsz/>
_, err = w.WriteBox(&amp4.Stsz{ // <stsz/>
})
if err != nil {
return err
}
_, err = w.writeBox(&amp4.Stco{ // <stco/>
_, err = w.WriteBox(&amp4.Stco{ // <stco/>
})
if err != nil {
return err
}
err = w.writeBoxEnd() // </stbl>
err = w.WriteBoxEnd() // </stbl>
if err != nil {
return err
}
err = w.writeBoxEnd() // </minf>
err = w.WriteBoxEnd() // </minf>
if err != nil {
return err
}
err = w.writeBoxEnd() // </mdia>
err = w.WriteBoxEnd() // </mdia>
if err != nil {
return err
}
err = w.writeBoxEnd() // </trak>
err = w.WriteBoxEnd() // </trak>
if err != nil {
return err
}

View File

@@ -1,83 +0,0 @@
package fmp4
import (
"io"
amp4 "github.com/abema/go-mp4"
)
type mp4Writer struct {
w *amp4.Writer
}
func newMP4Writer(w io.WriteSeeker) *mp4Writer {
return &mp4Writer{
w: amp4.NewWriter(w),
}
}
func (w *mp4Writer) writeBoxStart(box amp4.IImmutableBox) (int, error) {
bi := &amp4.BoxInfo{
Type: box.GetType(),
}
var err error
bi, err = w.w.StartBox(bi)
if err != nil {
return 0, err
}
_, err = amp4.Marshal(w.w, box, amp4.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 amp4.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 amp4.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
}

View File

@@ -4,6 +4,7 @@ import (
"io"
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
)
const (
@@ -33,14 +34,15 @@ func (p *Part) Marshal(w io.WriteSeeker) error {
|mdat|
*/
mw := newMP4Writer(w)
mw := &imp4.Writer{W: w}
mw.Initialize()
moofOffset, err := mw.writeBoxStart(&amp4.Moof{}) // <moof>
moofOffset, err := mw.WriteBoxStart(&amp4.Moof{}) // <moof>
if err != nil {
return err
}
_, err = mw.writeBox(&amp4.Mfhd{ // <mfhd/>
_, err = mw.WriteBox(&amp4.Mfhd{ // <mfhd/>
SequenceNumber: p.SequenceNumber,
})
if err != nil {
@@ -71,7 +73,7 @@ func (p *Part) Marshal(w io.WriteSeeker) error {
trunOffsets[i] = trunOffset
}
err = mw.writeBoxEnd() // </moof>
err = mw.WriteBoxEnd() // </moof>
if err != nil {
return err
}
@@ -86,14 +88,14 @@ func (p *Part) Marshal(w io.WriteSeeker) error {
}
}
mdatOffset, err := mw.writeBox(mdat)
mdatOffset, err := mw.WriteBox(mdat)
if err != nil {
return err
}
for i := range p.Tracks {
truns[i].DataOffset = int32(dataOffsets[i] + mdatOffset - moofOffset + 8)
err = mw.rewriteBox(trunOffsets[i], truns[i])
err = mw.RewriteBox(trunOffsets[i], truns[i])
if err != nil {
return err
}

View File

@@ -2,6 +2,7 @@ package fmp4
import (
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
)
// PartTrack is a track of Part.
@@ -11,7 +12,7 @@ type PartTrack struct {
Samples []*Sample
}
func (pt *PartTrack) marshal(w *mp4Writer) (*amp4.Trun, int, error) {
func (pt *PartTrack) marshal(w *imp4.Writer) (*amp4.Trun, int, error) {
/*
|traf|
| |tfhd|
@@ -19,14 +20,14 @@ func (pt *PartTrack) marshal(w *mp4Writer) (*amp4.Trun, int, error) {
| |trun|
*/
_, err := w.writeBoxStart(&amp4.Traf{}) // <traf>
_, err := w.WriteBoxStart(&amp4.Traf{}) // <traf>
if err != nil {
return nil, 0, err
}
flags := 0
_, err = w.writeBox(&amp4.Tfhd{ // <tfhd/>
_, err = w.WriteBox(&amp4.Tfhd{ // <tfhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{2, byte(flags >> 8), byte(flags)},
},
@@ -36,7 +37,7 @@ func (pt *PartTrack) marshal(w *mp4Writer) (*amp4.Trun, int, error) {
return nil, 0, err
}
_, err = w.writeBox(&amp4.Tfdt{ // <tfdt/>
_, err = w.WriteBox(&amp4.Tfdt{ // <tfdt/>
FullBox: amp4.FullBox{
Version: 1,
},
@@ -82,12 +83,12 @@ func (pt *PartTrack) marshal(w *mp4Writer) (*amp4.Trun, int, error) {
})
}
trunOffset, err := w.writeBox(trun)
trunOffset, err := w.WriteBox(trun)
if err != nil {
return nil, 0, err
}
err = w.writeBoxEnd() // </traf>
err = w.WriteBoxEnd() // </traf>
if err != nil {
return nil, 0, err
}

View File

@@ -1,83 +0,0 @@
package pmp4
import (
"io"
amp4 "github.com/abema/go-mp4"
)
type mp4Writer struct {
w *amp4.Writer
}
func newMP4Writer(w io.WriteSeeker) *mp4Writer {
return &mp4Writer{
w: amp4.NewWriter(w),
}
}
func (w *mp4Writer) writeBoxStart(box amp4.IImmutableBox) (int, error) {
bi := &amp4.BoxInfo{
Type: box.GetType(),
}
var err error
bi, err = w.w.StartBox(bi)
if err != nil {
return 0, err
}
_, err = amp4.Marshal(w.w, box, amp4.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 amp4.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 amp4.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
}

View File

@@ -8,6 +8,7 @@ import (
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/av1"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
@@ -478,7 +479,7 @@ func (p *Presentation) Unmarshal(r io.ReadSeeker) error {
switch state {
case waitingVideoEsds:
switch conf.ObjectTypeIndication {
case objectTypeIndicationVisualISO14496part2:
case imp4.ObjectTypeIndicationVisualISO14496part2:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -488,7 +489,7 @@ func (p *Presentation) Unmarshal(r io.ReadSeeker) error {
Config: spec,
}
case objectTypeIndicationVisualISO1318part2Main:
case imp4.ObjectTypeIndicationVisualISO1318part2Main:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -498,7 +499,7 @@ func (p *Presentation) Unmarshal(r io.ReadSeeker) error {
Config: spec,
}
case objectTypeIndicationVisualISO10918part1:
case imp4.ObjectTypeIndicationVisualISO10918part1:
if width == 0 || height == 0 {
return nil, fmt.Errorf("M-JPEG parameters not provided")
}
@@ -516,7 +517,7 @@ func (p *Presentation) Unmarshal(r io.ReadSeeker) error {
case waitingAudioEsds:
switch conf.ObjectTypeIndication {
case objectTypeIndicationAudioISO14496part3:
case imp4.ObjectTypeIndicationAudioISO14496part3:
spec := esdsFindDecoderSpecificInfo(esds.Descriptors)
if len(spec) == 0 {
return nil, fmt.Errorf("unable to find decoder specific info")
@@ -532,7 +533,7 @@ func (p *Presentation) Unmarshal(r io.ReadSeeker) error {
Config: c,
}
case objectTypeIndicationAudioISO11172part3:
case imp4.ObjectTypeIndicationAudioISO11172part3:
curTrack.Codec = &mp4.CodecMPEG1Audio{
SampleRate: sampleRate,
ChannelCount: channelCount,
@@ -922,9 +923,10 @@ func (p *Presentation) sortSamples() (uint32, []*Sample) {
func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
var outBuf seekablebuffer.Buffer
mw := newMP4Writer(&outBuf)
mw := &imp4.Writer{W: &outBuf}
mw.Initialize()
_, err := mw.writeBox(&amp4.Ftyp{ // <ftyp/>
_, err := mw.WriteBox(&amp4.Ftyp{ // <ftyp/>
MajorBrand: [4]byte{'i', 's', 'o', 'm'},
MinorVersion: 1,
CompatibleBrands: []amp4.CompatibleBrandElem{
@@ -938,7 +940,7 @@ func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
return err
}
_, err = mw.writeBoxStart(&amp4.Moov{}) // <moov>
_, err = mw.WriteBoxStart(&amp4.Moov{}) // <moov>
if err != nil {
return err
}
@@ -950,7 +952,7 @@ func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
Matrix: [9]int32{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000},
NextTrackID: uint32(len(p.Tracks) + 1),
}
mvhdOffset, err := mw.writeBox(mvhd)
mvhdOffset, err := mw.WriteBox(mvhd)
if err != nil {
return err
}
@@ -973,12 +975,12 @@ func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
}
}
err = mw.rewriteBox(mvhdOffset, mvhd)
err = mw.RewriteBox(mvhdOffset, mvhd)
if err != nil {
return err
}
err = mw.writeBoxEnd() // </moov>
err = mw.WriteBoxEnd() // </moov>
if err != nil {
return err
}
@@ -995,7 +997,7 @@ func (p *Presentation) marshalFtypAndMoov(w io.Writer) error {
stcos[i].ChunkOffset[j] += uint32(dataOffset)
}
err = mw.rewriteBox(stcosOffsets[i], stcos[i])
err = mw.RewriteBox(stcosOffsets[i], stcos[i])
if err != nil {
return err
}

View File

@@ -5,27 +5,13 @@ import (
amp4 "github.com/abema/go-mp4"
imp4 "github.com/bluenviron/mediacommon/v2/internal/mp4"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/av1"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
"github.com/bluenviron/mediacommon/v2/pkg/formats/mp4"
)
// Specification: ISO 14496-1, Table 5
const (
objectTypeIndicationVisualISO14496part2 = 0x20
objectTypeIndicationAudioISO14496part3 = 0x40
objectTypeIndicationVisualISO1318part2Main = 0x61
objectTypeIndicationAudioISO11172part3 = 0x6B
objectTypeIndicationVisualISO10918part1 = 0x6C
)
// Specification: ISO 14496-1, Table 6
const (
streamTypeVisualStream = 0x04
streamTypeAudioStream = 0x05
)
func boolToUint8(v bool) uint8 {
if v {
return 1
@@ -57,7 +43,7 @@ type Track struct {
Samples []*Sample
}
func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
func (t *Track) marshal(w *imp4.Writer) (*headerTrackMarshalResult, error) {
/*
|trak|
| |tkhd|
@@ -100,7 +86,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
| | | | |stco|
*/
_, err := w.writeBoxStart(&amp4.Trak{}) // <trak>
_, err := w.WriteBoxStart(&amp4.Trak{}) // <trak>
if err != nil {
return nil, err
}
@@ -194,7 +180,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
presentationDuration := uint32(((int64(sampleDuration) + int64(t.TimeOffset)) * globalTimescale) / int64(t.TimeScale))
if t.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Tkhd{ // <tkhd/>
_, err = w.WriteBox(&amp4.Tkhd{ // <tkhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
@@ -208,7 +194,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
} else {
_, err = w.writeBox(&amp4.Tkhd{ // <tkhd/>
_, err = w.WriteBox(&amp4.Tkhd{ // <tkhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 3},
},
@@ -223,7 +209,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
}
_, err = w.writeBoxStart(&amp4.Edts{}) // <edts>
_, err = w.WriteBoxStart(&amp4.Edts{}) // <edts>
if err != nil {
return nil, err
}
@@ -233,17 +219,17 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
err = w.writeBoxEnd() // </edts>
err = w.WriteBoxEnd() // </edts>
if err != nil {
return nil, err
}
_, err = w.writeBoxStart(&amp4.Mdia{}) // <mdia>
_, err = w.WriteBoxStart(&amp4.Mdia{}) // <mdia>
if err != nil {
return nil, err
}
_, err = w.writeBox(&amp4.Mdhd{ // <mdhd/>
_, err = w.WriteBox(&amp4.Mdhd{ // <mdhd/>
Timescale: t.TimeScale,
DurationV0: uint32(int64(sampleDuration) + int64(t.TimeOffset)),
Language: [3]byte{'u', 'n', 'd'},
@@ -253,7 +239,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
if t.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Hdlr{ // <hdlr/>
_, err = w.WriteBox(&amp4.Hdlr{ // <hdlr/>
HandlerType: [4]byte{'v', 'i', 'd', 'e'},
Name: "VideoHandler",
})
@@ -261,7 +247,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
} else {
_, err = w.writeBox(&amp4.Hdlr{ // <hdlr/>
_, err = w.WriteBox(&amp4.Hdlr{ // <hdlr/>
HandlerType: [4]byte{'s', 'o', 'u', 'n'},
Name: "SoundHandler",
})
@@ -270,13 +256,13 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
}
_, err = w.writeBoxStart(&amp4.Minf{}) // <minf>
_, err = w.WriteBoxStart(&amp4.Minf{}) // <minf>
if err != nil {
return nil, err
}
if t.Codec.IsVideo() {
_, err = w.writeBox(&amp4.Vmhd{ // <vmhd/>
_, err = w.WriteBox(&amp4.Vmhd{ // <vmhd/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
@@ -285,25 +271,25 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
} else {
_, err = w.writeBox(&amp4.Smhd{}) // <smhd/>
_, err = w.WriteBox(&amp4.Smhd{}) // <smhd/>
if err != nil {
return nil, err
}
}
_, err = w.writeBoxStart(&amp4.Dinf{}) // <dinf>
_, err = w.WriteBoxStart(&amp4.Dinf{}) // <dinf>
if err != nil {
return nil, err
}
_, err = w.writeBoxStart(&amp4.Dref{ // <dref>
_, err = w.WriteBoxStart(&amp4.Dref{ // <dref>
EntryCount: 1,
})
if err != nil {
return nil, err
}
_, err = w.writeBox(&amp4.Url{ // <url/>
_, err = w.WriteBox(&amp4.Url{ // <url/>
FullBox: amp4.FullBox{
Flags: [3]byte{0, 0, 1},
},
@@ -312,22 +298,22 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
err = w.writeBoxEnd() // </dref>
err = w.WriteBoxEnd() // </dref>
if err != nil {
return nil, err
}
err = w.writeBoxEnd() // </dinf>
err = w.WriteBoxEnd() // </dinf>
if err != nil {
return nil, err
}
_, err = w.writeBoxStart(&amp4.Stbl{}) // <stbl>
_, err = w.WriteBoxStart(&amp4.Stbl{}) // <stbl>
if err != nil {
return nil, err
}
_, err = w.writeBoxStart(&amp4.Stsd{ // <stsd>
_, err = w.WriteBoxStart(&amp4.Stsd{ // <stsd>
EntryCount: 1,
})
if err != nil {
@@ -336,7 +322,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
switch codec := t.Codec.(type) {
case *mp4.CodecAV1:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <av01>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <av01>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAv01(),
@@ -361,7 +347,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Av1C{ // <av1C/>
_, err = w.WriteBox(&amp4.Av1C{ // <av1C/>
Marker: 1,
Version: 1,
SeqProfile: av1SequenceHeader.SeqProfile,
@@ -380,7 +366,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecVP9:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <vp09>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <vp09>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeVp09(),
@@ -399,7 +385,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.VpcC{ // <vpcC/>
_, err = w.WriteBox(&amp4.VpcC{ // <vpcC/>
FullBox: amp4.FullBox{
Version: 1,
},
@@ -414,7 +400,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecH265:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <hev1>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <hev1>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeHev1(),
@@ -433,7 +419,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.HvcC{ // <hvcC/>
_, err = w.WriteBox(&amp4.HvcC{ // <hvcC/>
ConfigurationVersion: 1,
GeneralProfileIdc: h265SPS.ProfileTierLevel.GeneralProfileIdc,
GeneralProfileCompatibility: h265SPS.ProfileTierLevel.GeneralProfileCompatibilityFlag,
@@ -485,7 +471,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecH264:
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <avc1>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <avc1>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAvc1(),
@@ -504,7 +490,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.AVCDecoderConfiguration{ // <avcc/>
_, err = w.WriteBox(&amp4.AVCDecoderConfiguration{ // <avcc/>
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAvcC(),
},
@@ -533,7 +519,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecMPEG4Video: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -552,7 +538,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -565,8 +551,8 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(codec.Config)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO14496part2,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO14496part2,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: 1000000,
AvgBitrate: 1000000,
@@ -589,7 +575,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecMPEG1Video: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -608,7 +594,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -621,8 +607,8 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(codec.Config)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO1318part2Main,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO1318part2Main,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: 1000000,
AvgBitrate: 1000000,
@@ -645,7 +631,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecMJPEG: //nolint:dupl
_, err = w.writeBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
_, err = w.WriteBoxStart(&amp4.VisualSampleEntry{ // <mp4v>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4v(),
@@ -664,7 +650,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -677,8 +663,8 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
Tag: amp4.DecoderConfigDescrTag,
Size: 13,
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationVisualISO10918part1,
StreamType: streamTypeVisualStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationVisualISO10918part1,
StreamType: imp4.StreamTypeVisualStream,
Reserved: true,
MaxBitrate: 1000000,
AvgBitrate: 1000000,
@@ -696,7 +682,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecOpus:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <Opus>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <Opus>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeOpus(),
@@ -711,7 +697,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.DOps{ // <dOps/>
_, err = w.WriteBox(&amp4.DOps{ // <dOps/>
OutputChannelCount: uint8(codec.ChannelCount),
PreSkip: 312,
InputSampleRate: 48000,
@@ -721,7 +707,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecMPEG4Audio:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4a(),
@@ -738,7 +724,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
enc, _ := codec.Config.Marshal()
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -751,8 +737,8 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
Tag: amp4.DecoderConfigDescrTag,
Size: 18 + uint32(len(enc)),
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationAudioISO14496part3,
StreamType: streamTypeAudioStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationAudioISO14496part3,
StreamType: imp4.StreamTypeAudioStream,
Reserved: true,
MaxBitrate: 128825,
AvgBitrate: 128825,
@@ -775,7 +761,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecMPEG1Audio:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <mp4a>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeMp4a(),
@@ -790,7 +776,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Esds{ // <esds/>
_, err = w.WriteBox(&amp4.Esds{ // <esds/>
Descriptors: []amp4.Descriptor{
{
Tag: amp4.ESDescrTag,
@@ -803,8 +789,8 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
Tag: amp4.DecoderConfigDescrTag,
Size: 13,
DecoderConfigDescriptor: &amp4.DecoderConfigDescriptor{
ObjectTypeIndication: objectTypeIndicationAudioISO11172part3,
StreamType: streamTypeAudioStream,
ObjectTypeIndication: imp4.ObjectTypeIndicationAudioISO11172part3,
StreamType: imp4.StreamTypeAudioStream,
Reserved: true,
MaxBitrate: 128825,
AvgBitrate: 128825,
@@ -822,7 +808,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecAC3:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <ac-3>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <ac-3>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeAC3(),
@@ -837,7 +823,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.Dac3{ // <dac3/>
_, err = w.WriteBox(&amp4.Dac3{ // <dac3/>
Fscod: codec.Fscod,
Bsid: codec.Bsid,
Bsmod: codec.Bsmod,
@@ -855,7 +841,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
case *mp4.CodecLPCM:
_, err = w.writeBoxStart(&amp4.AudioSampleEntry{ // <ipcm>
_, err = w.WriteBoxStart(&amp4.AudioSampleEntry{ // <ipcm>
SampleEntry: amp4.SampleEntry{
AnyTypeBox: amp4.AnyTypeBox{
Type: amp4.BoxTypeIpcm(),
@@ -870,7 +856,7 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
_, err = w.writeBox(&amp4.PcmC{ // <pcmC/>
_, err = w.WriteBox(&amp4.PcmC{ // <pcmC/>
FormatFlags: func() uint8 {
if codec.LittleEndian {
return 1
@@ -884,12 +870,12 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}
}
err = w.writeBoxEnd() // </*>
err = w.WriteBoxEnd() // </*>
if err != nil {
return nil, err
}
err = w.writeBoxEnd() // </stsd>
err = w.WriteBoxEnd() // </stsd>
if err != nil {
return nil, err
}
@@ -924,22 +910,22 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
return nil, err
}
err = w.writeBoxEnd() // </stbl>
err = w.WriteBoxEnd() // </stbl>
if err != nil {
return nil, err
}
err = w.writeBoxEnd() // </minf>
err = w.WriteBoxEnd() // </minf>
if err != nil {
return nil, err
}
err = w.writeBoxEnd() // </mdia>
err = w.WriteBoxEnd() // </mdia>
if err != nil {
return nil, err
}
err = w.writeBoxEnd() // </trak>
err = w.WriteBoxEnd() // </trak>
if err != nil {
return nil, err
}
@@ -951,9 +937,9 @@ func (t *Track) marshal(w *mp4Writer) (*headerTrackMarshalResult, error) {
}, nil
}
func (t *Track) marshalELST(w *mp4Writer, sampleDuration uint32) error {
func (t *Track) marshalELST(w *imp4.Writer, sampleDuration uint32) error {
if t.TimeOffset > 0 {
_, err := w.writeBox(&amp4.Elst{
_, err := w.WriteBox(&amp4.Elst{
EntryCount: 2,
Entries: []amp4.ElstEntry{
{ // pause
@@ -973,7 +959,7 @@ func (t *Track) marshalELST(w *mp4Writer, sampleDuration uint32) error {
return err
}
_, err := w.writeBox(&amp4.Elst{
_, err := w.WriteBox(&amp4.Elst{
EntryCount: 1,
Entries: []amp4.ElstEntry{{
SegmentDurationV0: uint32(((uint64(sampleDuration) +
@@ -986,7 +972,7 @@ func (t *Track) marshalELST(w *mp4Writer, sampleDuration uint32) error {
return err
}
func (t *Track) marshalSTTS(w *mp4Writer) error {
func (t *Track) marshalSTTS(w *imp4.Writer) error {
entries := []amp4.SttsEntry{{
SampleCount: 1,
SampleDelta: t.Samples[0].Duration,
@@ -1003,14 +989,14 @@ func (t *Track) marshalSTTS(w *mp4Writer) error {
}
}
_, err := w.writeBox(&amp4.Stts{
_, err := w.WriteBox(&amp4.Stts{
EntryCount: uint32(len(entries)),
Entries: entries,
})
return err
}
func (t *Track) marshalSTSS(w *mp4Writer) error {
func (t *Track) marshalSTSS(w *imp4.Writer) error {
// ISO 14496-12 2015:
// "If the sync sample box is not present, every sample is a sync sample."
if allSamplesAreSync(t.Samples) {
@@ -1025,14 +1011,14 @@ func (t *Track) marshalSTSS(w *mp4Writer) error {
}
}
_, err := w.writeBox(&amp4.Stss{
_, err := w.WriteBox(&amp4.Stss{
EntryCount: uint32(len(sampleNumbers)),
SampleNumber: sampleNumbers,
})
return err
}
func (t *Track) marshalCTTS(w *mp4Writer) error {
func (t *Track) marshalCTTS(w *imp4.Writer) error {
entries := []amp4.CttsEntry{{
SampleCount: 1,
SampleOffsetV1: t.Samples[0].PTSOffset,
@@ -1049,7 +1035,7 @@ func (t *Track) marshalCTTS(w *mp4Writer) error {
}
}
_, err := w.writeBox(&amp4.Ctts{
_, err := w.WriteBox(&amp4.Ctts{
FullBox: amp4.FullBox{
Version: 1,
},
@@ -1059,7 +1045,7 @@ func (t *Track) marshalCTTS(w *mp4Writer) error {
return err
}
func (t *Track) marshalSTSC(w *mp4Writer) error {
func (t *Track) marshalSTSC(w *imp4.Writer) error {
entries := []amp4.StscEntry{{
FirstChunk: 1,
SamplesPerChunk: 1,
@@ -1093,21 +1079,21 @@ func (t *Track) marshalSTSC(w *mp4Writer) error {
}
}
_, err := w.writeBox(&amp4.Stsc{
_, err := w.WriteBox(&amp4.Stsc{
EntryCount: uint32(len(entries)),
Entries: entries,
})
return err
}
func (t *Track) marshalSTSZ(w *mp4Writer) error {
func (t *Track) marshalSTSZ(w *imp4.Writer) error {
sampleSizes := make([]uint32, len(t.Samples))
for i, sa := range t.Samples {
sampleSizes[i] = sa.PayloadSize
}
_, err := w.writeBox(&amp4.Stsz{
_, err := w.WriteBox(&amp4.Stsz{
SampleSize: 0,
SampleCount: uint32(len(sampleSizes)),
EntrySize: sampleSizes,
@@ -1115,7 +1101,7 @@ func (t *Track) marshalSTSZ(w *mp4Writer) error {
return err
}
func (t *Track) marshalSTCO(w *mp4Writer) (*amp4.Stco, int, error) {
func (t *Track) marshalSTCO(w *imp4.Writer) (*amp4.Stco, int, error) {
firstSample := t.Samples[0]
off := firstSample.offset + firstSample.PayloadSize
@@ -1133,7 +1119,7 @@ func (t *Track) marshalSTCO(w *mp4Writer) (*amp4.Stco, int, error) {
ChunkOffset: entries,
}
offset, err := w.writeBox(stco)
offset, err := w.WriteBox(stco)
if err != nil {
return nil, 0, err
}