mirror of
https://github.com/bluenviron/mediacommon.git
synced 2025-12-24 13:17:52 +08:00
move shared MP4 entities inside internal/mp4 (#201)
This commit is contained in:
@@ -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(&4.Ftyp{ // <ftyp/>
|
||||
_, err := mw.WriteBox(&4.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(&4.Moov{}) // <moov>
|
||||
_, err = mw.WriteBoxStart(&4.Moov{}) // <moov>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = mw.writeBox(&4.Mvhd{ // <mvhd/>
|
||||
_, err = mw.WriteBox(&4.Mvhd{ // <mvhd/>
|
||||
Timescale: 1000,
|
||||
Rate: 65536,
|
||||
Volume: 256,
|
||||
@@ -658,13 +645,13 @@ func (i *Init) Marshal(w io.WriteSeeker) error {
|
||||
}
|
||||
}
|
||||
|
||||
_, err = mw.writeBoxStart(&4.Mvex{}) // <mvex>
|
||||
_, err = mw.WriteBoxStart(&4.Mvex{}) // <mvex>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, track := range i.Tracks {
|
||||
_, err = mw.writeBox(&4.Trex{ // <trex/>
|
||||
_, err = mw.WriteBox(&4.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
|
||||
}
|
||||
|
||||
@@ -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(&4.Trak{}) // <trak>
|
||||
_, err := w.WriteBoxStart(&4.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(&4.Tkhd{ // <tkhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Tkhd{ // <tkhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Mdia{}) // <mdia>
|
||||
_, err = w.WriteBoxStart(&4.Mdia{}) // <mdia>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Mdhd{ // <mdhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Hdlr{ // <hdlr/>
|
||||
_, err = w.WriteBox(&4.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(&4.Hdlr{ // <hdlr/>
|
||||
_, err = w.WriteBox(&4.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(&4.Minf{}) // <minf>
|
||||
_, err = w.WriteBoxStart(&4.Minf{}) // <minf>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if it.Codec.IsVideo() {
|
||||
_, err = w.writeBox(&4.Vmhd{ // <vmhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Smhd{}) // <smhd/>
|
||||
_, err = w.WriteBox(&4.Smhd{}) // <smhd/>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Dinf{}) // <dinf>
|
||||
_, err = w.WriteBoxStart(&4.Dinf{}) // <dinf>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Dref{ // <dref>
|
||||
_, err = w.WriteBoxStart(&4.Dref{ // <dref>
|
||||
EntryCount: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Url{ // <url/>
|
||||
_, err = w.WriteBox(&4.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(&4.Stbl{}) // <stbl>
|
||||
_, err = w.WriteBoxStart(&4.Stbl{}) // <stbl>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Stsd{ // <stsd>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.VisualSampleEntry{ // <av01>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Av1C{ // <av1C/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <vp09>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.VpcC{ // <vpcC/>
|
||||
_, err = w.WriteBox(&4.VpcC{ // <vpcC/>
|
||||
FullBox: amp4.FullBox{
|
||||
Version: 1,
|
||||
},
|
||||
@@ -393,7 +394,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
|
||||
}
|
||||
|
||||
case *mp4.CodecH265:
|
||||
_, err = w.writeBoxStart(&4.VisualSampleEntry{ // <hev1>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.HvcC{ // <hvcC/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <avc1>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.AVCDecoderConfiguration{ // <avcc/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <Opus>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.DOps{ // <dOps/>
|
||||
_, err = w.WriteBox(&4.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(&4.AudioSampleEntry{ // <mp4a>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <mp4a>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <ac-3>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Dac3{ // <dac3/>
|
||||
_, err = w.WriteBox(&4.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(&4.AudioSampleEntry{ // <ipcm>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.PcmC{ // <pcmC/>
|
||||
_, err = w.WriteBox(&4.PcmC{ // <pcmC/>
|
||||
FormatFlags: func() uint8 {
|
||||
if codec.LittleEndian {
|
||||
return 1
|
||||
@@ -863,7 +864,7 @@ func (it *InitTrack) marshal(w *mp4Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Btrt{ // <btrt/>
|
||||
_, err = w.WriteBox(&4.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(&4.Stts{ // <stts/>
|
||||
_, err = w.WriteBox(&4.Stts{ // <stts/>
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Stsc{ // <stsc/>
|
||||
_, err = w.WriteBox(&4.Stsc{ // <stsc/>
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Stsz{ // <stsz/>
|
||||
_, err = w.WriteBox(&4.Stsz{ // <stsz/>
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Stco{ // <stco/>
|
||||
_, err = w.WriteBox(&4.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
|
||||
}
|
||||
|
||||
@@ -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 := &4.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
|
||||
}
|
||||
@@ -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(&4.Moof{}) // <moof>
|
||||
moofOffset, err := mw.WriteBoxStart(&4.Moof{}) // <moof>
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = mw.writeBox(&4.Mfhd{ // <mfhd/>
|
||||
_, err = mw.WriteBox(&4.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
|
||||
}
|
||||
|
||||
@@ -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(&4.Traf{}) // <traf>
|
||||
_, err := w.WriteBoxStart(&4.Traf{}) // <traf>
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
flags := 0
|
||||
|
||||
_, err = w.writeBox(&4.Tfhd{ // <tfhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Tfdt{ // <tfdt/>
|
||||
_, err = w.WriteBox(&4.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
|
||||
}
|
||||
|
||||
@@ -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 := &4.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
|
||||
}
|
||||
@@ -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(&4.Ftyp{ // <ftyp/>
|
||||
_, err := mw.WriteBox(&4.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(&4.Moov{}) // <moov>
|
||||
_, err = mw.WriteBoxStart(&4.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
|
||||
}
|
||||
|
||||
@@ -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(&4.Trak{}) // <trak>
|
||||
_, err := w.WriteBoxStart(&4.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(&4.Tkhd{ // <tkhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Tkhd{ // <tkhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Edts{}) // <edts>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Mdia{}) // <mdia>
|
||||
_, err = w.WriteBoxStart(&4.Mdia{}) // <mdia>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Mdhd{ // <mdhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Hdlr{ // <hdlr/>
|
||||
_, err = w.WriteBox(&4.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(&4.Hdlr{ // <hdlr/>
|
||||
_, err = w.WriteBox(&4.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(&4.Minf{}) // <minf>
|
||||
_, err = w.WriteBoxStart(&4.Minf{}) // <minf>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t.Codec.IsVideo() {
|
||||
_, err = w.writeBox(&4.Vmhd{ // <vmhd/>
|
||||
_, err = w.WriteBox(&4.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(&4.Smhd{}) // <smhd/>
|
||||
_, err = w.WriteBox(&4.Smhd{}) // <smhd/>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Dinf{}) // <dinf>
|
||||
_, err = w.WriteBoxStart(&4.Dinf{}) // <dinf>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Dref{ // <dref>
|
||||
_, err = w.WriteBoxStart(&4.Dref{ // <dref>
|
||||
EntryCount: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = w.writeBox(&4.Url{ // <url/>
|
||||
_, err = w.WriteBox(&4.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(&4.Stbl{}) // <stbl>
|
||||
_, err = w.WriteBoxStart(&4.Stbl{}) // <stbl>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = w.writeBoxStart(&4.Stsd{ // <stsd>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.VisualSampleEntry{ // <av01>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Av1C{ // <av1C/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <vp09>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.VpcC{ // <vpcC/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <hev1>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.HvcC{ // <hvcC/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <avc1>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.AVCDecoderConfiguration{ // <avcc/>
|
||||
_, err = w.WriteBox(&4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.VisualSampleEntry{ // <mp4v>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <Opus>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.DOps{ // <dOps/>
|
||||
_, err = w.WriteBox(&4.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(&4.AudioSampleEntry{ // <mp4a>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <mp4a>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Esds{ // <esds/>
|
||||
_, err = w.WriteBox(&4.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: &4.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(&4.AudioSampleEntry{ // <ac-3>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.Dac3{ // <dac3/>
|
||||
_, err = w.WriteBox(&4.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(&4.AudioSampleEntry{ // <ipcm>
|
||||
_, err = w.WriteBoxStart(&4.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(&4.PcmC{ // <pcmC/>
|
||||
_, err = w.WriteBox(&4.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(&4.Elst{
|
||||
_, err := w.WriteBox(&4.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(&4.Elst{
|
||||
_, err := w.WriteBox(&4.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(&4.Stts{
|
||||
_, err := w.WriteBox(&4.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(&4.Stss{
|
||||
_, err := w.WriteBox(&4.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(&4.Ctts{
|
||||
_, err := w.WriteBox(&4.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(&4.Stsc{
|
||||
_, err := w.WriteBox(&4.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(&4.Stsz{
|
||||
_, err := w.WriteBox(&4.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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user