diff --git a/cmd/mp4ff-crop/byteranges.go b/cmd/mp4ff-crop/byteranges.go deleted file mode 100644 index 23e75cfa..00000000 --- a/cmd/mp4ff-crop/byteranges.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -type byteRange struct { - start uint64 - end uint64 // Included -} - -type byteRanges struct { - ranges []byteRange -} - -func createByteRanges() *byteRanges { - return &byteRanges{} -} - -func (b *byteRanges) addRange(start, end uint64) { - if len(b.ranges) == 0 || b.ranges[len(b.ranges)-1].end+1 != start { - b.ranges = append(b.ranges, byteRange{start, end}) - return - } - b.ranges[len(b.ranges)-1].end = end -} - -func (b *byteRanges) size() uint64 { - var totSize uint64 = 0 - for _, br := range b.ranges { - totSize += br.end - br.start + 1 - } - return uint64(totSize) -} diff --git a/cmd/mp4ff-crop/main.go b/cmd/mp4ff-crop/main.go index d7658a30..e02d8440 100644 --- a/cmd/mp4ff-crop/main.go +++ b/cmd/mp4ff-crop/main.go @@ -11,6 +11,7 @@ import ( "io" "log" "os" + "sort" "strings" "github.com/Eyevinn/mp4ff/mp4" @@ -387,3 +388,147 @@ func minUint32(a, b uint32) uint32 { } return b } + +func cropStblChildren(traks []*mp4.TrakBox, trakOuts map[uint32]*trakOut) (err error) { + for _, trak := range traks { + trakID := trak.Tkhd.TrackID + stbl := trak.Mdia.Minf.Stbl + to := trakOuts[trakID] + for _, ch := range stbl.Children { + switch ch.Type() { + case "stts": + cropStts(ch.(*mp4.SttsBox), to.lastSampleNr) + case "stss": + cropStss(ch.(*mp4.StssBox), to.lastSampleNr) + case "ctts": + cropCtts(ch.(*mp4.CttsBox), to.lastSampleNr) + case "stsc": + err = cropStsc(ch.(*mp4.StscBox), to.lastSampleNr) + case "stsz": + cropStsz(ch.(*mp4.StszBox), to.lastSampleNr) + case "sdtp": + cropSdtp(ch.(*mp4.SdtpBox), to.lastSampleNr) + case "stco": + updateStco(ch.(*mp4.StcoBox), to.chunkOffsets) + case "co64": + updateCo64(ch.(*mp4.Co64Box), to.chunkOffsets) + } + } + } + return err +} + +func cropStts(b *mp4.SttsBox, lastSampleNr uint32) { + var countedSamples uint32 = 0 + lastEntry := -1 + for i := 0; i < len(b.SampleCount); i++ { + if countedSamples < lastSampleNr { + lastEntry++ + } + if countedSamples+b.SampleCount[i] >= lastSampleNr { + break + } + countedSamples += b.SampleCount[i] + } + remaining := lastSampleNr - countedSamples + if remaining > 0 { + b.SampleCount[lastEntry] = remaining + } + + b.SampleCount = b.SampleCount[:lastEntry+1] + b.SampleTimeDelta = b.SampleTimeDelta[:lastEntry+1] +} + +func cropStss(b *mp4.StssBox, lastSampleNr uint32) { + nrEntries := b.EntryCount() + nrEntriesToKeep := 0 + for i := uint32(0); i < nrEntries; i++ { + if b.SampleNumber[i] > lastSampleNr { + break + } + nrEntriesToKeep++ + } + b.SampleNumber = b.SampleNumber[:nrEntriesToKeep] +} + +func cropCtts(b *mp4.CttsBox, lastSampleNr uint32) { + lastIdx := sort.Search(len(b.EndSampleNr), func(i int) bool { return b.EndSampleNr[i] >= lastSampleNr }) + // Finally cut down the endSampleNr for this index + b.EndSampleNr[lastIdx] = lastSampleNr + b.EndSampleNr = b.EndSampleNr[:lastIdx+1] + b.SampleOffset = b.SampleOffset[:lastIdx] +} + +func cropStsc(b *mp4.StscBox, lastSampleNr uint32) error { + entryIdx := b.FindEntryNrForSampleNr(lastSampleNr, 0) + lastEntry := b.Entries[entryIdx] + b.Entries = b.Entries[:entryIdx+1] + if len(b.SampleDescriptionID) > 0 { + b.Entries = b.Entries[:entryIdx+1] + } + samplesLeft := lastSampleNr - lastEntry.FirstSampleNr + 1 + nrChunksInLast := samplesLeft / lastEntry.SamplesPerChunk + nrLeft := samplesLeft - nrChunksInLast*lastEntry.SamplesPerChunk + if nrLeft > 0 { + sdid := b.GetSampleDescriptionID(int(lastEntry.FirstChunk)) + err := b.AddEntry(lastEntry.FirstChunk+nrChunksInLast, nrLeft, sdid) + if err != nil { + return fmt.Errorf("stsc AddEntry: %w", err) + } + } + return nil +} + +func cropStsz(b *mp4.StszBox, lastSampleNr uint32) { + if b.SampleUniformSize == 0 { + b.SampleSize = b.SampleSize[:lastSampleNr] + } + b.SampleNumber = lastSampleNr +} + +func cropSdtp(b *mp4.SdtpBox, lastSampleNr uint32) { + if len(b.Entries) > int(lastSampleNr) { + b.Entries = b.Entries[:lastSampleNr] + } +} + +func updateStco(b *mp4.StcoBox, offsets []uint64) { + b.ChunkOffset = make([]uint32, len(offsets)) + for i := range offsets { + b.ChunkOffset[i] = uint32(offsets[i]) + } +} + +func updateCo64(b *mp4.Co64Box, offsets []uint64) { + b.ChunkOffset = make([]uint64, len(offsets)) + _ = copy(b.ChunkOffset, offsets) +} + +type byteRange struct { + start uint64 + end uint64 // Included +} + +type byteRanges struct { + ranges []byteRange +} + +func createByteRanges() *byteRanges { + return &byteRanges{} +} + +func (b *byteRanges) addRange(start, end uint64) { + if len(b.ranges) == 0 || b.ranges[len(b.ranges)-1].end+1 != start { + b.ranges = append(b.ranges, byteRange{start, end}) + return + } + b.ranges[len(b.ranges)-1].end = end +} + +func (b *byteRanges) size() uint64 { + var totSize uint64 = 0 + for _, br := range b.ranges { + totSize += br.end - br.start + 1 + } + return uint64(totSize) +} diff --git a/cmd/mp4ff-crop/stblcrop.go b/cmd/mp4ff-crop/stblcrop.go deleted file mode 100644 index 5fb22a71..00000000 --- a/cmd/mp4ff-crop/stblcrop.go +++ /dev/null @@ -1,123 +0,0 @@ -package main - -import ( - "fmt" - "sort" - - "github.com/Eyevinn/mp4ff/mp4" -) - -func cropStblChildren(traks []*mp4.TrakBox, trakOuts map[uint32]*trakOut) (err error) { - for _, trak := range traks { - trakID := trak.Tkhd.TrackID - stbl := trak.Mdia.Minf.Stbl - to := trakOuts[trakID] - for _, ch := range stbl.Children { - switch ch.Type() { - case "stts": - cropStts(ch.(*mp4.SttsBox), to.lastSampleNr) - case "stss": - cropStss(ch.(*mp4.StssBox), to.lastSampleNr) - case "ctts": - cropCtts(ch.(*mp4.CttsBox), to.lastSampleNr) - case "stsc": - err = cropStsc(ch.(*mp4.StscBox), to.lastSampleNr) - case "stsz": - cropStsz(ch.(*mp4.StszBox), to.lastSampleNr) - case "sdtp": - cropSdtp(ch.(*mp4.SdtpBox), to.lastSampleNr) - case "stco": - updateStco(ch.(*mp4.StcoBox), to.chunkOffsets) - case "co64": - updateCo64(ch.(*mp4.Co64Box), to.chunkOffsets) - } - } - } - return err -} - -func cropStts(b *mp4.SttsBox, lastSampleNr uint32) { - var countedSamples uint32 = 0 - lastEntry := -1 - for i := 0; i < len(b.SampleCount); i++ { - if countedSamples < lastSampleNr { - lastEntry++ - } - if countedSamples+b.SampleCount[i] >= lastSampleNr { - break - } - countedSamples += b.SampleCount[i] - } - remaining := lastSampleNr - countedSamples - if remaining > 0 { - b.SampleCount[lastEntry] = remaining - } - - b.SampleCount = b.SampleCount[:lastEntry+1] - b.SampleTimeDelta = b.SampleTimeDelta[:lastEntry+1] -} - -func cropStss(b *mp4.StssBox, lastSampleNr uint32) { - nrEntries := b.EntryCount() - nrEntriesToKeep := 0 - for i := uint32(0); i < nrEntries; i++ { - if b.SampleNumber[i] > lastSampleNr { - break - } - nrEntriesToKeep++ - } - b.SampleNumber = b.SampleNumber[:nrEntriesToKeep] -} - -func cropCtts(b *mp4.CttsBox, lastSampleNr uint32) { - lastIdx := sort.Search(len(b.EndSampleNr), func(i int) bool { return b.EndSampleNr[i] >= lastSampleNr }) - // Finally cut down the endSampleNr for this index - b.EndSampleNr[lastIdx] = lastSampleNr - b.EndSampleNr = b.EndSampleNr[:lastIdx+1] - b.SampleOffset = b.SampleOffset[:lastIdx] -} - -func cropStsc(b *mp4.StscBox, lastSampleNr uint32) error { - entryIdx := b.FindEntryNrForSampleNr(lastSampleNr, 0) - lastEntry := b.Entries[entryIdx] - b.Entries = b.Entries[:entryIdx+1] - if len(b.SampleDescriptionID) > 0 { - b.Entries = b.Entries[:entryIdx+1] - } - samplesLeft := lastSampleNr - lastEntry.FirstSampleNr + 1 - nrChunksInLast := samplesLeft / lastEntry.SamplesPerChunk - nrLeft := samplesLeft - nrChunksInLast*lastEntry.SamplesPerChunk - if nrLeft > 0 { - sdid := b.GetSampleDescriptionID(int(lastEntry.FirstChunk)) - err := b.AddEntry(lastEntry.FirstChunk+nrChunksInLast, nrLeft, sdid) - if err != nil { - return fmt.Errorf("stsc AddEntry: %w", err) - } - } - return nil -} - -func cropStsz(b *mp4.StszBox, lastSampleNr uint32) { - if b.SampleUniformSize == 0 { - b.SampleSize = b.SampleSize[:lastSampleNr] - } - b.SampleNumber = lastSampleNr -} - -func cropSdtp(b *mp4.SdtpBox, lastSampleNr uint32) { - if len(b.Entries) > int(lastSampleNr) { - b.Entries = b.Entries[:lastSampleNr] - } -} - -func updateStco(b *mp4.StcoBox, offsets []uint64) { - b.ChunkOffset = make([]uint32, len(offsets)) - for i := range offsets { - b.ChunkOffset[i] = uint32(offsets[i]) - } -} - -func updateCo64(b *mp4.Co64Box, offsets []uint64) { - b.ChunkOffset = make([]uint64, len(offsets)) - _ = copy(b.ChunkOffset, offsets) -}