Repository: Eyevinn/mp4ff
Pull request #416 (2025-03-28 10:44:27)

Golangci-lint v2
Updated to golangci-lint v2 and got more linters.
Fixed all the corresponding warnings.


Patch:
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 581a29c..8dc3385 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -14,7 +14,7 @@ jobs:
       - uses: actions/checkout@v3
 
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v3
+        uses: golangci/golangci-lint-action@v7
         with:
           only-new-issues: true
 
diff --git a/.golangci.yml b/.golangci.yml
index a34cadd..77392d1 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,11 +1,26 @@
+version: "2"
 linters:
   enable:
     - lll
-
-linters-settings:
-  lll:
-    # max line length, lines longer will be reported. Default is 120.
-    # '\t' is counted as 1 character by default, and can be changed with the tab-width option
-    line-length: 140
-    # tab width in spaces. Default to 1.
-    tab-width: 4
+  settings:
+    lll:
+      line-length: 140
+      tab-width: 4
+  exclusions:
+    generated: lax
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
+formatters:
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
diff --git a/aac/adts.go b/aac/adts.go
index 7ed0959..8425377 100644
--- a/aac/adts.go
+++ b/aac/adts.go
@@ -24,11 +24,11 @@ type ADTSHeader struct {
 // NewADTSHeader - create a new ADTS header
 func NewADTSHeader(samplingFrequency int, channelConfig byte, objectType byte, plLen uint16) (*ADTSHeader, error) {
 	if objectType != AAClc {
-		return nil, fmt.Errorf("Must use AAC-LC (type 2) not %d", objectType)
+		return nil, fmt.Errorf("must use AAC-LC (type 2) not %d", objectType)
 	}
 	sfi, ok := ReverseFrequencies[samplingFrequency]
 	if !ok {
-		return nil, fmt.Errorf("Sampling frequency %d not supported", samplingFrequency)
+		return nil, fmt.Errorf("sampling frequency %d not supported", samplingFrequency)
 	}
 	return &ADTSHeader{
 		ObjectType:             objectType,
diff --git a/avc/annexb.go b/avc/annexb.go
index cd6bbfc..99e9f2f 100644
--- a/avc/annexb.go
+++ b/avc/annexb.go
@@ -166,10 +166,7 @@ func getStartCodePositions(stream []byte) (scNalus []scNalu, minStartCodeLength
 func ConvertSampleToByteStream(sample []byte) []byte {
 	sampleLength := uint32(len(sample))
 	var pos uint32 = 0
-	for {
-		if pos >= sampleLength {
-			break
-		}
+	for pos < sampleLength {
 		naluLength := binary.BigEndian.Uint32(sample[pos : pos+4])
 		startCode := []byte{0, 0, 0, 1}
 		copy(sample[pos:pos+4], startCode)
diff --git a/avc/avc.go b/avc/avc.go
index c982ca0..12b44d9 100644
--- a/avc/avc.go
+++ b/avc/avc.go
@@ -143,10 +143,7 @@ func GetParameterSets(sample []byte) (sps [][]byte, pps [][]byte) {
 	sampleLength := uint32(len(sample))
 	var pos uint32 = 0
 naluLoop:
-	for {
-		if pos >= sampleLength {
-			break
-		}
+	for pos < sampleLength {
 		naluLength := binary.BigEndian.Uint32(sample[pos : pos+4])
 		pos += 4
 		naluHdr := sample[pos]
diff --git a/avc/avcdecoderconfigurationrecord.go b/avc/avcdecoderconfigurationrecord.go
index f720346..8af768f 100644
--- a/avc/avcdecoderconfigurationrecord.go
+++ b/avc/avcdecoderconfigurationrecord.go
@@ -11,8 +11,8 @@ import (
 
 // AVC parsing errors
 var (
-	ErrCannotParseAVCExtension = errors.New("Cannot parse SPS extensions")
-	ErrLengthSize              = errors.New("Can only handle 4byte NAL length size")
+	ErrCannotParseAVCExtension = errors.New("cannot parse SPS extensions")
+	ErrLengthSize              = errors.New("can only handle 4byte NAL length size")
 )
 
 // DecConfRec - AVCDecoderConfigurationRecord
@@ -203,17 +203,17 @@ func (a *DecConfRec) EncodeSW(sw bits.SliceWriter) error {
 	sw.WriteUint8(a.AVCLevelIndication)
 	sw.WriteUint8(0xff) // Set length to 4
 
-	var nrSPS byte = byte(len(a.SPSnalus)) | 0xe0 // Added reserved 3 bits
+	var nrSPS = byte(len(a.SPSnalus)) | 0xe0 // Added reserved 3 bits
 	sw.WriteUint8(nrSPS)
 	for _, sps := range a.SPSnalus {
-		var length uint16 = uint16(len(sps))
+		var length = uint16(len(sps))
 		sw.WriteUint16(length)
 		sw.WriteBytes(sps)
 	}
-	var nrPPS byte = byte(len(a.PPSnalus))
+	var nrPPS = byte(len(a.PPSnalus))
 	sw.WriteUint8(nrPPS)
 	for _, pps := range a.PPSnalus {
-		var length uint16 = uint16(len(pps))
+		var length = uint16(len(pps))
 		sw.WriteUint16(length)
 		sw.WriteBytes(pps)
 	}
diff --git a/avc/pps.go b/avc/pps.go
index 13fad8d..97a029d 100644
--- a/avc/pps.go
+++ b/avc/pps.go
@@ -42,7 +42,7 @@ type PPS struct {
 
 // AVC PPS errors
 var (
-	ErrNotPPS = errors.New("Not an PPS NAL unit")
+	ErrNotPPS = errors.New("not an PPS NAL unit")
 )
 
 // ParsePPSNALUnit - Parse AVC PPS NAL unit starting with NAL header
@@ -163,7 +163,7 @@ func ParsePPSNALUnit(data []byte, spsMap map[uint32]*SPS) (*PPS, error) {
 	}
 	_ = reader.Read(1)
 	if reader.AccError() != io.EOF {
-		return nil, fmt.Errorf("Not at end after reading rbsp_trailing_bits")
+		return nil, fmt.Errorf("not at end after reading rbsp_trailing_bits")
 	}
 	return pps, nil
 }
diff --git a/avc/slice.go b/avc/slice.go
index 4ab4a20..76568f6 100644
--- a/avc/slice.go
+++ b/avc/slice.go
@@ -11,9 +11,9 @@ import (
 
 // Errors for parsing and handling AVC slices
 var (
-	ErrNoSliceHeader      = errors.New("No slice header")
-	ErrInvalidSliceType   = errors.New("Invalid slice type")
-	ErrTooFewBytesToParse = errors.New("Too few bytes to parse symbol")
+	ErrNoSliceHeader      = errors.New("no slice header")
+	ErrInvalidSliceType   = errors.New("invalid slice type")
+	ErrTooFewBytesToParse = errors.New("too few bytes to parse symbol")
 )
 
 // SliceType - AVC slice type
diff --git a/avc/sps.go b/avc/sps.go
index 509698f..08ddc80 100644
--- a/avc/sps.go
+++ b/avc/sps.go
@@ -13,7 +13,7 @@ const ExtendedSAR = 255
 
 // SPS errors
 var (
-	ErrNotSPS = errors.New("Not an SPS NAL unit")
+	ErrNotSPS = errors.New("not an SPS NAL unit")
 )
 
 // SPS - AVC SPS parameters
@@ -173,9 +173,10 @@ func ParseSPSNALUnit(data []byte, parseVUIBeyondAspectRatio bool) (*SPS, error)
 
 	sps.Log2MaxFrameNumMinus4 = reader.ReadExpGolomb()
 	sps.PicOrderCntType = reader.ReadExpGolomb()
-	if sps.PicOrderCntType == 0 {
+	switch sps.PicOrderCntType {
+	case 0:
 		sps.Log2MaxPicOrderCntLsbMinus4 = reader.ReadExpGolomb()
-	} else if sps.PicOrderCntType == 1 {
+	case 1:
 		sps.DeltaPicOrderAlwaysZeroFlag = reader.ReadFlag()
 		sps.OffsetForNonRefPic = reader.ReadExpGolomb()
 		sps.OffsetForTopToBottomField = reader.ReadExpGolomb()
@@ -219,7 +220,7 @@ func ParseSPSNALUnit(data []byte, parseVUIBeyondAspectRatio bool) (*SPS, error)
 		case 3: //This lacks one extra check?
 			cropUnitX, cropUnitY = 1, 1*(2-frameMbsOnly)
 		default:
-			return nil, fmt.Errorf("Non-vaild chroma_format_idc value: %d", sps.ChromaFormatIDC)
+			return nil, fmt.Errorf("non-vaild chroma_format_idc value: %d", sps.ChromaFormatIDC)
 		}
 
 		sps.FrameCropLeftOffset = reader.ReadExpGolomb()
diff --git a/examples/combine-segs/main.go b/examples/combine-segs/main.go
index 481840a..97d6f7d 100644
--- a/examples/combine-segs/main.go
+++ b/examples/combine-segs/main.go
@@ -120,7 +120,7 @@ func combineMediaSegments(files []string, newTrackIDs []uint32) (*mp4.MediaSegme
 			return nil, fmt.Errorf("failed to get full samples: %w", err)
 		}
 		for _, fs := range fss {
-			outFrag.AddFullSampleToTrack(fs, newTrackIDs[i])
+			_ = outFrag.AddFullSampleToTrack(fs, newTrackIDs[i])
 		}
 	}
 	return combinedSeg, nil
diff --git a/examples/multitrack/main.go b/examples/multitrack/main.go
index 4b7562f..111eb09 100644
--- a/examples/multitrack/main.go
+++ b/examples/multitrack/main.go
@@ -128,7 +128,7 @@ func writeScenaristFile(w io.Writer, clcpTrack *Track) error {
 		}
 		cdat, ok := box.(*mp4.CdatBox)
 		if !ok {
-			return fmt.Errorf("Box type is not cdat")
+			return fmt.Errorf("box type is not cdat")
 		}
 		dataStr := hex.EncodeToString(cdat.Data)
 		for i := 0; i < len(dataStr); i += 4 {
diff --git a/examples/segmenter/main.go b/examples/segmenter/main.go
index 4ebf92f..8f2ab0a 100644
--- a/examples/segmenter/main.go
+++ b/examples/segmenter/main.go
@@ -47,7 +47,8 @@ func parseOptions(fs *flag.FlagSet, args []string) (*options, error) {
 
 	opts := options{}
 
-	fs.Uint64Var(&opts.chunkDurMS, "d", 0, "Required: segment duration (milliseconds). The segments will start at syncSamples with decoded time >= n*segDur")
+	fs.Uint64Var(&opts.chunkDurMS, "d", 0,
+		"Required: segment duration (milliseconds). The segments will start at syncSamples with decoded time >= n*segDur")
 	fs.BoolVar(&opts.multipex, "m", false, "Output multiplexed segments")
 	fs.BoolVar(&opts.lazy, "lazy", false, "Read/write mdat lazily")
 	fs.BoolVar(&opts.verbose, "v", false, "Verbose output")
diff --git a/examples/segmenter/segment.go b/examples/segmenter/segment.go
index 966aff1..dc50ab3 100644
--- a/examples/segmenter/segment.go
+++ b/examples/segmenter/segment.go
@@ -213,7 +213,7 @@ func getSegmentStartsFromVideo(parsedMp4 *mp4.File, segDurMS uint32) (timeScale
 	stss := refTrak.Mdia.Minf.Stbl.Stss
 	ctts := refTrak.Mdia.Minf.Stbl.Ctts
 	syncPoints = make([]syncPoint, 0, stss.EntryCount())
-	var segmentStep uint32 = uint32(uint64(segDurMS) * uint64(timeScale) / 1000)
+	var segmentStep = uint32(uint64(segDurMS) * uint64(timeScale) / 1000)
 	var nextSegmentStart uint32 = 0
 	for _, sampleNr := range stss.SampleNumber {
 		decodeTime, _ := stts.GetDecodeTime(sampleNr)
diff --git a/examples/segmenter/segmenter.go b/examples/segmenter/segmenter.go
index cb847ac..40f4250 100644
--- a/examples/segmenter/segmenter.go
+++ b/examples/segmenter/segmenter.go
@@ -137,7 +137,8 @@ func (s *Segmenter) MakeMuxedInitSegment() (*mp4.InitSegment, error) {
 }
 
 // GetFullSamplesForInterval - get slice of fullsamples with numbers startSampleNr to endSampleNr (inclusive)
-func (s *Segmenter) GetFullSamplesForInterval(mp4f *mp4.File, tr *Track, startSampleNr, endSampleNr uint32, rs io.ReadSeeker) ([]mp4.FullSample, error) {
+func (s *Segmenter) GetFullSamplesForInterval(mp4f *mp4.File, tr *Track, startSampleNr, endSampleNr uint32,
+	rs io.ReadSeeker) ([]mp4.FullSample, error) {
 	stbl := tr.inTrak.Mdia.Minf.Stbl
 	samples := make([]mp4.FullSample, 0, endSampleNr-startSampleNr+1)
 	mdat := mp4f.Mdat
diff --git a/hevc/hevc.go b/hevc/hevc.go
index 9406b73..d6be7b7 100644
--- a/hevc/hevc.go
+++ b/hevc/hevc.go
@@ -198,10 +198,7 @@ func GetParameterSets(sample []byte) (vps, sps, pps [][]byte) {
 	sampleLength := uint32(len(sample))
 	var pos uint32 = 0
 naluLoop:
-	for {
-		if pos >= sampleLength {
-			break
-		}
+	for pos < sampleLength {
 		naluLength := binary.BigEndian.Uint32(sample[pos : pos+4])
 		pos += 4
 		switch naluType := GetNaluType(sample[pos]); {
diff --git a/mp4/audiosamplentry.go b/mp4/audiosamplentry.go
index 1f82a8c..84b8212 100644
--- a/mp4/audiosamplentry.go
+++ b/mp4/audiosamplentry.go
@@ -135,10 +135,7 @@ func DecodeAudioSampleEntrySR(hdr BoxHeader, startPos uint64, sr bits.SliceReade
 
 	pos := startPos + nrAudioSampleBytesBeforeChildren // Size of all previous data
 	lastPos := startPos + hdr.Size
-	for {
-		if pos >= lastPos {
-			break
-		}
+	for pos < lastPos {
 		box, err := DecodeBoxSR(pos, sr)
 		if err != nil {
 			return nil, err
diff --git a/mp4/box.go b/mp4/box.go
index 1437e3f..61239dc 100644
--- a/mp4/box.go
+++ b/mp4/box.go
@@ -192,7 +192,8 @@ func DecodeHeader(r io.Reader) (BoxHeader, error) {
 	}
 	size := uint64(binary.BigEndian.Uint32(buf[0:4]))
 	headerLen := boxHeaderSize
-	if size == 1 {
+	switch size {
+	case 1: // size 1 means large size in next 8 bytes
 		buf := make([]byte, largeSizeLen)
 		_, err = io.ReadFull(r, buf)
 		if err != nil {
@@ -200,7 +201,7 @@ func DecodeHeader(r io.Reader) (BoxHeader, error) {
 		}
 		size = binary.BigEndian.Uint64(buf)
 		headerLen += largeSizeLen
-	} else if size == 0 {
+	case 0: // size 0 means to end of file
 		return BoxHeader{}, fmt.Errorf("Size 0, meaning to end of file, not supported")
 	}
 	if uint64(headerLen) > size {
diff --git a/mp4/boxsr.go b/mp4/boxsr.go
index c625529..034ec2a 100644
--- a/mp4/boxsr.go
+++ b/mp4/boxsr.go
@@ -188,10 +188,11 @@ func DecodeHeaderSR(sr bits.SliceReader) (BoxHeader, error) {
 	size := uint64(sr.ReadUint32())
 	boxType := sr.ReadFixedLengthString(4)
 	headerLen := boxHeaderSize
-	if size == 1 {
+	switch size {
+	case 1: // size 1 means large size in next 8 bytes
 		size = sr.ReadUint64()
 		headerLen += largeSizeLen
-	} else if size == 0 {
+	case 0: // size 0 means to end of file
 		return BoxHeader{}, fmt.Errorf("Size 0, meaning to end of file, not supported")
 	}
 	if uint64(headerLen) > size {
diff --git a/mp4/crypto.go b/mp4/crypto.go
index ab11023..f144973 100644
--- a/mp4/crypto.go
+++ b/mp4/crypto.go
@@ -66,7 +66,7 @@ func GetAVCProtectRanges(spsMap map[uint32]*avc.SPS, ppsMap map[uint32]*avc.PPS,
 			}
 		}
 		if bytesToProtect > 0 {
-			ssps = appendProtectRange(ssps, clearEnd-clearStart, bytesToProtect)
+			ssps = AppendProtectRange(ssps, clearEnd-clearStart, bytesToProtect)
 			clearStart = clearEnd + bytesToProtect
 			clearEnd = clearStart
 		}
@@ -74,7 +74,7 @@ func GetAVCProtectRanges(spsMap map[uint32]*avc.SPS, ppsMap map[uint32]*avc.PPS,
 		pos += naluLength
 	}
 	if clearEnd > clearStart {
-		ssps = appendProtectRange(ssps, clearEnd-clearStart, 0)
+		ssps = AppendProtectRange(ssps, clearEnd-clearStart, 0)
 	}
 	return ssps, nil
 }
@@ -122,7 +122,7 @@ func GetHEVCProtectRanges(spsMap map[uint32]*hevc.SPS, ppsMap map[uint32]*hevc.P
 			}
 		}
 		if bytesToProtect > 0 {
-			ssps = appendProtectRange(ssps, clearEnd-clearStart, bytesToProtect)
+			ssps = AppendProtectRange(ssps, clearEnd-clearStart, bytesToProtect)
 			clearStart = clearEnd + bytesToProtect
 			clearEnd = clearStart
 		}
@@ -130,17 +130,14 @@ func GetHEVCProtectRanges(spsMap map[uint32]*hevc.SPS, ppsMap map[uint32]*hevc.P
 		pos += naluLength
 	}
 	if clearEnd > clearStart {
-		ssps = appendProtectRange(ssps, clearEnd-clearStart, 0)
+		ssps = AppendProtectRange(ssps, clearEnd-clearStart, 0)
 	}
 	return ssps, nil
 }
 
-// appendProtectRange appends a SubSamplePattern to a slice of SubSamplePattern, splitting into multiple if needed.
-func appendProtectRange(ssps []SubSamplePattern, nrClear, nrProtected uint32) []SubSamplePattern {
-	for {
-		if nrClear < 65536 {
-			break
-		}
+// AppendProtectRange appends a SubSamplePattern to a slice of SubSamplePattern, splitting into multiple if needed.
+func AppendProtectRange(ssps []SubSamplePattern, nrClear, nrProtected uint32) []SubSamplePattern {
+	for nrClear >= 65536 {
 		ssps = append(ssps, SubSamplePattern{65535, 0})
 		nrClear -= 65535
 	}
@@ -244,10 +241,7 @@ func cbcsCrypt(dir cryptoDir, data []byte, key []byte, iv []byte, nrInCryptBlock
 		cph.CryptBlocks(data[:nrToCrypt], data[:nrToCrypt])
 		return nil
 	}
-	for {
-		if size-pos < nrInCryptBlock { // Leave the rest
-			break
-		}
+	for size-pos >= nrInCryptBlock {
 		cph.CryptBlocks(data[pos:pos+nrInCryptBlock], data[pos:pos+nrInCryptBlock])
 		pos += nrInCryptBlock
 		if size-pos < nrInSkipBlock {
diff --git a/mp4/descriptors.go b/mp4/descriptors.go
index 83f6213..618ed1c 100644
--- a/mp4/descriptors.go
+++ b/mp4/descriptors.go
@@ -701,10 +701,7 @@ func CreateESDescriptor(decConfig []byte) ESDescriptor {
 func readSizeSize(sr bits.SliceReader) (sizeFieldSizeMinus1 byte, size uint64, err error) {
 	tmp := sr.ReadUint8()
 	sizeOfInstance := uint64(tmp & 0x7f)
-	for {
-		if (tmp >> 7) == 0 {
-			break // Last byte of size field
-		}
+	for tmp&0x80 != 0 {
 		tmp = sr.ReadUint8()
 		sizeFieldSizeMinus1++
 		sizeOfInstance = sizeOfInstance<<7 | uint64(tmp&0x7f)
diff --git a/mp4/elst.go b/mp4/elst.go
index 9ffd9b8..2693ed1 100644
--- a/mp4/elst.go
+++ b/mp4/elst.go
@@ -49,21 +49,22 @@ func DecodeElstSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 
 	b.Entries = make([]ElstEntry, entryCount)
 
-	if version == 1 {
+	switch version {
+	case 1:
 		for i := 0; i < int(entryCount); i++ {
 			b.Entries[i].SegmentDuration = sr.ReadUint64()
 			b.Entries[i].MediaTime = sr.ReadInt64()
 			b.Entries[i].MediaRateInteger = sr.ReadInt16()
 			b.Entries[i].MediaRateFraction = sr.ReadInt16()
 		}
-	} else if version == 0 {
+	case 0:
 		for i := 0; i < int(entryCount); i++ {
 			b.Entries[i].SegmentDuration = uint64(sr.ReadUint32())
 			b.Entries[i].MediaTime = int64(sr.ReadInt32())
 			b.Entries[i].MediaRateInteger = sr.ReadInt16()
 			b.Entries[i].MediaRateFraction = sr.ReadInt16()
 		}
-	} else {
+	default:
 		return nil, fmt.Errorf("unknown version for elst")
 	}
 	return b, sr.AccError()
diff --git a/mp4/emsg.go b/mp4/emsg.go
index b133d81..4f52a93 100644
--- a/mp4/emsg.go
+++ b/mp4/emsg.go
@@ -42,7 +42,8 @@ func DecodeEmsgSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 		Flags:       versionAndFlags & flagsMask,
 		MessageData: nil,
 	}
-	if version == 1 {
+	switch version {
+	case 1:
 		b.TimeScale = sr.ReadUint32()
 		b.PresentationTime = sr.ReadUint64()
 		b.EventDuration = sr.ReadUint32()
@@ -51,7 +52,7 @@ func DecodeEmsgSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 		b.SchemeIDURI = sr.ReadZeroTerminatedString(maxLen)
 		maxLen = hdr.payloadLen() - (sr.GetPos() - initPos)
 		b.Value = sr.ReadZeroTerminatedString(maxLen)
-	} else if version == 0 {
+	case 0:
 		maxLen := hdr.payloadLen() - (sr.GetPos() - initPos) - 17
 		b.SchemeIDURI = sr.ReadZeroTerminatedString(maxLen)
 		maxLen = hdr.payloadLen() - (sr.GetPos() - initPos) - 16
@@ -60,7 +61,7 @@ func DecodeEmsgSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 		b.PresentationTimeDelta = sr.ReadUint32()
 		b.EventDuration = sr.ReadUint32()
 		b.ID = sr.ReadUint32()
-	} else {
+	default:
 		return nil, fmt.Errorf("unknown version %d for emsg", version)
 	}
 
diff --git a/mp4/esds.go b/mp4/esds.go
index eea7c6d..2b3c2a2 100644
--- a/mp4/esds.go
+++ b/mp4/esds.go
@@ -58,7 +58,7 @@ func (e *EsdsBox) Type() string {
 
 // Size - calculated size of box
 func (e *EsdsBox) Size() uint64 {
-	return uint64(8 + 4 + e.ESDescriptor.SizeSize())
+	return uint64(8 + 4 + e.SizeSize())
 }
 
 // Encode - write box to w
diff --git a/mp4/infodumper.go b/mp4/infodumper.go
index e93bd46..23970ed 100644
--- a/mp4/infodumper.go
+++ b/mp4/infodumper.go
@@ -92,13 +92,14 @@ func getInfoLevel(b boxLike, specificBoxLevels string) (level int) {
 		}
 		bt := bl[:splitPos]
 		nr := bl[splitPos+1:]
-		if bt == boxType {
+		switch bt {
+		case boxType:
 			level, err = strconv.Atoi(nr)
 			if err != nil {
 				level = 0
 			}
 			return level
-		} else if bt == "all" {
+		case "all":
 			level, err = strconv.Atoi(nr)
 			if err != nil {
 				level = 0
diff --git a/mp4/mdhd.go b/mp4/mdhd.go
index a34cb9b..4a78a32 100644
--- a/mp4/mdhd.go
+++ b/mp4/mdhd.go
@@ -43,17 +43,18 @@ func DecodeMdhdSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 		Version: version,
 		Flags:   versionAndFlags & flagsMask,
 	}
-	if version == 1 {
+	switch version {
+	case 1:
 		b.CreationTime = sr.ReadUint64()
 		b.ModificationTime = sr.ReadUint64()
 		b.Timescale = sr.ReadUint32()
 		b.Duration = sr.ReadUint64()
-	} else if version == 0 {
+	case 0:
 		b.CreationTime = uint64(sr.ReadUint32())
 		b.ModificationTime = uint64(sr.ReadUint32())
 		b.Timescale = sr.ReadUint32()
 		b.Duration = uint64(sr.ReadUint32())
-	} else {
+	default:
 		return nil, fmt.Errorf("unknown mdhd version %d", version)
 	}
 	b.Language = sr.ReadUint16()
diff --git a/mp4/sgpd.go b/mp4/sgpd.go
index 7651ab8..d9cb9fc 100644
--- a/mp4/sgpd.go
+++ b/mp4/sgpd.go
@@ -48,7 +48,7 @@ func DecodeSgpdSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 	}
 	entryCount := sr.ReadUint32()
 	for i := uint32(0); i < entryCount; i++ {
-		var descriptionLength uint32 = b.DefaultLength
+		var descriptionLength = b.DefaultLength
 		if b.Version >= 1 && b.DefaultLength == 0 {
 			descriptionLength = sr.ReadUint32()
 			b.DescriptionLengths = append(b.DescriptionLengths, descriptionLength)
diff --git a/mp4/visualsampleentry.go b/mp4/visualsampleentry.go
index 4d561c8..7a98982 100644
--- a/mp4/visualsampleentry.go
+++ b/mp4/visualsampleentry.go
@@ -127,10 +127,7 @@ func DecodeVisualSampleEntrySR(hdr BoxHeader, startPos uint64, sr bits.SliceRead
 	// 14496-15  5.4.2.1.2 avcC should be inside avc1, avc3 box
 	pos := startPos + 86 // Size of all previous data
 	endPos := startPos + uint64(hdr.Hdrlen) + uint64(hdr.payloadLen())
-	for {
-		if pos >= endPos {
-			break
-		}
+	for pos < endPos {
 		box, err := DecodeBoxSR(pos, sr)
 		if err != nil {
 			return nil, fmt.Errorf("error decoding childBox of VisualSampleEntry: %w", err)
@@ -284,9 +281,9 @@ func (b *VisualSampleEntryBox) ConvertHev1ToHvc1(vpss [][]byte, spss [][]byte, p
 		return fmt.Errorf("type is %s and not hev1", b.Type())
 	}
 	b.SetType("hvc1")
-	b.HvcC.DecConfRec.NaluArrays = append(b.HvcC.DecConfRec.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_VPS, vpss))
-	b.HvcC.DecConfRec.NaluArrays = append(b.HvcC.DecConfRec.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_SPS, spss))
-	b.HvcC.DecConfRec.NaluArrays = append(b.HvcC.DecConfRec.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_PPS, ppss))
+	b.HvcC.NaluArrays = append(b.HvcC.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_VPS, vpss))
+	b.HvcC.NaluArrays = append(b.HvcC.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_SPS, spss))
+	b.HvcC.NaluArrays = append(b.HvcC.NaluArrays, hevc.NewNaluArray(true, hevc.NALU_PPS, ppss))
 	return nil
 }
 
@@ -296,7 +293,7 @@ func (b *VisualSampleEntryBox) ConvertAvc3ToAvc1(spss [][]byte, ppss [][]byte) e
 		return fmt.Errorf("type is %s and not avc3", b.Type())
 	}
 	b.SetType("avc1")
-	b.AvcC.DecConfRec.SPSnalus = spss
-	b.AvcC.DecConfRec.PPSnalus = ppss
+	b.AvcC.SPSnalus = spss
+	b.AvcC.PPSnalus = ppss
 	return nil
 }
diff --git a/mp4/wvtt.go b/mp4/wvtt.go
index 30d691c..6dc04d9 100644
--- a/mp4/wvtt.go
+++ b/mp4/wvtt.go
@@ -62,10 +62,7 @@ func DecodeWvttSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 	w.DataReferenceIndex = sr.ReadUint16()
 	pos := startPos + nrWvttBytesBeforeChildren
 	endPos := startPos + uint64(hdr.Hdrlen+hdr.payloadLen())
-	for {
-		if pos >= endPos {
-			break
-		}
+	for pos < endPos {
 		box, err := DecodeBoxSR(pos, sr)
 		if err != nil {
 			return nil, err
diff --git a/sei/sei4.go b/sei/sei4.go
index c304470..f4ad0d5 100644
--- a/sei/sei4.go
+++ b/sei/sei4.go
@@ -135,10 +135,11 @@ func ParseCEA608(payload []byte) ([]byte, []byte, error) {
 		ccData2 := payload[pos] // Keep parity bit
 		pos++
 		if ccValid != 0 && ((ccData1&0x7f)+(ccData2&0x7f) != 0) { //Check validity and non-empty data
-			if ccType == 0 {
+			switch ccType {
+			case 0:
 				field1 = append(field1, ccData1)
 				field1 = append(field1, ccData2)
-			} else if ccType == 1 {
+			case 1:
 				field2 = append(field2, ccData1)
 				field2 = append(field2, ccData2)
 			}


Test patch:
diff --git a/bits/fixedslicewriter_test.go b/bits/fixedslicewriter_test.go
index a1fcfa3..dbf7cbf 100644
--- a/bits/fixedslicewriter_test.go
+++ b/bits/fixedslicewriter_test.go
@@ -106,7 +106,7 @@ func TestFixedSliceWriter(t *testing.T) {
 			t.Errorf("unexpected offset %d instead of %d", offset, wantedOffset)
 		}
 		result := sw.Bytes()
-		if !(result[0] == 0xf2 && result[1] == 0x50) {
+		if result[0] != 0xf2 || result[1] != 0x50 {
 			t.Errorf("got %02x%02x instead of 0xf250", result[0], result[1])
 		}
 		sw.WriteUint16(0xffff)
diff --git a/examples/resegmenter/main_test.go b/examples/resegmenter/main_test.go
index 07e911c..138196b 100644
--- a/examples/resegmenter/main_test.go
+++ b/examples/resegmenter/main_test.go
@@ -18,7 +18,8 @@ func TestCommandLines(t *testing.T) {
 		{desc: "no args", args: []string{appName}, expectedErr: true},
 		{desc: "duration = 0", args: []string{appName, "-d", "0", "dummy.mp4", "dummy.mp4"}, expectedErr: true},
 		{desc: "non-existing infile", args: []string{appName, "-d", "1000", "notExists.mp4", "dummy.mp4"}, expectedErr: true},
-		{desc: "segment 2s to 1s (30fps 3000 ticks/frame)", args: []string{appName, "-v", "-d", "90000", "../../mp4/testdata/1.m4s", outFile},
+		{desc: "segment 2s to 1s (30fps 3000 ticks/frame)", args: []string{appName, "-v", "-d", "90000", "../../mp4/testdata/1.m4s",
+			outFile},
 			wantedOutput: `Started segment 1 at dts=0 pts=6000
    0 DTS 0 PTS 6000
   30 DTS 90000 PTS 96000
diff --git a/examples/segmenter/main_test.go b/examples/segmenter/main_test.go
index deb93a4..f22272c 100644
--- a/examples/segmenter/main_test.go
+++ b/examples/segmenter/main_test.go
@@ -21,10 +21,12 @@ func TestCommandLines(t *testing.T) {
 		{desc: "duration = 0", args: []string{appName, "-d", "0", "dummy.mp4", "dummy.mp4"}, expectedErr: true},
 		{desc: "non-existing infile", args: []string{appName, "-d", "1000", "notExists.mp4", "dummy.mp4"}, expectedErr: true},
 		{desc: "segment 10s to 5s", args: []string{appName, "-d", "5000", testIn, "split"}, expectedErr: false,
-			wantedFiles: []string{"split_a1_1.m4s", "split_a1_2.m4s", "split_a1_init.mp4", "split_v1_1.m4s", "split_v1_2.m4s", "split_v1_init.mp4"},
+			wantedFiles: []string{"split_a1_1.m4s", "split_a1_2.m4s", "split_a1_init.mp4", "split_v1_1.m4s",
+				"split_v1_2.m4s", "split_v1_init.mp4"},
 		},
 		{desc: "segment 10s to 5s lazy", args: []string{appName, "-d", "5000", "-lazy", testIn, "lazy"}, expectedErr: false,
-			wantedFiles: []string{"lazy_a1_1.m4s", "lazy_a1_2.m4s", "lazy_a1_init.mp4", "lazy_v1_1.m4s", "lazy_v1_2.m4s", "lazy_v1_init.mp4"},
+			wantedFiles: []string{"lazy_a1_1.m4s", "lazy_a1_2.m4s", "lazy_a1_init.mp4", "lazy_v1_1.m4s",
+				"lazy_v1_2.m4s", "lazy_v1_init.mp4"},
 		},
 		{desc: "segment 10s to 5s muxed", args: []string{appName, "-d", "5000", "-m", testIn, "mux"}, expectedErr: false,
 			wantedFiles: []string{"mux_init.mp4", "mux_media_1.m4s", "mux_media_2.m4s"},
diff --git a/mp4/crypto_test.go b/mp4/crypto_test.go
index 05acb1b..0b56e59 100644
--- a/mp4/crypto_test.go
+++ b/mp4/crypto_test.go
@@ -277,3 +277,69 @@ func TestDecryptInit(t *testing.T) {
 		}
 	}
 }
+
+func TestAppendProtectRange(t *testing.T) {
+	testCases := []struct {
+		name        string
+		nrClear     uint32
+		nrProtected uint32
+		expected    []mp4.SubSamplePattern
+	}{
+		{
+			name:        "clear data under limit",
+			nrClear:     1000,
+			nrProtected: 500,
+			expected: []mp4.SubSamplePattern{
+				{BytesOfClearData: 1000, BytesOfProtectedData: 500},
+			},
+		},
+		{
+			name:        "clear data at limit",
+			nrClear:     65535,
+			nrProtected: 500,
+			expected: []mp4.SubSamplePattern{
+				{BytesOfClearData: 65535, BytesOfProtectedData: 500},
+			},
+		},
+		{
+			name:        "clear data just over limit",
+			nrClear:     65536,
+			nrProtected: 500,
+			expected: []mp4.SubSamplePattern{
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 1, BytesOfProtectedData: 500},
+			},
+		},
+		{
+			name:        "clear data well over limit",
+			nrClear:     140000,
+			nrProtected: 800,
+			expected: []mp4.SubSamplePattern{
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 140000 - 65535 - 65535, BytesOfProtectedData: 800},
+			},
+		},
+		{
+			name:        "multiple of 65535 plus remainder",
+			nrClear:     65535*3 + 42,
+			nrProtected: 100,
+			expected: []mp4.SubSamplePattern{
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 65535, BytesOfProtectedData: 0},
+				{BytesOfClearData: 42, BytesOfProtectedData: 100},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := mp4.AppendProtectRange(nil, tc.nrClear, tc.nrProtected)
+			if diff := deep.Equal(result, tc.expected); diff != nil {
+				t.Errorf("AppendProtectRange(%d, %d) returned unexpected result: %v",
+					tc.nrClear, tc.nrProtected, diff)
+			}
+		})
+	}
+}
diff --git a/mp4/stpp_test.go b/mp4/stpp_test.go
index 9f6dd67..7ac641d 100644
--- a/mp4/stpp_test.go
+++ b/mp4/stpp_test.go
@@ -91,7 +91,7 @@ func TestStpp(t *testing.T) {
 		hexData := ("0000002b737470700000000000000001" +
 			"687474703a2f2f7777772e77332e6f72" +
 			"672f6e732f74746d6c0000")
-		hexData = strings.Replace(hexData, " ", "", -1)
+		hexData = strings.ReplaceAll(hexData, " ", "")
 		data, err := hex.DecodeString(hexData)
 		if err != nil {
 			t.Error(err)