github.com/bluenviron/mediacommon@v1.9.3/pkg/formats/fmp4/part.go (about) 1 package fmp4 2 3 import ( 4 "io" 5 6 "github.com/abema/go-mp4" 7 ) 8 9 const ( 10 trunFlagDataOffsetPreset = 0x01 11 trunFlagSampleDurationPresent = 0x100 12 trunFlagSampleSizePresent = 0x200 13 trunFlagSampleFlagsPresent = 0x400 14 trunFlagSampleCompositionTimeOffsetPresentOrV1 = 0x800 15 16 sampleFlagIsNonSyncSample = 1 << 16 17 ) 18 19 // Part is a fMP4 part. 20 type Part struct { 21 SequenceNumber uint32 22 Tracks []*PartTrack 23 } 24 25 // Marshal encodes a fMP4 part. 26 func (p *Part) Marshal(w io.WriteSeeker) error { 27 /* 28 |moof| 29 | |mfhd| 30 | |traf| 31 | |traf| 32 | |....| 33 |mdat| 34 */ 35 36 mw := newMP4Writer(w) 37 38 moofOffset, err := mw.writeBoxStart(&mp4.Moof{}) // <moof> 39 if err != nil { 40 return err 41 } 42 43 _, err = mw.writeBox(&mp4.Mfhd{ // <mfhd/> 44 SequenceNumber: p.SequenceNumber, 45 }) 46 if err != nil { 47 return err 48 } 49 50 trackLen := len(p.Tracks) 51 truns := make([]*mp4.Trun, trackLen) 52 trunOffsets := make([]int, trackLen) 53 dataOffsets := make([]int, trackLen) 54 dataSize := 0 55 56 for i, track := range p.Tracks { 57 trun, trunOffset, err := track.marshal(mw) 58 if err != nil { 59 return err 60 } 61 62 dataOffsets[i] = dataSize 63 64 for _, sample := range track.Samples { 65 dataSize += len(sample.Payload) 66 } 67 68 truns[i] = trun 69 trunOffsets[i] = trunOffset 70 } 71 72 err = mw.writeBoxEnd() // </moof> 73 if err != nil { 74 return err 75 } 76 77 mdat := &mp4.Mdat{} // <mdat/> 78 mdat.Data = make([]byte, dataSize) 79 pos := 0 80 81 for _, track := range p.Tracks { 82 for _, sample := range track.Samples { 83 pos += copy(mdat.Data[pos:], sample.Payload) 84 } 85 } 86 87 mdatOffset, err := mw.writeBox(mdat) 88 if err != nil { 89 return err 90 } 91 92 for i := range p.Tracks { 93 truns[i].DataOffset = int32(dataOffsets[i] + mdatOffset - moofOffset + 8) 94 err = mw.rewriteBox(trunOffsets[i], truns[i]) 95 if err != nil { 96 return err 97 } 98 } 99 100 return nil 101 }