Repository: Eyevinn/mp4ff
Pull request #415 (2025-03-04 15:45:10)

refactor: move all mp4 test to mp4_test package for black-box testing
Almost all tests in the mp4 package were already black-box tests, but not all.
After pondering on Issue #414, I think that it would be useful to make them black-box testing.
That is what this PR does. 

A similar approach should be taken to the other repos.

All forks with a different domain, need to make a global replacement of paths in the `_test.go` files, but that should be relatively easy to automate.

During this work, some other changes were needed, or felt natural:

### Changed

- Replaced mp4.AlouBox and mp4.TlouBox with a common mp4.LoudnessBaseBox
 - mp4.Measurement changed to clearer mp4.LoudnessMeasurement
 
 ### Added
 
 - Exported constants for ColrBox's ColorType
 - mp4.NewFreeBox, mp4.NewSkipBox functions
 - mp4.FreeBox.Payload method
 - New mp4.SencBox methods: SetPerSampleIVSize, PerSampleIVSize, and ReadButNotParsed
 - New function mp4.CreateUnknownBox
 - New functions mp4.NewTfrfBox and mp4.NewTfxdBox



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aed311f..5b8d27b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### New
+
+* UUID
+* Mdat
+
 ### Changed
 
 - mp4.NewUUIDFromHex() changed to more general mp4.NewUUIDFromString()
 - cmd/mp4ff-decrypt -key option instead of -k. Takes hex or base64 value
 - cmd/mp4ff-encrypt -key and -kid options now take hex or bae64 values
+- Replaced mp4.AlouBox and mp4.TlouBox with a common mp4.LoudnessBaseBox
+- mp4.Measurement changed to clearer mp4.LoudnessMeasurement
 
 ### Added
 
@@ -22,6 +29,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Support for Content Light Level Box (CoLL)
 - Better test coverage for VisualSampleEntryBox
 - IsVideoNaluType functions in both avc and hevc packages
+- Exported constants for ColrBox's ColorType
+- mp4.NewFreeBox, mp4.NewSkipBox functions
+- mp4.FreeBox.Payload method
+- New mp4.SencBox methods: SetPerSampleIVSize, PerSampleIVSize, and ReadButNotParsed
+- New function mp4.CreateUnknownBox
+- New functions mp4.NewTfrfBox and mp4.NewTfxdBox
 
 ### Fixed
 
diff --git a/mp4/box.go b/mp4/box.go
index 7a90c70..1437e3f 100644
--- a/mp4/box.go
+++ b/mp4/box.go
@@ -24,7 +24,7 @@ func init() {
 		"\xa9too": DecodeGenericContainerBox,
 		"\xa9cpy": DecodeGenericContainerBox,
 		"ac-3":    DecodeAudioSampleEntry,
-		"alou":    DecodeAlou,
+		"alou":    DecodeLoudnessBaseBox,
 		"av01":    DecodeVisualSampleEntry,
 		"av1C":    DecodeAv1C,
 		"avc1":    DecodeVisualSampleEntry,
@@ -130,7 +130,7 @@ func init() {
 		"tfhd":    DecodeTfhd,
 		"tfra":    DecodeTfra,
 		"tkhd":    DecodeTkhd,
-		"tlou":    DecodeTlou,
+		"tlou":    DecodeLoudnessBaseBox,
 		"traf":    DecodeTraf,
 		"trak":    DecodeTrak,
 		"tref":    DecodeTref,
diff --git a/mp4/boxsr.go b/mp4/boxsr.go
index 7bc31f1..c625529 100644
--- a/mp4/boxsr.go
+++ b/mp4/boxsr.go
@@ -15,7 +15,7 @@ func init() {
 		"\xa9nam": DecodeGenericContainerBoxSR,
 		"\xa9too": DecodeGenericContainerBoxSR,
 		"ac-3":    DecodeAudioSampleEntrySR,
-		"alou":    DecodeAlouBoxSR,
+		"alou":    DecodeLoudnessBaseBoxSR,
 		"av01":    DecodeVisualSampleEntrySR,
 		"av1C":    DecodeAv1CSR,
 		"avc1":    DecodeVisualSampleEntrySR,
@@ -121,7 +121,7 @@ func init() {
 		"tfhd":    DecodeTfhdSR,
 		"tfra":    DecodeTfraSR,
 		"tkhd":    DecodeTkhdSR,
-		"tlou":    DecodeTlouSR,
+		"tlou":    DecodeLoudnessBaseBoxSR,
 		"traf":    DecodeTrafSR,
 		"trak":    DecodeTrakSR,
 		"tref":    DecodeTrefSR,
diff --git a/mp4/colr.go b/mp4/colr.go
index 7ecf76c..5561aaa 100644
--- a/mp4/colr.go
+++ b/mp4/colr.go
@@ -8,18 +8,18 @@ import (
 )
 
 const (
-	colrType            = "colr"
-	onScreenColors      = "nclx"
-	restrictedICCType   = "rICC"
-	unrestrictedICCType = "prof"
-	// quickTimeColorParameters defined in [nclc]
+	colrType                         = "colr"
+	ColorTypeOnScreenColors          = "nclx" // on-screen colours acc. to ISO/IEC 14496-12 Sec. 12.1.5.2
+	ColorTypeRestrictedICCProfile    = "rICC" // restricted ICC profile acc. to ISO/IEC 14496-12 Sec. 12.1.5.2
+	ColorTypeUnrestrictedICCTProfile = "prof" // unrestricted ICC profile acc. to ISO/IEC 14496-12 Sec. 12.1.5.2
+	// QuickTimeColorParameters defined in [nclc]
 	//
 	// [nclc]: https://developer.apple.com/library/archive/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG10
-	quickTimeColorParameters = "nclc"
+	QuickTimeColorParameters = "nclc"
 	fullRangeBit             = 0x80
 )
 
-// ColrBox is colr box defined in ISO/IEC 14496-2 2021 12.1.5.
+// ColrBox is colr box defined in ISO/IEC 14496-12 2021 Sec. 12.1.5.
 type ColrBox struct {
 	ColorType               string
 	ICCProfile              []byte
@@ -46,15 +46,15 @@ func DecodeColrSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 		ColorType: sr.ReadFixedLengthString(4),
 	}
 	switch c.ColorType {
-	case onScreenColors:
+	case ColorTypeOnScreenColors:
 		c.ColorPrimaries = sr.ReadUint16()
 		c.TransferCharacteristics = sr.ReadUint16()
 		c.MatrixCoefficients = sr.ReadUint16()
 		b := sr.ReadUint8()
 		c.FullRangeFlag = (b & fullRangeBit) == fullRangeBit
-	case restrictedICCType, unrestrictedICCType:
+	case ColorTypeRestrictedICCProfile, ColorTypeUnrestrictedICCTProfile:
 		c.ICCProfile = sr.RemainingBytes()
-	case quickTimeColorParameters:
+	case QuickTimeColorParameters:
 		c.ColorPrimaries = sr.ReadUint16()
 		c.TransferCharacteristics = sr.ReadUint16()
 		c.MatrixCoefficients = sr.ReadUint16()
@@ -73,11 +73,11 @@ func (c *ColrBox) Type() string {
 func (c *ColrBox) Size() uint64 {
 	var size uint64 = 8 + 4
 	switch c.ColorType {
-	case onScreenColors:
+	case ColorTypeOnScreenColors:
 		size += 7
-	case restrictedICCType, unrestrictedICCType:
+	case ColorTypeRestrictedICCProfile, ColorTypeUnrestrictedICCTProfile:
 		size += uint64(len(c.ICCProfile))
-	case quickTimeColorParameters:
+	case QuickTimeColorParameters:
 		size += 6
 	default:
 		size += uint64(len(c.UnknownPayload))
@@ -104,7 +104,7 @@ func (c *ColrBox) EncodeSW(sw bits.SliceWriter) error {
 	}
 	sw.WriteString(c.ColorType, false)
 	switch c.ColorType {
-	case onScreenColors:
+	case ColorTypeOnScreenColors:
 		sw.WriteUint16(c.ColorPrimaries)
 		sw.WriteUint16(c.TransferCharacteristics)
 		sw.WriteUint16(c.MatrixCoefficients)
@@ -113,9 +113,9 @@ func (c *ColrBox) EncodeSW(sw bits.SliceWriter) error {
 			b = fullRangeBit
 		}
 		sw.WriteUint8(b)
-	case restrictedICCType, unrestrictedICCType:
+	case ColorTypeRestrictedICCProfile, ColorTypeUnrestrictedICCTProfile:
 		sw.WriteBytes(c.ICCProfile)
-	case quickTimeColorParameters:
+	case QuickTimeColorParameters:
 		sw.WriteUint16(c.ColorPrimaries)
 		sw.WriteUint16(c.TransferCharacteristics)
 		sw.WriteUint16(c.MatrixCoefficients)
@@ -130,12 +130,12 @@ func (c *ColrBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string
 	bd := newInfoDumper(w, indent, c, -1, 0)
 	bd.write(" - colorType: %s", c.ColorType)
 	switch c.ColorType {
-	case onScreenColors:
+	case ColorTypeOnScreenColors:
 		bd.write(" - ColorPrimaries: %d, TransferCharacteristics: %d, MatrixCoefficients: %d, FullRange: %t",
 			c.ColorPrimaries, c.TransferCharacteristics, c.MatrixCoefficients, c.FullRangeFlag)
-	case restrictedICCType, unrestrictedICCType:
+	case ColorTypeRestrictedICCProfile, ColorTypeUnrestrictedICCTProfile:
 		bd.write(" - ICCProfile: %s", hex.EncodeToString(c.ICCProfile))
-	case quickTimeColorParameters:
+	case QuickTimeColorParameters:
 		bd.write(" - ColorPrimaries: %d, TransferCharacteristics: %d, MatrixCoefficients: %d",
 			c.ColorPrimaries, c.TransferCharacteristics, c.MatrixCoefficients)
 	default:
diff --git a/mp4/free.go b/mp4/free.go
index 6651a3e..903602e 100644
--- a/mp4/free.go
+++ b/mp4/free.go
@@ -12,6 +12,21 @@ type FreeBox struct {
 	notDecoded []byte
 }
 
+// NewFreeBox creates a new FreeBox with arbitrary data payload.
+func NewFreeBox(data []byte) *FreeBox {
+	return &FreeBox{Name: "free", notDecoded: data}
+}
+
+// NewSkipBox creates a new SkipBox with arbitrary data payload.
+func NewSkipBox(data []byte) *FreeBox {
+	return &FreeBox{Name: "skip", notDecoded: data}
+}
+
+// Payload returns the payload of the box (everything after the box header)
+func (b *FreeBox) Payload() []byte {
+	return b.notDecoded
+}
+
 // DecodeFree - box-specific decode
 func DecodeFree(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
 	data, err := readBoxBody(r, hdr)
diff --git a/mp4/lou.go b/mp4/lou.go
index 38899e3..6aad69d 100644
--- a/mp4/lou.go
+++ b/mp4/lou.go
@@ -7,20 +7,17 @@ import (
 	"github.com/Eyevinn/mp4ff/bits"
 )
 
-// TlouBox - Track loudness info Box
-//
-// Contained in : Ludt Box (ludt)
-type TlouBox struct {
-	loudnessBaseBox
-}
-
-// TlouBox - Album loudness info Box
-//
-// Contained in : Ludt Box (ludt)
-type AlouBox struct {
-	loudnessBaseBox
+// LoudnessBaseBox according to ISO/IEC 14496-12 Section 12.2.7.2
+// TrackLoudnessInfo (tlou) and AudioLoudnessInfo (alou) boxes
+// are extensions of the LoudnessBaseBox.
+type LoudnessBaseBox struct {
+	Name          string
+	Version       byte
+	Flags         uint32
+	LoudnessBases []*LoudnessBase
 }
 
+// LoudnessBase provides a loudness entry in a LoudnessBaseBox
 type LoudnessBase struct {
 	EQSetID                uint8
 	DownmixID              uint8
@@ -29,27 +26,33 @@ type LoudnessBase struct {
 	BsTruePeakLevel        int16
 	MeasurementSystemForTP uint8
 	ReliabilityForTP       uint8
-	Measurements           []Measurement
+	Measurements           []LoudnessMeasurement
 }
 
-type Measurement struct {
+// LoudnessMeasurement provides a loudness measurement in a LoudnessBase.
+type LoudnessMeasurement struct {
 	MethodDefinition  uint8
 	MethodValue       uint8
 	MeasurementSystem uint8
 	Reliability       uint8
 }
 
-// loudnessBaseBox according to ISO/IEC 14496-12 Section 12.2.7.2
-type loudnessBaseBox struct {
-	Version       byte
-	Flags         uint32
-	LoudnessBases []*LoudnessBase
+// DecodeLoudnessBaseBox - box-specific decode
+func DecodeLoudnessBaseBox(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
+	data, err := readBoxBody(r, hdr)
+	if err != nil {
+		return nil, err
+	}
+	sr := bits.NewFixedSliceReader(data)
+	return DecodeLoudnessBaseBoxSR(hdr, startPos, sr)
 }
 
-func decodeLoudnessBaseBoxSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (*loudnessBaseBox, error) {
+// DecodeLoudnessBaseBoxSR - box-specific decode
+func DecodeLoudnessBaseBoxSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) {
 	versionAndFlags := sr.ReadUint32()
 	version := byte(versionAndFlags >> 24)
-	b := &loudnessBaseBox{
+	b := &LoudnessBaseBox{
+		Name:    hdr.Name,
 		Version: version,
 		Flags:   versionAndFlags & flagsMask,
 	}
@@ -81,9 +84,9 @@ func decodeLoudnessBaseBoxSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader
 		l.MeasurementSystemForTP = measurementSystemAndReliablityForTP >> 4
 		l.ReliabilityForTP = measurementSystemAndReliablityForTP & 0x0f
 		measurementCount := sr.ReadUint8()
-		l.Measurements = make([]Measurement, 0, measurementCount)
+		l.Measurements = make([]LoudnessMeasurement, 0, measurementCount)
 		for i := uint8(0); i < measurementCount; i++ {
-			m := Measurement{}
+			m := LoudnessMeasurement{}
 			m.MethodDefinition = sr.ReadUint8()
 			m.MethodValue = sr.ReadUint8()
 			measurementSystemAndReliablity := sr.ReadUint8()
@@ -96,8 +99,14 @@ func decodeLoudnessBaseBoxSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader
 	return b, nil
 }
 
-func (b *loudnessBaseBox) size() uint64 {
-	size := 4
+// Type of LoundessBaseBox, should be tlou or alou
+func (b *LoudnessBaseBox) Type() string {
+	return b.Name
+}
+
+// Size of LoudnessBaseBox.
+func (b *LoudnessBaseBox) Size() uint64 {
+	size := 12
 	if b.Version >= 1 {
 		size += 1
 	}
@@ -111,9 +120,9 @@ func (b *loudnessBaseBox) size() uint64 {
 	return uint64(size)
 }
 
-func (b *loudnessBaseBox) encode(w io.Writer) error {
-	sw := bits.NewFixedSliceWriter(int(b.size()))
-	err := b.encodeSW(sw)
+func (b *LoudnessBaseBox) Encode(w io.Writer) error {
+	sw := bits.NewFixedSliceWriter(int(b.Size()))
+	err := b.EncodeSW(sw)
 	if err != nil {
 		return err
 	}
@@ -121,7 +130,11 @@ func (b *loudnessBaseBox) encode(w io.Writer) error {
 	return err
 }
 
-func (b *loudnessBaseBox) encodeSW(sw bits.SliceWriter) error {
+func (b *LoudnessBaseBox) EncodeSW(sw bits.SliceWriter) error {
+	err := EncodeHeaderSW(b, sw)
+	if err != nil {
+		return err
+	}
 	versionAndFlags := (uint32(b.Version) << 24) + b.Flags
 	sw.WriteUint32(versionAndFlags)
 	if b.Version >= 1 {
@@ -150,10 +163,10 @@ func (b *loudnessBaseBox) encodeSW(sw bits.SliceWriter) error {
 	return sw.AccError()
 }
 
-func (b *loudnessBaseBox) info(realBox Box, w io.Writer, specificBoxLevels, indent, indentStep string) error {
-	bd := newInfoDumper(w, indent, realBox, int(b.Version), 0)
+func (b *LoudnessBaseBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
+	bd := newInfoDumper(w, indent, b, int(b.Version), 0)
 	bd.write(" - LoudnessBaseCount: %d", len(b.LoudnessBases))
-	level := getInfoLevel(realBox, specificBoxLevels)
+	level := getInfoLevel(b, specificBoxLevels)
 	if level >= 1 {
 		loudnessIndent := "     "
 		for a, l := range b.LoudnessBases {
@@ -180,107 +193,3 @@ func (b *loudnessBaseBox) info(realBox Box, w io.Writer, specificBoxLevels, inde
 	}
 	return bd.err
 }
-
-// DecodeTlou - box-specific decode
-func DecodeTlou(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
-	data, err := readBoxBody(r, hdr)
-	if err != nil {
-		return nil, err
-	}
-	sr := bits.NewFixedSliceReader(data)
-	return DecodeTlouSR(hdr, startPos, sr)
-}
-
-// DecodeTlouSR - box-specific decode
-func DecodeTlouSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) {
-	loudnessBaseBox, err := decodeLoudnessBaseBoxSR(hdr, startPos+hdr.Size, sr)
-	if err != nil {
-		return nil, err
-	}
-	return &TlouBox{loudnessBaseBox: *loudnessBaseBox}, nil
-}
-
-// Encode - write tlou container to w
-func (b *TlouBox) Encode(w io.Writer) error {
-	err := EncodeHeader(b, w)
-	if err != nil {
-		return err
-	}
-	return b.loudnessBaseBox.encode(w)
-}
-
-// Encode - write tlou container to sw
-func (b *TlouBox) EncodeSW(sw bits.SliceWriter) error {
-	err := EncodeHeaderSW(b, sw)
-	if err != nil {
-		return err
-	}
-	return b.loudnessBaseBox.encodeSW(sw)
-}
-
-// Type - return box type
-func (b *TlouBox) Type() string {
-	return "tlou"
-}
-
-// Size - calculated size of box
-func (b *TlouBox) Size() uint64 {
-	return b.loudnessBaseBox.size() + boxHeaderSize
-}
-
-// Info - write box-specific information
-func (b *TlouBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
-	return b.loudnessBaseBox.info(b, w, specificBoxLevels, indent, indentStep)
-}
-
-// DecodeAlou - box-specific decode
-func DecodeAlou(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
-	data, err := readBoxBody(r, hdr)
-	if err != nil {
-		return nil, err
-	}
-	sr := bits.NewFixedSliceReader(data)
-	return DecodeAlouBoxSR(hdr, startPos, sr)
-}
-
-// DecodeAlouSR - box-specific decode
-func DecodeAlouBoxSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) {
-	loudnessBaseBox, err := decodeLoudnessBaseBoxSR(hdr, startPos+hdr.Size, sr)
-	if err != nil {
-		return nil, err
-	}
-	return &AlouBox{loudnessBaseBox: *loudnessBaseBox}, nil
-}
-
-// Encode - write alou container to w
-func (b *AlouBox) Encode(w io.Writer) error {
-	err := EncodeHeader(b, w)
-	if err != nil {
-		return err
-	}
-	return b.loudnessBaseBox.encode(w)
-}
-
-// Encode - write alou container to sw
-func (b *AlouBox) EncodeSW(sw bits.SliceWriter) error {
-	err := EncodeHeaderSW(b, sw)
-	if err != nil {
-		return err
-	}
-	return b.loudnessBaseBox.encodeSW(sw)
-}
-
-// Type - return box type
-func (b *AlouBox) Type() string {
-	return "alou"
-}
-
-// Size - calculated size of box
-func (b *AlouBox) Size() uint64 {
-	return b.loudnessBaseBox.size() + boxHeaderSize
-}
-
-// Info - write box-specific information
-func (b *AlouBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
-	return b.loudnessBaseBox.info(b, w, specificBoxLevels, indent, indentStep)
-}
diff --git a/mp4/ludt.go b/mp4/ludt.go
index 83ba7ec..903c65e 100644
--- a/mp4/ludt.go
+++ b/mp4/ludt.go
@@ -10,8 +10,8 @@ import (
 //
 // Contained in : Udta Box (udta)
 type LudtBox struct {
-	Loudness      []*TlouBox
-	AlbumLoudness []*AlouBox
+	Loudness      []*LoudnessBaseBox
+	AlbumLoudness []*LoudnessBaseBox
 	Children      []Box
 }
 
@@ -43,11 +43,11 @@ func DecodeLudtSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, err
 
 // AddChild - add child box
 func (b *LudtBox) AddChild(child Box) {
-	switch box := child.(type) {
-	case *TlouBox:
-		b.Loudness = append(b.Loudness, box)
-	case *AlouBox:
-		b.AlbumLoudness = append(b.AlbumLoudness, box)
+	switch boxType := child.Type(); boxType {
+	case "tlou":
+		b.Loudness = append(b.Loudness, child.(*LoudnessBaseBox))
+	case "alou":
+		b.AlbumLoudness = append(b.AlbumLoudness, child.(*LoudnessBaseBox))
 	}
 	b.Children = append(b.Children, child)
 }
diff --git a/mp4/senc.go b/mp4/senc.go
index dc01da2..c731815 100644
--- a/mp4/senc.go
+++ b/mp4/senc.go
@@ -85,6 +85,28 @@ func (s *SencBox) AddSample(sample SencSample) error {
 	return nil
 }
 
+// SetPerSampleIVSize sets the per-sample IV size. Should be 0, 8 or 16.
+func (s *SencBox) SetPerSampleIVSize(size byte) {
+	s.perSampleIVSize = size
+}
+
+// PerSampleIVSize returns the per-sample IV size, 0 if not known yet.
+// This will be automatically determined when parsing the box, or when
+// adding samples. It can also be set explicitly.
+func (s *SencBox) PerSampleIVSize() byte {
+	if s.SampleCount == 0 {
+		return 0
+	}
+	return s.perSampleIVSize
+}
+
+// ReadButNotParsed returns true if box has been read but not parsed.
+// The parsing happens as a second step after perSampleIVSize is known.
+// ParseReadBox should be called to parse the box.
+func (s *SencBox) ReadButNotParsed() bool {
+	return s.readButNotParsed
+}
+
 // DecodeSenc - box-specific decode
 func DecodeSenc(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
 	if hdr.Size < 16 {
diff --git a/mp4/unknown.go b/mp4/unknown.go
index d5b4283..5efcd3b 100644
--- a/mp4/unknown.go
+++ b/mp4/unknown.go
@@ -24,6 +24,12 @@ func DecodeUnknown(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
 	return DecodeUnknownSR(hdr, startPos, sr)
 }
 
+// CreateUnknownBox creates an unknown box. Set the size to match
+// the payload size + header size to get a well-formed box.
+func CreateUnknownBox(name string, size uint64, payload []byte) *UnknownBox {
+	return &UnknownBox{name, size, payload}
+}
+
 // DecodeUnknownSR - decode an unknown box
 func DecodeUnknownSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) {
 	return &UnknownBox{hdr.Name, hdr.Size, sr.ReadBytes(hdr.payloadLen())}, sr.AccError()
@@ -39,6 +45,11 @@ func (b *UnknownBox) Size() uint64 {
 	return b.size
 }
 
+// Payload returns the (non-decoded) payload.
+func (b *UnknownBox) Payload() []byte {
+	return b.notDecoded
+}
+
 // Encode - write box to w
 func (b *UnknownBox) Encode(w io.Writer) error {
 	sw := bits.NewFixedSliceWriter(int(b.Size()))
diff --git a/mp4/uuid.go b/mp4/uuid.go
index 3715113..b5531f0 100644
--- a/mp4/uuid.go
+++ b/mp4/uuid.go
@@ -51,6 +51,33 @@ const (
 	UUIDPiffSenc = "a2394f52-5a9b-4f14-a244-6c427c648df4"
 )
 
+// NewTrfrfBox creates a new TfrfBox with values.
+// fragmentCount is the number of fragments, andb both
+// fragmentAbsoluteTimes and fragmentAbsoluteDurations must be slices of that length.
+func NewTfrfBox(fragmentCount byte, fragmentAbsoluteTimes, fragmentAbsoluteDurations []uint64) *UUIDBox {
+	return &UUIDBox{
+		uuid: mustCreateUUID(UUIDTfrf),
+		Tfrf: &TfrfData{
+			Version:                   0,
+			Flags:                     0,
+			FragmentCount:             fragmentCount,
+			FragmentAbsoluteTimes:     fragmentAbsoluteTimes,
+			FragmentAbsoluteDurations: fragmentAbsoluteDurations,
+		},
+	}
+}
+
+// NewTfxdBox creates a new TfxdBox with values.
+func NewTfxdBox(fragmentAbsoluteTime, fragmentAbsoluteDuration uint64) *UUIDBox {
+	return &UUIDBox{
+		uuid: mustCreateUUID(UUIDTfxd),
+		Tfxd: &TfxdData{
+			FragmentAbsoluteTime:     fragmentAbsoluteTime,
+			FragmentAbsoluteDuration: fragmentAbsoluteDuration,
+		},
+	}
+}
+
 // createUUID - create uuid from hex, uuid-formatted hex, or base64 string
 func createUUID(u string) (UUID, error) {
 	b, err := UnpackKey(u)


Test patch:
diff --git a/mp4/audiosampleentry_test.go b/mp4/audiosampleentry_test.go
index 0bfe761..49f6759 100644
--- a/mp4/audiosampleentry_test.go
+++ b/mp4/audiosampleentry_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestWriteReadOfAudioSampleEntry(t *testing.T) {
 	ascBytes := []byte{0x11, 0x90}
-	esds := CreateEsdsBox(ascBytes)
-	ase := CreateAudioSampleEntryBox("mp4a", 2, 16, 48000, esds)
+	esds := mp4.CreateEsdsBox(ascBytes)
+	ase := mp4.CreateAudioSampleEntryBox("mp4a", 2, 16, 48000, esds)
 	boxDiffAfterEncodeAndDecode(t, ase)
 	_, err := ase.RemoveEncryption()
 	expectedErrMsg := "is not encrypted: mp4a"
diff --git a/mp4/av1c_test.go b/mp4/av1c_test.go
index 4ec9b41..9e71863 100644
--- a/mp4/av1c_test.go
+++ b/mp4/av1c_test.go
@@ -1,13 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/av1"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncodeDecodeAvc1(t *testing.T) {
-	adc := Av1CBox{
+	adc := mp4.Av1CBox{
 		CodecConfRec: av1.CodecConfRec{
 			Version: 1,
 		},
diff --git a/mp4/benchmarks_srw_test.go b/mp4/benchmarks_srw_test.go
index e3d64c9..c608dd0 100644
--- a/mp4/benchmarks_srw_test.go
+++ b/mp4/benchmarks_srw_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestDecodEncodeFileSRW(t *testing.T) {
@@ -21,12 +22,12 @@ func TestDecodEncodeFileSRW(t *testing.T) {
 		rawOut := make([]byte, len(raw))
 		t.Run(testFile, func(t *testing.T) {
 			sr := bits.NewFixedSliceReader(raw)
-			f, err := DecodeFileSR(sr)
+			f, err := mp4.DecodeFileSR(sr)
 			if err != nil {
 				t.Error(err)
 			}
 			sw := bits.NewFixedSliceWriterFromSlice(rawOut)
-			f.FragEncMode = EncModeBoxTree
+			f.FragEncMode = mp4.EncModeBoxTree
 			err = f.EncodeSW(sw)
 			if err != nil {
 				t.Error(err)
@@ -48,7 +49,7 @@ func BenchmarkDecodeFileSR(b *testing.B) {
 		b.Run(testFile, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
 				sr := bits.NewFixedSliceReader(raw)
-				_, _ = DecodeFileSR(sr)
+				_, _ = mp4.DecodeFileSR(sr)
 			}
 		})
 	}
@@ -62,7 +63,7 @@ func BenchmarkEncodeFileSW(b *testing.B) {
 	for _, testFile := range testFiles {
 		raw, _ := os.ReadFile("testdata/" + testFile)
 		inBuf := bytes.NewBuffer(raw)
-		decFile, _ := DecodeFile(inBuf)
+		decFile, _ := mp4.DecodeFile(inBuf)
 		rawOut := make([]byte, len(raw))
 		b.Run(testFile, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
diff --git a/mp4/benchmarks_test.go b/mp4/benchmarks_test.go
index 85527e8..8cb9b09 100644
--- a/mp4/benchmarks_test.go
+++ b/mp4/benchmarks_test.go
@@ -1,9 +1,11 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"os"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestDecodEncodeFile(t *testing.T) {
@@ -20,12 +22,12 @@ func TestDecodEncodeFile(t *testing.T) {
 		outBuf := bytes.NewBuffer(rawOut)
 		t.Run(testFile, func(t *testing.T) {
 			buf := bytes.NewBuffer(raw)
-			f, err := DecodeFile(buf)
+			f, err := mp4.DecodeFile(buf)
 			if err != nil {
 				t.Error(err)
 			}
 			outBuf.Reset()
-			f.FragEncMode = EncModeBoxTree
+			f.FragEncMode = mp4.EncModeBoxTree
 			err = f.Encode(outBuf)
 			if err != nil {
 				t.Error(err)
@@ -47,7 +49,7 @@ func BenchmarkDecodeFile(b *testing.B) {
 		b.Run(testFile, func(b *testing.B) {
 			for i := 0; i < b.N; i++ {
 				buf := bytes.NewBuffer(raw)
-				_, _ = DecodeFile(buf)
+				_, _ = mp4.DecodeFile(buf)
 			}
 		})
 	}
@@ -61,7 +63,7 @@ func BenchmarkEncodeFile(b *testing.B) {
 	for _, testFile := range testFiles {
 		raw, _ := os.ReadFile("testdata/" + testFile)
 		inBuf := bytes.NewBuffer(raw)
-		decFile, _ := DecodeFile(inBuf)
+		decFile, _ := mp4.DecodeFile(inBuf)
 		rawOut := make([]byte, 0, len(raw))
 		outBuf := bytes.NewBuffer(rawOut)
 		b.Run(testFile, func(b *testing.B) {
diff --git a/mp4/box_test.go b/mp4/box_test.go
index 9b861bf..d21e0f7 100644
--- a/mp4/box_test.go
+++ b/mp4/box_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 // TestBadBoxAndRemoveBoxDecoder checks that we can avoid decoder error by removing a BoxDecode.
@@ -19,22 +20,22 @@ func TestBadBoxAndRemoveBoxDecoder(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(data)
-	_, err = DecodeBoxSR(0, sr)
+	_, err = mp4.DecodeBoxSR(0, sr)
 	if err == nil {
 		t.Errorf("reading bad meta box should have failed")
 	}
 	sr = bits.NewFixedSliceReader(data)
-	RemoveBoxDecoder("meta")
-	defer SetBoxDecoder("meta", DecodeMeta, DecodeMetaSR)
-	box, err := DecodeBoxSR(0, sr)
+	mp4.RemoveBoxDecoder("meta")
+	defer mp4.SetBoxDecoder("meta", mp4.DecodeMeta, mp4.DecodeMetaSR)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
-	_, ok := box.(*MetaBox)
+	_, ok := box.(*mp4.MetaBox)
 	if ok {
 		t.Errorf("box should not be MetaBox")
 	}
-	unknown, ok := box.(*UnknownBox)
+	unknown, ok := box.(*mp4.UnknownBox)
 	if !ok {
 		t.Errorf("box should be unknown")
 	}
@@ -52,11 +53,11 @@ func TestBadBoxAndRemoveBoxDecoder(t *testing.T) {
 }
 
 func TestFixed16and32(t *testing.T) {
-	f16 := Fixed16(256)
+	f16 := mp4.Fixed16(256)
 	if f16.String() != "1.0" {
 		t.Errorf("Fixed16(256) should be 1.0, not %s", f16.String())
 	}
-	f32 := Fixed32(65536)
+	f32 := mp4.Fixed32(65536)
 	if f16.String() != "1.0" {
 		t.Errorf("Fixed32(65536) should be 1.0, not %s", f32.String())
 	}
diff --git a/mp4/boxsr_test.go b/mp4/boxsr_test.go
index 6a1f209..3bba24a 100644
--- a/mp4/boxsr_test.go
+++ b/mp4/boxsr_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 // Test decode + encode file with slice reader and writer
@@ -22,11 +23,11 @@ func TestDecodeEncodeSRW(t *testing.T) {
 			t.Error(err)
 		}
 		sr := bits.NewFixedSliceReader(inData)
-		decFile, err := DecodeFileSR(sr)
+		decFile, err := mp4.DecodeFileSR(sr)
 		if err != nil {
 			t.Error(err)
 		}
-		decFile.FragEncMode = EncModeBoxTree
+		decFile.FragEncMode = mp4.EncModeBoxTree
 		sw := bits.NewFixedSliceWriter(len(inData))
 		err = decFile.EncodeSW(sw)
 		if err != nil {
diff --git a/mp4/btrt_test.go b/mp4/btrt_test.go
index 10c4f5d..31fa02b 100644
--- a/mp4/btrt_test.go
+++ b/mp4/btrt_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestBtrt(t *testing.T) {
 
-	boxes := []Box{
-		&BtrtBox{
+	boxes := []mp4.Box{
+		&mp4.BtrtBox{
 			BufferSizeDB: 123456,
 			MaxBitrate:   2000000,
 			AvgBitrate:   1500000,
diff --git a/mp4/cdat_test.go b/mp4/cdat_test.go
index 581da22..06a39fb 100644
--- a/mp4/cdat_test.go
+++ b/mp4/cdat_test.go
@@ -1,10 +1,14 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestEncodeDecodeCdat(t *testing.T) {
 
-	cdat := CdatBox{
+	cdat := mp4.CdatBox{
 		Data: []byte{0x01, 0x02, 0x03, 0x04},
 	}
 	boxDiffAfterEncodeAndDecode(t, &cdat)
diff --git a/mp4/clap_test.go b/mp4/clap_test.go
index c3e2953..b5e604b 100644
--- a/mp4/clap_test.go
+++ b/mp4/clap_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncDecClap(t *testing.T) {
 
-	b := &ClapBox{
+	b := &mp4.ClapBox{
 		CleanApertureWidthN: 1, CleanApertureWidthD: 2,
 		CleanApertureHeightN: 3, CleanApertureHeightD: 4,
 		HorizOffN: 5, HorizOffD: 6,
diff --git a/mp4/co64_test.go b/mp4/co64_test.go
index 9c38049..385a169 100644
--- a/mp4/co64_test.go
+++ b/mp4/co64_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncDecCo64(t *testing.T) {
 
-	b := &Co64Box{
+	b := &mp4.Co64Box{
 		Version:     0,
 		Flags:       2, // Just in test
 		ChunkOffset: []uint64{1234, 8908080},
diff --git a/mp4/coll_test.go b/mp4/coll_test.go
index 4c08f2e..b2f1005 100644
--- a/mp4/coll_test.go
+++ b/mp4/coll_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"fmt"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestCoLL(t *testing.T) {
 	// Create a sample CoLL box with test values
-	coll := CreateCoLLBox(
+	coll := mp4.CreateCoLLBox(
 		1000, // maxCLL
 		500,  // maxFALL
 	)
diff --git a/mp4/colr_test.go b/mp4/colr_test.go
index 91f758d..a2c6b67 100644
--- a/mp4/colr_test.go
+++ b/mp4/colr_test.go
@@ -1,36 +1,38 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestColrEncodeDecode(t *testing.T) {
-	cases := []ColrBox{
+	cases := []mp4.ColrBox{
 		{
-			ColorType:               onScreenColors,
+			ColorType:               mp4.ColorTypeOnScreenColors,
 			ColorPrimaries:          9,
 			TransferCharacteristics: 16,
 			MatrixCoefficients:      9,
 			FullRangeFlag:           true,
 		},
 		{
-			ColorType:               onScreenColors,
+			ColorType:               mp4.ColorTypeOnScreenColors,
 			ColorPrimaries:          9,
 			TransferCharacteristics: 16,
 			MatrixCoefficients:      9,
 			FullRangeFlag:           false,
 		},
 		{
-			ColorType:  restrictedICCType,
+			ColorType:  mp4.ColorTypeRestrictedICCProfile,
 			ICCProfile: []byte{1, 2, 2, 43, 4},
 		},
 		{
-			ColorType:  unrestrictedICCType,
+			ColorType:  mp4.ColorTypeUnrestrictedICCTProfile,
 			ICCProfile: []byte{1, 2, 2, 43, 4, 5},
 		},
 		{
-			ColorType:               quickTimeColorParameters,
+			ColorType:               mp4.QuickTimeColorParameters,
 			ColorPrimaries:          1,
 			TransferCharacteristics: 1,
 			MatrixCoefficients:      1,
@@ -47,12 +49,12 @@ func TestColrEncodeDecode(t *testing.T) {
 
 func TestColrInfo(t *testing.T) {
 	cases := []struct {
-		cb     ColrBox
+		cb     mp4.ColrBox
 		wanted string
 	}{
 		{
-			cb: ColrBox{
-				ColorType:               onScreenColors,
+			cb: mp4.ColrBox{
+				ColorType:               mp4.ColorTypeOnScreenColors,
 				ColorPrimaries:          9,
 				TransferCharacteristics: 9,
 				MatrixCoefficients:      16,
@@ -62,8 +64,8 @@ func TestColrInfo(t *testing.T) {
 				"TransferCharacteristics: 9, MatrixCoefficients: 16, FullRange: true\n"),
 		},
 		{
-			cb: ColrBox{
-				ColorType:  restrictedICCType,
+			cb: mp4.ColrBox{
+				ColorType:  mp4.ColorTypeRestrictedICCProfile,
 				ICCProfile: []byte{0x02, 0x04},
 			},
 			wanted: "[colr] size=14\n - colorType: rICC\n - ICCProfile: 0204\n",
diff --git a/mp4/container_test.go b/mp4/container_test.go
index 184369e..1ca314c 100644
--- a/mp4/container_test.go
+++ b/mp4/container_test.go
@@ -1,14 +1,16 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestGenericContainer(t *testing.T) {
 	// Just check that it doesn't crash
-	c := NewGenericContainerBox("test")
-	c.AddChild(&VsidBox{SourceID: 42})
+	c := mp4.NewGenericContainerBox("test")
+	c.AddChild(&mp4.VsidBox{SourceID: 42})
 	w := bytes.Buffer{}
 	err := c.Encode(&w)
 	if err != nil {
diff --git a/mp4/crypto_test.go b/mp4/crypto_test.go
index 3dc076e..05acb1b 100644
--- a/mp4/crypto_test.go
+++ b/mp4/crypto_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -9,12 +9,13 @@ import (
 
 	"github.com/Eyevinn/mp4ff/avc"
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestFindAVCSubsampleRanges(t *testing.T) {
 	infile := "testdata/1.m4s"
-	fmp4, err := ReadMP4File(infile)
+	fmp4, err := mp4.ReadMP4File(infile)
 	if err != nil {
 		t.Error(err)
 	}
@@ -44,11 +45,11 @@ func TestFindAVCSubsampleRanges(t *testing.T) {
 	}
 	testCases := []struct {
 		scheme         string
-		expectedRanges [][]SubSamplePattern
+		expectedRanges [][]mp4.SubSamplePattern
 	}{
 		{
 			scheme: "cenc",
-			expectedRanges: [][]SubSamplePattern{
+			expectedRanges: [][]mp4.SubSamplePattern{
 				{{BytesOfClearData: 906, BytesOfProtectedData: 2224}},
 				{{BytesOfClearData: 103, BytesOfProtectedData: 80}},
 				{{BytesOfClearData: 104, BytesOfProtectedData: 64}},
@@ -61,7 +62,7 @@ func TestFindAVCSubsampleRanges(t *testing.T) {
 		},
 		{
 			scheme: "cbcs",
-			expectedRanges: [][]SubSamplePattern{
+			expectedRanges: [][]mp4.SubSamplePattern{
 				{{BytesOfClearData: 805, BytesOfProtectedData: 2325}},
 				{{BytesOfClearData: 10, BytesOfProtectedData: 173}},
 				{{BytesOfClearData: 13, BytesOfProtectedData: 155}},
@@ -83,7 +84,7 @@ func TestFindAVCSubsampleRanges(t *testing.T) {
 			for _, nalu := range nalus {
 				t.Logf("Sample %d: NALU %d %dB\n", i+1, avc.GetNaluType(nalu[0]), len(nalu))
 			}
-			protectRanges, err := GetAVCProtectRanges(spsMap, ppsMap, data, tc.scheme)
+			protectRanges, err := mp4.GetAVCProtectRanges(spsMap, ppsMap, data, tc.scheme)
 			if err != nil {
 				t.Error(err)
 			}
@@ -107,17 +108,17 @@ func TestEncryptDecrypt(t *testing.T) {
 	ivHex16 := "ffeeddccbbaa99887766554433221100"
 	kidHex := "11112222333344445555666677778888"
 	key, _ := hex.DecodeString(keyHex)
-	kidUUID, _ := NewUUIDFromString(kidHex)
+	kidUUID, _ := mp4.NewUUIDFromString(kidHex)
 	psshFile := "testdata/pssh.bin"
 	psh, err := os.Open(psshFile)
 	if err != nil {
 		t.Fatal(err)
 	}
-	box, err := DecodeBox(0, psh)
+	box, err := mp4.DecodeBox(0, psh)
 	if err != nil {
 		t.Fatal(err)
 	}
-	pssh := box.(*PsshBox)
+	pssh := box.(*mp4.PsshBox)
 
 	testCases := []struct {
 		desc    string
@@ -141,7 +142,7 @@ func TestEncryptDecrypt(t *testing.T) {
 			if err != nil {
 				t.Fatal(err)
 			}
-			init, err := DecodeFile(ifh)
+			init, err := mp4.DecodeFile(ifh)
 			ifh.Close()
 			if err != nil {
 				t.Fatal(err)
@@ -151,12 +152,12 @@ func TestEncryptDecrypt(t *testing.T) {
 				t.Fatal(err)
 			}
 
-			var psshs []*PsshBox
+			var psshs []*mp4.PsshBox
 			if c.hasPssh {
-				psshs = []*PsshBox{pssh}
+				psshs = []*mp4.PsshBox{pssh}
 			}
 
-			ipf, err := InitProtect(init.Init, key, iv, c.scheme, kidUUID, psshs)
+			ipf, err := mp4.InitProtect(init.Init, key, iv, c.scheme, kidUUID, psshs)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -168,7 +169,7 @@ func TestEncryptDecrypt(t *testing.T) {
 			}
 
 			// Check that one can extract the protection the InitProtectData from the init segment
-			ipd, err := ExtractInitProtectData(init.Init)
+			ipd, err := mp4.ExtractInitProtectData(init.Init)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -183,13 +184,13 @@ func TestEncryptDecrypt(t *testing.T) {
 				t.Fatal(err)
 			}
 			rs := bytes.NewBuffer(rawSeg)
-			seg, err := DecodeFile(rs)
+			seg, err := mp4.DecodeFile(rs)
 			if err != nil {
 				t.Fatal(err)
 			}
 			for _, s := range seg.Segments {
 				for _, f := range s.Fragments {
-					err := EncryptFragment(f, key, iv, ipf)
+					err := mp4.EncryptFragment(f, key, iv, ipf)
 					if err != nil {
 						t.Error(err)
 					}
@@ -203,24 +204,24 @@ func TestEncryptDecrypt(t *testing.T) {
 			// Get decrypt info from init segment
 			encInitRaw := encInitBuf.Bytes()
 			sr := bits.NewFixedSliceReader(encInitRaw)
-			encInit, err := DecodeFileSR(sr)
+			encInit, err := mp4.DecodeFileSR(sr)
 			if err != nil {
 				t.Error(err)
 			}
-			decInfo, err := DecryptInit(encInit.Init)
+			decInfo, err := mp4.DecryptInit(encInit.Init)
 			if err != nil {
 				t.Error(err)
 			}
 
 			// Decode and decrypt the written segment
 			sr = bits.NewFixedSliceReader(outBuf.Bytes())
-			decode, err := DecodeFileSR(sr)
+			decode, err := mp4.DecodeFileSR(sr)
 			if err != nil {
 				t.Error(err)
 			}
 			// Decrypt the segment
 			for _, s := range decode.Segments {
-				err := DecryptSegment(s, decInfo, key)
+				err := mp4.DecryptSegment(s, decInfo, key)
 				if err != nil {
 					t.Error(err)
 				}
@@ -239,13 +240,13 @@ func TestEncryptDecrypt(t *testing.T) {
 			// Make a new encryption to check that the decrypted segment is OK
 			// for re-encryption (Issue #378).
 
-			pd2, err := InitProtect(encInit.Init, key, iv, c.scheme, kidUUID, nil)
+			pd2, err := mp4.InitProtect(encInit.Init, key, iv, c.scheme, kidUUID, nil)
 			if err != nil {
 				t.Error(err)
 			}
 			for _, s := range decode.Segments {
 				for _, f := range s.Fragments {
-					err := EncryptFragment(f, key, iv, pd2)
+					err := mp4.EncryptFragment(f, key, iv, pd2)
 					if err != nil {
 						t.Errorf("Error re-encrypting fragment: %v\n", err)
 					}
@@ -257,12 +258,12 @@ func TestEncryptDecrypt(t *testing.T) {
 
 func TestDecryptInit(t *testing.T) {
 	encFile := "testdata/prog_8s_enc_dashinit.mp4"
-	mp4f, err := ReadMP4File(encFile)
+	mp4f, err := mp4.ReadMP4File(encFile)
 	if err != nil {
 		t.Error(err)
 	}
 	init := mp4f.Init
-	decInfo, err := DecryptInit(init)
+	decInfo, err := mp4.DecryptInit(init)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/cslg_test.go b/mp4/cslg_test.go
index 47fcb14..017eecc 100644
--- a/mp4/cslg_test.go
+++ b/mp4/cslg_test.go
@@ -1,9 +1,13 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestCslgEncodeDecode(t *testing.T) {
-	cslg := CslgBox{
+	cslg := mp4.CslgBox{
 		Version:                      0,
 		CompositionToDTSShift:        -100,
 		LeastDecodeToDisplayDelta:    200,
@@ -14,7 +18,7 @@ func TestCslgEncodeDecode(t *testing.T) {
 
 	boxDiffAfterEncodeAndDecode(t, &cslg)
 
-	cslg = CslgBox{
+	cslg = mp4.CslgBox{
 		Version:                      1,
 		CompositionToDTSShift:        -100,
 		LeastDecodeToDisplayDelta:    200,
diff --git a/mp4/ctts_test.go b/mp4/ctts_test.go
index 6f778a8..03205cb 100644
--- a/mp4/ctts_test.go
+++ b/mp4/ctts_test.go
@@ -1,9 +1,13 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestCtts(t *testing.T) {
-	ctts := &CttsBox{
+	ctts := &mp4.CttsBox{
 		Version: 0,
 		Flags:   0,
 	}
@@ -16,7 +20,7 @@ func TestCtts(t *testing.T) {
 }
 
 func TestGetCompositionTimeOffset(t *testing.T) {
-	ctts := &CttsBox{
+	ctts := &mp4.CttsBox{
 		Version: 0,
 		Flags:   0,
 	}
diff --git a/mp4/dac3_test.go b/mp4/dac3_test.go
index 7bbcb9a..b2f86a5 100644
--- a/mp4/dac3_test.go
+++ b/mp4/dac3_test.go
@@ -1,19 +1,20 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncodeDedodeAC3(t *testing.T) {
 	t.Run("normal-dac3", func(t *testing.T) {
-		dac3 := &Dac3Box{FSCod: 1, BSID: 2, ACMod: 3, LFEOn: 1, BitRateCode: 7}
+		dac3 := &mp4.Dac3Box{FSCod: 1, BSID: 2, ACMod: 3, LFEOn: 1, BitRateCode: 7}
 		boxDiffAfterEncodeAndDecode(t, dac3)
 	})
 	t.Run("weird-dac3", func(t *testing.T) {
-		dac3 := &Dac3Box{FSCod: 1, BSID: 2, ACMod: 3, LFEOn: 1, BitRateCode: 7, InitialZeroes: 4}
+		dac3 := &mp4.Dac3Box{FSCod: 1, BSID: 2, ACMod: 3, LFEOn: 1, BitRateCode: 7, InitialZeroes: 4}
 		boxDiffAfterEncodeAndDecode(t, dac3)
 	})
 }
@@ -25,11 +26,11 @@ func TestGetChannelInfo(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(dac3Bytes)
-	box, err := DecodeBoxSR(0, sr)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
-	dac3 := box.(*Dac3Box)
+	dac3 := box.(*mp4.Dac3Box)
 	gotNrChannels, gotChanmap := dac3.ChannelInfo()
 	if gotNrChannels != 6 {
 		t.Errorf("%d channels instead of 6", gotNrChannels)
diff --git a/mp4/dec3_test.go b/mp4/dec3_test.go
index 8cefc51..fb50077 100644
--- a/mp4/dec3_test.go
+++ b/mp4/dec3_test.go
@@ -1,16 +1,17 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncDecDec3(t *testing.T) {
-	b := &Dec3Box{DataRate: 448,
+	b := &mp4.Dec3Box{DataRate: 448,
 		NumIndSub: 0,
-		EC3Subs: []EC3Sub{
+		EC3Subs: []mp4.EC3Sub{
 			{FSCod: 2}},
 		Reserved: []byte{}}
 	boxDiffAfterEncodeAndDecode(t, b)
@@ -48,11 +49,11 @@ func TestGetChannelInfoDec3(t *testing.T) {
 			t.Error(err)
 		}
 		sr := bits.NewFixedSliceReader(dec3Bytes)
-		box, err := DecodeBoxSR(0, sr)
+		box, err := mp4.DecodeBoxSR(0, sr)
 		if err != nil {
 			t.Error(err)
 		}
-		dec3 := box.(*Dec3Box)
+		dec3 := box.(*mp4.Dec3Box)
 		gotNrChannels, gotChanmap := dec3.ChannelInfo()
 		if gotNrChannels != tc.wantedNrChannels {
 			t.Errorf("got %d channels instead of %d", gotNrChannels, tc.wantedNrChannels)
diff --git a/mp4/descriptors_test.go b/mp4/descriptors_test.go
index 8588439..d9b5cd6 100644
--- a/mp4/descriptors_test.go
+++ b/mp4/descriptors_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
@@ -32,11 +33,11 @@ func TestDecodeDescriptor(t *testing.T) {
 				t.Error(err)
 			}
 			sr := bits.NewFixedSliceReader(data)
-			desc, err := DecodeESDescriptor(sr, uint32(len(data)))
+			desc, err := mp4.DecodeESDescriptor(sr, uint32(len(data)))
 			if err != nil {
 				t.Error(err)
 			}
-			if desc.Tag() != ES_DescrTag {
+			if desc.Tag() != mp4.ES_DescrTag {
 				t.Error("tag is not 3")
 			}
 			out := make([]byte, len(data))
@@ -119,7 +120,7 @@ func TestDescriptorInfo(t *testing.T) {
 				t.Error(err)
 			}
 			sr := bits.NewFixedSliceReader(data)
-			desc, err := DecodeESDescriptor(sr, uint32(len(data)))
+			desc, err := mp4.DecodeESDescriptor(sr, uint32(len(data)))
 			if err != nil {
 				t.Error(err)
 			}
@@ -147,7 +148,7 @@ func TestDescriptorInfo(t *testing.T) {
 func TestRawDescriptor(t *testing.T) {
 	sizeSizeMinus1 := 0
 	data := []byte{0x02, 0x03}
-	rd, err := CreateRawDescriptor(15, byte(sizeSizeMinus1), data)
+	rd, err := mp4.CreateRawDescriptor(15, byte(sizeSizeMinus1), data)
 	if err != nil {
 		t.Error(err)
 	}
@@ -173,11 +174,11 @@ func TestRawDescriptor(t *testing.T) {
 	}
 	totNrBytes := rd.SizeSize()
 	rw := bits.NewFixedSliceReader(sw.Bytes())
-	rdDec, err := DecodeDescriptor(rw, int(totNrBytes))
+	rdDec, err := mp4.DecodeDescriptor(rw, int(totNrBytes))
 	if err != nil {
 		t.Error(err)
 	}
-	rawDec := rdDec.(*RawDescriptor)
+	rawDec := rdDec.(*mp4.RawDescriptor)
 	if diff := deep.Equal(rawDec, &rd); diff != nil {
 		t.Error(diff)
 	}
diff --git a/mp4/dref_test.go b/mp4/dref_test.go
index 481d78d..051a852 100644
--- a/mp4/dref_test.go
+++ b/mp4/dref_test.go
@@ -1,16 +1,17 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 const data = `000000326472656600000000000000010000002275726c200000000168747470733a2f2f666c7573736f6e69632e636f6d2f`
 
 func TestDref(t *testing.T) {
-	dref := CreateDref()
+	dref := mp4.CreateDref()
 	boxDiffAfterEncodeAndDecode(t, dref)
 }
 
@@ -20,7 +21,7 @@ func TestDrefDecode(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(d)
-	box, err := DecodeBoxSR(0, sr)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/edts_test.go b/mp4/edts_test.go
index 9608afb..3b4d357 100644
--- a/mp4/edts_test.go
+++ b/mp4/edts_test.go
@@ -1,32 +1,33 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"reflect"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestEncodeDecodeEdts(t *testing.T) {
 
-	elst := &ElstBox{
+	elst := &mp4.ElstBox{
 		Version: 0,
 		Flags:   0,
-		Entries: []ElstEntry{{1000, 1234, 1, 1}},
+		Entries: []mp4.ElstEntry{{1000, 1234, 1, 1}},
 	}
-	edts := &EdtsBox{}
+	edts := &mp4.EdtsBox{}
 	edts.AddChild(elst)
 	buf := bytes.Buffer{}
 	err := edts.Encode(&buf)
 	if err != nil {
 		t.Error(err)
 	}
-	box, err := DecodeBox(0, &buf)
+	box, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error(err)
 	}
-	edts2 := box.(*EdtsBox)
+	edts2 := box.(*mp4.EdtsBox)
 	elst2 := edts2.Elst[0]
 	if !reflect.DeepEqual(elst, elst2) {
 		t.Errorf("elst box not equal after decode: %s", deep.Equal(elst, elst2))
diff --git a/mp4/elng_test.go b/mp4/elng_test.go
index e2a679c..57dd107 100644
--- a/mp4/elng_test.go
+++ b/mp4/elng_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestDecodeElng(t *testing.T) {
 
-	elng := &ElngBox{Language: "en-US"}
+	elng := &mp4.ElngBox{Language: "en-US"}
 	boxDiffAfterEncodeAndDecode(t, elng)
 }
 
@@ -15,11 +17,11 @@ func TestDecodeElng(t *testing.T) {
 func TestElngWithoutFullBox(t *testing.T) {
 	data := []byte("\x00\x00\x00\x0belngdk\x00")
 	bufIn := bytes.NewBuffer(data)
-	box, err := DecodeBox(0, bufIn)
+	box, err := mp4.DecodeBox(0, bufIn)
 	if err != nil {
 		t.Errorf("could not decode elng")
 	}
-	elng := box.(*ElngBox)
+	elng := box.(*mp4.ElngBox)
 	if !elng.MissingFullBoxBytes() {
 		t.Errorf("missing full box not set")
 	}
@@ -37,11 +39,11 @@ func TestFixElngMissingFullBoxBytes(t *testing.T) {
 	dataIn := []byte("\x00\x00\x00\x0belngdk\x00")
 	dataOut := []byte("\x00\x00\x00\x0felng\x00\x00\x00\x00dk\x00")
 	bufIn := bytes.NewBuffer(dataIn)
-	box, err := DecodeBox(0, bufIn)
+	box, err := mp4.DecodeBox(0, bufIn)
 	if err != nil {
 		t.Errorf("could not decode elng")
 	}
-	elng := box.(*ElngBox)
+	elng := box.(*mp4.ElngBox)
 	if !elng.MissingFullBoxBytes() {
 		t.Errorf("missing full box not set")
 	}
diff --git a/mp4/elst_test.go b/mp4/elst_test.go
index 97915b0..8d061c9 100644
--- a/mp4/elst_test.go
+++ b/mp4/elst_test.go
@@ -1,23 +1,25 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestElst(t *testing.T) {
 
-	boxes := []Box{
-		&ElstBox{
+	boxes := []mp4.Box{
+		&mp4.ElstBox{
 			Version: 0,
 			Flags:   0,
-			Entries: []ElstEntry{
+			Entries: []mp4.ElstEntry{
 				{1000, 1234, 1, 1},
 			},
 		},
-		&ElstBox{
+		&mp4.ElstBox{
 			Version: 1,
 			Flags:   0,
-			Entries: []ElstEntry{
+			Entries: []mp4.ElstEntry{
 				{1000, 1234, 1, 1},
 			},
 		},
diff --git a/mp4/emsg_test.go b/mp4/emsg_test.go
index f809434..26c9e01 100644
--- a/mp4/emsg_test.go
+++ b/mp4/emsg_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
@@ -6,12 +6,13 @@ import (
 	"github.com/go-test/deep"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEmsg(t *testing.T) {
 
-	boxes := []Box{
-		&EmsgBox{Version: 1,
+	boxes := []mp4.Box{
+		&mp4.EmsgBox{Version: 1,
 			TimeScale:        90000,
 			PresentationTime: 10000000,
 			EventDuration:    90000,
@@ -19,14 +20,14 @@ func TestEmsg(t *testing.T) {
 			SchemeIDURI:      "https://aomedia.org/emsg/ID3",
 			Value:            "relative",
 		},
-		&EmsgBox{Version: 0,
+		&mp4.EmsgBox{Version: 0,
 			TimeScale:             90000,
 			PresentationTimeDelta: 45000,
 			EventDuration:         90000,
 			ID:                    42,
 			SchemeIDURI:           "schid",
 			Value:                 "special"},
-		&EmsgBox{Version: 1,
+		&mp4.EmsgBox{Version: 1,
 			TimeScale:        90000,
 			PresentationTime: 10000000,
 			EventDuration:    90000,
@@ -35,7 +36,7 @@ func TestEmsg(t *testing.T) {
 			Value:            "relative",
 			MessageData:      []byte{73, 68, 51, 4, 0, 32, 0, 0, 2, 5, 80, 82, 73, 86, 0, 0, 1, 123, 0, 0, 119, 119, 119},
 		},
-		&EmsgBox{Version: 0,
+		&mp4.EmsgBox{Version: 0,
 			TimeScale:             90000,
 			PresentationTimeDelta: 45000,
 			EventDuration:         90000,
@@ -52,7 +53,7 @@ func TestEmsg(t *testing.T) {
 
 func TestEmsgMessageDataIsEncoded(t *testing.T) {
 
-	b1 := EmsgBox{Version: 1,
+	b1 := mp4.EmsgBox{Version: 1,
 		TimeScale:        90000,
 		PresentationTime: 10000000,
 		EventDuration:    90000,
@@ -62,7 +63,7 @@ func TestEmsgMessageDataIsEncoded(t *testing.T) {
 		MessageData:      []byte{73, 68, 51, 4, 0, 32, 0, 0, 2, 5, 80, 82, 73, 86, 0, 0, 1, 123, 0, 0, 119, 119, 119},
 	}
 
-	b2 := EmsgBox{Version: 1,
+	b2 := mp4.EmsgBox{Version: 1,
 		TimeScale:        90000,
 		PresentationTime: 10000000,
 		EventDuration:    90000,
@@ -89,5 +90,4 @@ func TestEmsgMessageDataIsEncoded(t *testing.T) {
 	if diff := deep.Equal(b1writer.Bytes(), b2writer.Bytes()); diff == nil {
 		t.Error("Different emsg boxes have the same encoded data")
 	}
-
 }
diff --git a/mp4/esds_test.go b/mp4/esds_test.go
index 160a131..d4ac184 100644
--- a/mp4/esds_test.go
+++ b/mp4/esds_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 const (
@@ -19,7 +20,7 @@ const (
 func TestEsdsEncodeAndDecode(t *testing.T) {
 	decCfg := []byte{0x11, 0x90}
 
-	esdsIn := CreateEsdsBox(decCfg)
+	esdsIn := mp4.CreateEsdsBox(decCfg)
 
 	// Write to a buffer so that we can read and check
 	var buf bytes.Buffer
@@ -29,11 +30,11 @@ func TestEsdsEncodeAndDecode(t *testing.T) {
 	}
 
 	// Read back from buffer
-	decodedBox, err := DecodeBox(0, &buf)
+	decodedBox, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error("Did not get a box back")
 	}
-	esdsOut := decodedBox.(*EsdsBox)
+	esdsOut := decodedBox.(*mp4.EsdsBox)
 	decCfgOut := esdsOut.DecConfigDescriptor.DecSpecificInfo.DecConfig
 	if !bytes.Equal(decCfgOut, decCfg) {
 		t.Errorf("Decode cfg out %s differs from decode cfg in %s",
@@ -50,7 +51,7 @@ func TestDecodeEncodeEsds(t *testing.T) {
 			t.Error(err)
 		}
 		sr := bits.NewFixedSliceReader(data)
-		esds, err := DecodeBoxSR(0, sr)
+		esds, err := mp4.DecodeBoxSR(0, sr)
 		if err != nil {
 			t.Error(err)
 		}
diff --git a/mp4/eventmessage_test.go b/mp4/eventmessage_test.go
index 57f276c..5a1ac38 100644
--- a/mp4/eventmessage_test.go
+++ b/mp4/eventmessage_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEvteDecode(t *testing.T) {
@@ -16,11 +17,11 @@ func TestEvteDecode(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(data)
-	box, err := DecodeBoxSR(0, sr)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
-	evte := box.(*EvteBox)
+	evte := box.(*mp4.EvteBox)
 	if evte.DataReferenceIndex != 1 {
 		t.Errorf("Wrong DataReferenceIndex %d", evte.DataReferenceIndex)
 	}
@@ -31,10 +32,10 @@ func TestEvteDecode(t *testing.T) {
 }
 
 func TestEvteInclSilb(t *testing.T) {
-	silb := SilbBox{
+	silb := mp4.SilbBox{
 		Version: 0,
 		Flags:   0,
-		Schemes: []SilbEntry{
+		Schemes: []mp4.SilbEntry{
 			{
 				SchemeIdURI:    "urn:mpeg:dash:event:2012",
 				Value:          "event1",
@@ -43,7 +44,7 @@ func TestEvteInclSilb(t *testing.T) {
 		},
 	}
 	boxDiffAfterEncodeAndDecode(t, &silb)
-	evte := EvteBox{
+	evte := mp4.EvteBox{
 		DataReferenceIndex: 1,
 	}
 	evte.AddChild(&silb)
@@ -58,11 +59,11 @@ func TestEmib(t *testing.T) {
 			t.Error(err)
 		}
 		buf := bytes.NewBuffer(data)
-		box, err := DecodeBox(0, buf)
+		box, err := mp4.DecodeBox(0, buf)
 		if err != nil {
 			t.Error(err)
 		}
-		emib := box.(*EmibBox)
+		emib := box.(*mp4.EmibBox)
 		if emib.SchemeIdURI != scteSchemeIdURI {
 			t.Errorf("Wrong SchemeIdURI %s", emib.SchemeIdURI)
 		}
@@ -76,7 +77,7 @@ func TestEmib(t *testing.T) {
 		}
 	})
 	t.Run("EncodeDecodeEmib", func(t *testing.T) {
-		emib := EmibBox{
+		emib := mp4.EmibBox{
 			Version:               0,
 			Flags:                 0,
 			PresentationTimeDelta: -1000,
@@ -91,6 +92,6 @@ func TestEmib(t *testing.T) {
 }
 
 func TestEmeb(t *testing.T) {
-	emeb := EmebBox{}
+	emeb := mp4.EmebBox{}
 	boxDiffAfterEncodeAndDecode(t, &emeb)
 }
diff --git a/mp4/ffmpeg_test.go b/mp4/ffmpeg_test.go
index 7508b40..714e35f 100644
--- a/mp4/ffmpeg_test.go
+++ b/mp4/ffmpeg_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestDecodeFFMpeg(t *testing.T) {
@@ -15,11 +16,11 @@ func TestDecodeFFMpeg(t *testing.T) {
 		t.Error(err)
 	}
 	buf := bytes.NewBuffer(raw)
-	box, err := DecodeBox(0, buf)
+	box, err := mp4.DecodeBox(0, buf)
 	if err != nil {
 		t.Error(err)
 	}
-	ilst := box.(*IlstBox)
+	ilst := box.(*mp4.IlstBox)
 	sw := bits.NewFixedSliceWriter(int(ilst.Size()))
 	err = ilst.EncodeSW(sw)
 	if err != nil {
@@ -33,6 +34,6 @@ func TestDecodeFFMpeg(t *testing.T) {
 
 func TestEncodeData(t *testing.T) {
 	data := []byte("dummy")
-	db := &DataBox{Data: data}
+	db := &mp4.DataBox{Data: data}
 	boxDiffAfterEncodeAndDecode(t, db)
 }
diff --git a/mp4/file_test.go b/mp4/file_test.go
index 8aec4a5..317a8a3 100644
--- a/mp4/file_test.go
+++ b/mp4/file_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -8,6 +8,7 @@ import (
 
 	"github.com/Eyevinn/mp4ff/aac"
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestDecodeFileWithLazyMdatOption(t *testing.T) {
@@ -18,7 +19,7 @@ func TestDecodeFileWithLazyMdatOption(t *testing.T) {
 		t.Error(err)
 	}
 
-	parsedFile, err := DecodeFile(file, WithDecodeMode(DecModeLazyMdat))
+	parsedFile, err := mp4.DecodeFile(file, mp4.WithDecodeMode(mp4.DecModeLazyMdat))
 	if err != nil {
 		t.Error(err)
 	}
@@ -44,15 +45,15 @@ func TestDecodeFileWithNoLazyMdatOption(t *testing.T) {
 		t.Error(err)
 	}
 
-	parsedFile, err := DecodeFile(file)
+	parsedFile, err := mp4.DecodeFile(file)
 	if err != nil {
 		t.Error(err)
 	}
 
 	for _, seg := range parsedFile.Segments {
 		for _, frag := range seg.Fragments {
-			if frag.Mdat.lazyDataSize != 0 {
-				t.Error("decLazyDataSize is expected to be 0")
+			if frag.Mdat.IsLazy() {
+				t.Error("mdat box is expected to be non-lazy")
 			}
 			if len(frag.Mdat.Data) == 0 {
 				t.Error("Mdat Data is expected to be non-nil")
@@ -79,13 +80,13 @@ func TestCopyTrackSampleData(t *testing.T) {
 			t.Error(err)
 		}
 		defer fd.Close()
-		var mp4f *File
+		var mp4f *mp4.File
 		var workSpace []byte
 		if tc.lazy {
-			mp4f, err = DecodeFile(fd, WithDecodeMode(DecModeLazyMdat))
+			mp4f, err = mp4.DecodeFile(fd, mp4.WithDecodeMode(mp4.DecModeLazyMdat))
 			workSpace = make([]byte, tc.workSpaceSize)
 		} else {
-			mp4f, err = DecodeFile(fd)
+			mp4f, err = mp4.DecodeFile(fd)
 		}
 		if err != nil {
 			t.Error(err)
@@ -130,7 +131,7 @@ func TestDecodeEncode(t *testing.T) {
 		}
 		rawOutput := make([]byte, len(rawInput))
 		inBuf := bytes.NewBuffer(rawInput)
-		parsedFile, err := DecodeFile(inBuf)
+		parsedFile, err := mp4.DecodeFile(inBuf)
 		if err != nil {
 			t.Error(err)
 		}
@@ -160,7 +161,7 @@ func TestDecodeEncode(t *testing.T) {
 
 func TestFilesWithEmsg(t *testing.T) {
 	// File with ftyp, moov, styp, emsg, emsg, moof, mdat, moof, mdat
-	init := CreateEmptyInit()
+	init := mp4.CreateEmptyInit()
 	init.AddEmptyTrack(uint32(48000), "audio", "en")
 	trak := init.Moov.Trak
 	err := trak.SetAACDescriptor(aac.AAClc, 48000)
@@ -173,10 +174,10 @@ func TestFilesWithEmsg(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	seg := NewMediaSegment()
+	seg := mp4.NewMediaSegment()
 	frag := createFragment(t, 1, 1024, 0)
-	frag.AddEmsg(&EmsgBox{ID: 1})
-	frag.AddEmsg(&EmsgBox{ID: 2})
+	frag.AddEmsg(&mp4.EmsgBox{ID: 1})
+	frag.AddEmsg(&mp4.EmsgBox{ID: 2})
 	seg.AddFragment(frag)
 	frag = createFragment(t, 2, 1024, 1024)
 	seg.AddFragment(frag)
@@ -186,7 +187,7 @@ func TestFilesWithEmsg(t *testing.T) {
 	}
 	encData := buf.Bytes()
 	sr := bits.NewFixedSliceReader(encData)
-	decFile, err := DecodeFileSR(sr)
+	decFile, err := mp4.DecodeFileSR(sr)
 	if err != nil {
 		t.Error(err)
 	}
@@ -219,7 +220,7 @@ func TestFilesWithEmsg(t *testing.T) {
 
 func TestSegmentWith2Fragments(t *testing.T) {
 	// File styp, moof, mdat, moof, mdat
-	seg := NewMediaSegment()
+	seg := mp4.NewMediaSegment()
 	frag := createFragment(t, 1, 1024, 0)
 	seg.AddFragment(frag)
 	frag = createFragment(t, 2, 1024, 1024)
@@ -231,7 +232,7 @@ func TestSegmentWith2Fragments(t *testing.T) {
 	}
 	encData := buf.Bytes()
 	sr := bits.NewFixedSliceReader(encData)
-	decFile, err := DecodeFileSR(sr)
+	decFile, err := mp4.DecodeFileSR(sr)
 	if err != nil {
 		t.Error(err)
 	}
@@ -252,13 +253,13 @@ func TestSegmentWith2Fragments(t *testing.T) {
 	}
 }
 
-func createFragment(t *testing.T, seqNr, dur uint32, decTime uint64) *Fragment {
-	frag, err := CreateFragment(seqNr, 1)
+func createFragment(t *testing.T, seqNr, dur uint32, decTime uint64) *mp4.Fragment {
+	frag, err := mp4.CreateFragment(seqNr, 1)
 	if err != nil {
 		t.Fail()
 	}
-	frag.AddFullSample(FullSample{
-		Sample: Sample{
+	frag.AddFullSample(mp4.FullSample{
+		Sample: mp4.Sample{
 			Flags:                 0x0,
 			Dur:                   dur,
 			Size:                  6,
@@ -276,7 +277,7 @@ func TestGetSegmentBoundariesFromSidx(t *testing.T) {
 		t.Error(err)
 	}
 
-	parsedFile, err := DecodeFile(file, WithDecodeFlags(DecISMFlag))
+	parsedFile, err := mp4.DecodeFile(file, mp4.WithDecodeFlags(mp4.DecISMFlag))
 	if err != nil {
 		t.Error(err)
 	}
@@ -291,7 +292,7 @@ func TestGetSegmentBoundariesFromMfra(t *testing.T) {
 		t.Error(err)
 	}
 
-	parsedFile, err := DecodeFile(file, WithDecodeFlags(DecISMFlag))
+	parsedFile, err := mp4.DecodeFile(file, mp4.WithDecodeFlags(mp4.DecISMFlag))
 	if err != nil {
 		t.Error(err)
 	}
@@ -306,7 +307,7 @@ func TestUpdateSidx(t *testing.T) {
 		t.Error(err)
 	}
 
-	parsedFile, err := DecodeFile(file)
+	parsedFile, err := mp4.DecodeFile(file)
 	if err != nil {
 		t.Error(err)
 	}
@@ -343,7 +344,7 @@ func TestEmptyMdat(t *testing.T) {
 			t.Run(fmt.Sprintf("%s_readSlice_%t", tc.desc, readSlice), func(t *testing.T) {
 				buf := bytes.Buffer{}
 				for _, mdatSize := range tc.mdatSizes {
-					mdat := &MdatBox{}
+					mdat := &mp4.MdatBox{}
 					if mdatSize > 8 {
 						mdat.Data = make([]byte, mdatSize-8)
 					}
@@ -352,13 +353,13 @@ func TestEmptyMdat(t *testing.T) {
 						t.Error(err)
 					}
 				}
-				var decFile *File
+				var decFile *mp4.File
 				var err error
 				if readSlice {
 					sr := bits.NewFixedSliceReader(buf.Bytes())
-					decFile, err = DecodeFileSR(sr)
+					decFile, err = mp4.DecodeFileSR(sr)
 				} else {
-					decFile, err = DecodeFile(&buf)
+					decFile, err = mp4.DecodeFile(&buf)
 				}
 				if tc.expectedError != "" {
 					if err == nil {
diff --git a/mp4/fragment_test.go b/mp4/fragment_test.go
index bb809b0..75852da 100644
--- a/mp4/fragment_test.go
+++ b/mp4/fragment_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestCreateMultiTrackFragment(t *testing.T) {
 
 	trackIDs := []uint32{1, 2, 3}
-	mFrag, err := CreateMultiTrackFragment(1, trackIDs)
+	mFrag, err := mp4.CreateMultiTrackFragment(1, trackIDs)
 	if err != nil {
 		t.Error("Error creating MultiTrackFragment")
 	}
@@ -17,13 +19,13 @@ func TestCreateMultiTrackFragment(t *testing.T) {
 }
 
 func TestFragmentSampleIntervals(t *testing.T) {
-	frag, err := CreateFragment(12, 1)
+	frag, err := mp4.CreateFragment(12, 1)
 	if err != nil {
 		t.Error("Error creating Fragment")
 	}
-	s := NewSample(0, 100, 1, 0)
+	s := mp4.NewSample(0, 100, 1, 0)
 	frag.AddSample(s, 1230)
-	samples := []Sample{NewSample(0, 100, 2, 0), NewSample(0, 100, 3, 0), NewSample(0, 100, 4, 0)}
+	samples := []mp4.Sample{mp4.NewSample(0, 100, 2, 0), mp4.NewSample(0, 100, 3, 0), mp4.NewSample(0, 100, 4, 0)}
 	frag.AddSamples(samples, 1330)
 
 	sampleNr, err := frag.GetSampleNrFromTime(nil, 1430)
@@ -48,9 +50,9 @@ func TestFragmentSampleIntervals(t *testing.T) {
 		t.Error("Should have gotten error from CommonSampleDuration")
 	}
 
-	sampleItvl := SampleInterval{
+	sampleItvl := mp4.SampleInterval{
 		FirstDecodeTime: 1630,
-		Samples:         []Sample{{0, 100, 2, 0}},
+		Samples:         []mp4.Sample{{0, 100, 2, 0}},
 		OffsetInMdat:    0,
 		Data:            []byte{},
 	}
diff --git a/mp4/free_test.go b/mp4/free_test.go
index b956d02..6b4ed57 100644
--- a/mp4/free_test.go
+++ b/mp4/free_test.go
@@ -1,16 +1,21 @@
-package mp4
+package mp4_test
 
 import (
+	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestFree(t *testing.T) {
-	freeEmpty := &FreeBox{Name: "free"}
+	freeEmpty := mp4.NewFreeBox([]byte{})
 	boxDiffAfterEncodeAndDecode(t, freeEmpty)
 
-	free := &FreeBox{Name: "free", notDecoded: []byte{0, 1, 2, 3}}
-	boxDiffAfterEncodeAndDecode(t, free)
-
-	skip := &FreeBox{Name: "skip"}
+	emptySmall := mp4.NewFreeBox([]byte{0x01, 0x02})
+	boxDiffAfterEncodeAndDecode(t, emptySmall)
+	if !bytes.Equal(emptySmall.Payload(), []byte{0x01, 0x02}) {
+		t.Error("Payload not equal")
+	}
+	skip := mp4.NewSkipBox([]byte{0x02, 0x03})
 	boxDiffAfterEncodeAndDecode(t, skip)
 }
diff --git a/mp4/frma_test.go b/mp4/frma_test.go
index fb49e7a..1af346e 100644
--- a/mp4/frma_test.go
+++ b/mp4/frma_test.go
@@ -1,8 +1,12 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestFrma(t *testing.T) {
-	frma := &FrmaBox{DataFormat: "avc1"}
+	frma := &mp4.FrmaBox{DataFormat: "avc1"}
 	boxDiffAfterEncodeAndDecode(t, frma)
 }
diff --git a/mp4/ftyp_test.go b/mp4/ftyp_test.go
index bd016c2..6f2f457 100644
--- a/mp4/ftyp_test.go
+++ b/mp4/ftyp_test.go
@@ -1,11 +1,13 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestFtyp(t *testing.T) {
 
-	ftyp := CreateFtyp()
+	ftyp := mp4.CreateFtyp()
 	boxDiffAfterEncodeAndDecode(t, ftyp)
 }
diff --git a/mp4/fuzz_test.go b/mp4/fuzz_test.go
index bd23aab..b58f36a 100644
--- a/mp4/fuzz_test.go
+++ b/mp4/fuzz_test.go
@@ -1,7 +1,7 @@
 //go:build go1.18
 // +build go1.18
 
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -15,6 +15,7 @@ import (
 	"time"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func monitorMemory(ctx context.Context, t *testing.T, memoryLimit int) {
@@ -73,7 +74,7 @@ func FuzzDecodeBox(f *testing.F) {
 		r := bytes.NewReader(b)
 		var pos uint64 = 0
 		for {
-			box, err := DecodeBox(pos, r)
+			box, err := mp4.DecodeBox(pos, r)
 			if err != nil {
 				if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
 					break
@@ -88,7 +89,7 @@ func FuzzDecodeBox(f *testing.F) {
 		pos = 0
 		sr := bits.NewFixedSliceReader(b)
 		for {
-			box, err := DecodeBoxSR(pos, sr)
+			box, err := mp4.DecodeBoxSR(pos, sr)
 			if err != nil {
 				if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
 					break
diff --git a/mp4/hdlr_test.go b/mp4/hdlr_test.go
index 2b51438..b865a7b 100644
--- a/mp4/hdlr_test.go
+++ b/mp4/hdlr_test.go
@@ -1,9 +1,11 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestHdlr(t *testing.T) {
@@ -29,7 +31,7 @@ func TestHdlr(t *testing.T) {
 
 	for _, c := range cases {
 		t.Run(c.mediaType, func(t *testing.T) {
-			hdlr, err := CreateHdlr(c.mediaType)
+			hdlr, err := mp4.CreateHdlr(c.mediaType)
 			if c.expectedError != "" {
 				if err == nil {
 					t.Errorf("Expected error %s, but got nil", c.expectedError)
@@ -55,11 +57,11 @@ func TestHdlrDecodeMissingNullTermination(t *testing.T) {
 	hdlrExample := "0000002068646C72000000000000000049443332000000000000000000000000"
 	byteData, _ := hex.DecodeString(hdlrExample)
 	buf := bytes.NewBuffer(byteData)
-	box, err := DecodeBox(0, buf)
+	box, err := mp4.DecodeBox(0, buf)
 	if err != nil {
 		t.Error(err)
 	}
-	hdlr := box.(*HdlrBox)
+	hdlr := box.(*mp4.HdlrBox)
 	if hdlr.Size() != uint64(len(byteData)) {
 		t.Errorf("Got size %d instead of %d", hdlr.Size(), len(byteData))
 	}
diff --git a/mp4/helpers_test.go b/mp4/helpers_test.go
index ddff54a..e16a566 100644
--- a/mp4/helpers_test.go
+++ b/mp4/helpers_test.go
@@ -1,13 +1,16 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/binary"
 	"flag"
+	"fmt"
+	"io"
 	"os"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
@@ -24,7 +27,7 @@ func cmpAfterDecodeEncodeBox(t *testing.T, data []byte) {
 
 	// First SliceReader + SliceWriter
 	sr := bits.NewFixedSliceReader(data)
-	box, err := DecodeBoxSR(0, sr)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
@@ -38,7 +41,7 @@ func cmpAfterDecodeEncodeBox(t *testing.T, data []byte) {
 	}
 
 	bufIn := bytes.NewBuffer(data)
-	box, err = DecodeBox(0, bufIn)
+	box, err = mp4.DecodeBox(0, bufIn)
 	if err != nil {
 		t.Error(err)
 	}
@@ -54,7 +57,7 @@ func cmpAfterDecodeEncodeBox(t *testing.T, data []byte) {
 
 // boxDiffAfterEncodeAndDecode compares a box after encoding and decoding using deep.Equal().
 // Further check that Info can be run without an error.
-func boxDiffAfterEncodeAndDecode(t *testing.T, box Box) {
+func boxDiffAfterEncodeAndDecode(t *testing.T, box mp4.Box) {
 	t.Helper()
 
 	// First do encode in a slice via SliceWriter
@@ -66,7 +69,7 @@ func boxDiffAfterEncodeAndDecode(t *testing.T, box Box) {
 	}
 	buf := bytes.NewBuffer(sw.Bytes())
 
-	boxDec, err := DecodeBox(0, buf)
+	boxDec, err := mp4.DecodeBox(0, buf)
 	if err != nil {
 		t.Error(err)
 	}
@@ -83,7 +86,7 @@ func boxDiffAfterEncodeAndDecode(t *testing.T, box Box) {
 	}
 	// and decode using SliceReader
 	sr := bits.NewFixedSliceReader(midBuf.Bytes())
-	boxDec, err = DecodeBoxSR(0, sr)
+	boxDec, err = mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
@@ -100,7 +103,7 @@ func boxDiffAfterEncodeAndDecode(t *testing.T, box Box) {
 	}
 }
 
-func boxAfterEncodeAndDecode(t *testing.T, box Box) Box {
+func boxAfterEncodeAndDecode(t *testing.T, box mp4.Box) mp4.Box {
 	t.Helper()
 	buf := bytes.Buffer{}
 	err := box.Encode(&buf)
@@ -108,7 +111,7 @@ func boxAfterEncodeAndDecode(t *testing.T, box Box) Box {
 		t.Error(err)
 	}
 
-	boxDec, err := DecodeBox(0, &buf)
+	boxDec, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error(err)
 	}
@@ -139,7 +142,7 @@ func changeBoxSizeAndAssertError(t *testing.T, data []byte, pos uint64, newSize
 
 func assertBoxDecodeError(t *testing.T, data []byte, pos uint64, errMsg string) {
 	t.Helper()
-	_, err := DecodeBox(pos, bytes.NewBuffer(data))
+	_, err := mp4.DecodeBox(pos, bytes.NewBuffer(data))
 	if err == nil || err.Error() != errMsg {
 		got := ""
 		if err != nil {
@@ -147,7 +150,7 @@ func assertBoxDecodeError(t *testing.T, data []byte, pos uint64, errMsg string)
 		}
 		t.Errorf("DecodeBox: Expected error msg: %q, got: %q", errMsg, got)
 	}
-	_, err = DecodeBoxSR(pos, bits.NewFixedSliceReader(data))
+	_, err = mp4.DecodeBoxSR(pos, bits.NewFixedSliceReader(data))
 	if err == nil || err.Error() != errMsg {
 		got := ""
 		if err != nil {
@@ -157,7 +160,7 @@ func assertBoxDecodeError(t *testing.T, data []byte, pos uint64, errMsg string)
 	}
 }
 
-func encodeBox(t *testing.T, box Box) []byte {
+func encodeBox(t *testing.T, box mp4.Box) []byte {
 	buf := bytes.Buffer{}
 	err := box.Encode(&buf)
 	if err != nil {
@@ -180,8 +183,61 @@ func writeGolden(t *testing.T, goldenAssetPath string, data []byte) error {
 	return nil
 }
 
+type testReadSeeker struct {
+	data []byte
+	pos  int
+}
+
+func newTestReadSeeker(data []byte) *testReadSeeker {
+	return &testReadSeeker{
+		data: data,
+		pos:  0,
+	}
+}
+
+func (sr *testReadSeeker) Read(p []byte) (n int, err error) {
+	if sr.pos >= len(sr.data) {
+		return 0, io.EOF
+	}
+	n = copy(p, sr.data[sr.pos:])
+	sr.pos += n
+	return n, nil
+}
+
+func (sr *testReadSeeker) Seek(offset int64, whence int) (int64, error) {
+	switch whence {
+	case 0:
+		sr.pos = int(offset)
+	case 1:
+		sr.pos += int(offset)
+	case 2:
+		sr.pos = len(sr.data) + int(offset)
+	default:
+		return 0, fmt.Errorf("invalid whence: %d", whence)
+	}
+	return int64(sr.pos), nil
+}
+
+func createLazyMdat(t *testing.T, data []byte) (*mp4.MdatBox, io.ReadSeeker) {
+	t.Helper()
+	fullData := make([]byte, 8+len(data))
+	binary.BigEndian.PutUint32(fullData[0:4], uint32(len(data)+8))
+	copy(fullData[4:], "mdat")
+	copy(fullData[8:], data)
+	testSeeker := newTestReadSeeker(fullData)
+	box, err := mp4.DecodeBoxLazyMdat(0, testSeeker)
+	if err != nil {
+		t.Error(err)
+	}
+	lazyMdat := box.(*mp4.MdatBox)
+	return lazyMdat, testSeeker
+}
+
 // TestMain is to set flags for tests. In particular, the update flag to update golden files.
 func TestMain(m *testing.M) {
 	flag.Parse()
+	if *update {
+		fmt.Println("update flag is set to:", *update)
+	}
 	os.Exit(m.Run())
 }
diff --git a/mp4/hvcc_test.go b/mp4/hvcc_test.go
index 68df660..b3e1a10 100644
--- a/mp4/hvcc_test.go
+++ b/mp4/hvcc_test.go
@@ -1,8 +1,10 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 const (
@@ -25,7 +27,7 @@ func TestHvcC(t *testing.T) {
 		t.Error(err)
 	}
 	includePS := true
-	hvcC, err := CreateHvcC([][]byte{vpsNalu}, [][]byte{spsNalu}, [][]byte{ppsNalu}, true, true, true, includePS)
+	hvcC, err := mp4.CreateHvcC([][]byte{vpsNalu}, [][]byte{spsNalu}, [][]byte{ppsNalu}, true, true, true, includePS)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/infodumper_test.go b/mp4/infodumper_test.go
index d32c1d8..e5486f0 100644
--- a/mp4/infodumper_test.go
+++ b/mp4/infodumper_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -7,11 +7,12 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 // compareOrUpdateInfo - compare box with golden dump or update it with -update flag set
-func compareOrUpdateInfo(t *testing.T, b Informer, path string) error {
+func compareOrUpdateInfo(t *testing.T, b mp4.Informer, path string) error {
 	t.Helper()
 
 	var dumpBuf bytes.Buffer
diff --git a/mp4/initsegment_test.go b/mp4/initsegment_test.go
index 8c603ee..b3973b0 100644
--- a/mp4/initsegment_test.go
+++ b/mp4/initsegment_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -8,20 +8,21 @@ import (
 	"os"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 const sps1nalu = "674d401fe4605017fcb80b4f00000300010000030032e4800753003a9e08200e58e189c0"
 const pps1nalu = "685bdf20"
 
-func parseInitFile(fileName string) (*File, error) {
+func parseInitFile(fileName string) (*mp4.File, error) {
 	fd, err := os.Open(fileName)
 	if err != nil {
 		return nil, err
 	}
 	defer fd.Close()
 
-	f, err := DecodeFile(fd)
+	f, err := mp4.DecodeFile(fd)
 	if err != io.EOF && err != nil {
 		return nil, err
 	}
@@ -29,7 +30,7 @@ func parseInitFile(fileName string) (*File, error) {
 		return nil, fmt.Errorf("No ftyp present")
 	}
 
-	if f.isFragmented && len(f.Init.Moov.Traks) != 1 {
+	if f.IsFragmented() && len(f.Init.Moov.Traks) != 1 {
 		return nil, fmt.Errorf("Not exactly one track")
 	}
 	return f, nil
@@ -149,7 +150,7 @@ func TestGenerateInitSegment(t *testing.T) {
 	pps, _ := hex.DecodeString(pps1nalu)
 	ppsData := [][]byte{pps}
 
-	init := CreateEmptyInit()
+	init := mp4.CreateEmptyInit()
 	init.AddEmptyTrack(180000, "video", "und")
 	trak := init.Moov.Trak
 	err := trak.SetAVCDescriptor("avc3", spsData, ppsData, true)
@@ -168,7 +169,7 @@ func TestGenerateInitSegment(t *testing.T) {
 		t.Error(err)
 	}
 
-	initRead, err := DecodeFile(&buf)
+	initRead, err := mp4.DecodeFile(&buf)
 	if err != io.EOF && err != nil {
 		t.Error(err)
 	}
@@ -212,13 +213,13 @@ func TestInitTweakSingleTrakLive(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	f, err := DecodeFile(r)
+	f, err := mp4.DecodeFile(r)
 	if err != nil {
 		t.Error(err)
 	}
 	moov := f.Init.Moov
 	mvex := moov.Mvex
-	mehd := MehdBox{
+	mehd := mp4.MehdBox{
 		FragmentDuration: 1000,
 	}
 	mvex.AddChild(&mehd)
diff --git a/mp4/kind_test.go b/mp4/kind_test.go
index 2530e3c..311316e 100644
--- a/mp4/kind_test.go
+++ b/mp4/kind_test.go
@@ -1,14 +1,16 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestKind(t *testing.T) {
 	t.Run("encode and decode", func(t *testing.T) {
-		kind := &KindBox{SchemeURI: "urn:mpeg:dash:role:2011", Value: "forced-subtitle"}
+		kind := &mp4.KindBox{SchemeURI: "urn:mpeg:dash:role:2011", Value: "forced-subtitle"}
 		boxDiffAfterEncodeAndDecode(t, kind)
 	})
 	t.Run("decode with full box header", func(t *testing.T) {
@@ -20,11 +22,11 @@ func TestKind(t *testing.T) {
 			t.Error(err)
 		}
 		buffer := bytes.NewReader(rawBytes)
-		box, err := DecodeBox(0, buffer)
+		box, err := mp4.DecodeBox(0, buffer)
 		if err != nil {
 			t.Errorf("Error decoding kind box: %v", err)
 		}
-		kind := box.(*KindBox)
+		kind := box.(*mp4.KindBox)
 		if kind.SchemeURI != "urn:mpeg:dash:role:2011" {
 			t.Errorf("Expected scheme URI 'urn:mpeg:dash:role:2011', got '%s'", kind.SchemeURI)
 		}
diff --git a/mp4/leva_test.go b/mp4/leva_test.go
index 9c0dbde..b7009a9 100644
--- a/mp4/leva_test.go
+++ b/mp4/leva_test.go
@@ -1,30 +1,34 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestLeva(t *testing.T) {
-	leva := LevaBox{}
-	lvl, err := NewLevaLevel(1, true, 0, 42, 0, 0)
+	leva := mp4.LevaBox{}
+	lvl, err := mp4.NewLevaLevel(1, true, 0, 42, 0, 0)
 	if err != nil {
 		t.Error(err)
 	}
 	leva.Levels = append(leva.Levels, lvl)
-	lvl, err = NewLevaLevel(2, false, 1, 42, 43, 0)
+	lvl, err = mp4.NewLevaLevel(2, false, 1, 42, 43, 0)
 	if err != nil {
 		t.Error(err)
 	}
 	leva.Levels = append(leva.Levels, lvl)
-	lvl, err = NewLevaLevel(2, false, 2, 0, 0, 0)
+	lvl, err = mp4.NewLevaLevel(2, false, 2, 0, 0, 0)
 	if err != nil {
 		t.Error(err)
 	}
 	leva.Levels = append(leva.Levels, lvl)
-	lvl, err = NewLevaLevel(2, false, 3, 0, 0, 0)
+	lvl, err = mp4.NewLevaLevel(2, false, 3, 0, 0, 0)
 	if err != nil {
 		t.Error(err)
 	}
 	leva.Levels = append(leva.Levels, lvl)
-	lvl, err = NewLevaLevel(3, false, 4, 0, 0, 44)
+	lvl, err = mp4.NewLevaLevel(3, false, 4, 0, 0, 44)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/lou_test.go b/mp4/lou_test.go
index dcf688a..bb63539 100644
--- a/mp4/lou_test.go
+++ b/mp4/lou_test.go
@@ -1,119 +1,64 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestTlou(t *testing.T) {
-	tlou := &TlouBox{
-		loudnessBaseBox: loudnessBaseBox{
-			Version: 1,
-			Flags:   0,
-			LoudnessBases: []*LoudnessBase{
-				{
-					EQSetID:                0,
-					DownmixID:              0,
-					DRCSetID:               0,
-					BsSamplePeakLevel:      1087,
-					BsTruePeakLevel:        1086,
-					MeasurementSystemForTP: 2,
-					ReliabilityForTP:       3,
-					Measurements: []Measurement{
-						{
-							MethodDefinition:  1,
-							MethodValue:       121,
-							MeasurementSystem: 2,
-							Reliability:       3,
-						},
-						{
-							MethodDefinition:  3,
-							MethodValue:       122,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
+	tlou := mp4.LoudnessBaseBox{
+		Name:    "tlou",
+		Version: 1,
+		Flags:   0,
+		LoudnessBases: []*mp4.LoudnessBase{
+			{
+				EQSetID:                0,
+				DownmixID:              0,
+				DRCSetID:               0,
+				BsSamplePeakLevel:      1087,
+				BsTruePeakLevel:        1086,
+				MeasurementSystemForTP: 2,
+				ReliabilityForTP:       3,
+				Measurements: []mp4.LoudnessMeasurement{
+					{
+						MethodDefinition:  1,
+						MethodValue:       121,
+						MeasurementSystem: 2,
+						Reliability:       3,
 					},
-				},
-				{
-					EQSetID:                0,
-					DownmixID:              0,
-					DRCSetID:               0,
-					BsSamplePeakLevel:      1087,
-					BsTruePeakLevel:        1086,
-					MeasurementSystemForTP: 2,
-					ReliabilityForTP:       3,
-					Measurements: []Measurement{
-						{
-							MethodDefinition:  4,
-							MethodValue:       124,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
-						{
-							MethodDefinition:  5,
-							MethodValue:       122,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
+					{
+						MethodDefinition:  3,
+						MethodValue:       122,
+						MeasurementSystem: 1,
+						Reliability:       3,
 					},
 				},
 			},
-		},
-	}
-	boxDiffAfterEncodeAndDecode(t, tlou)
-}
-
-func TestAlou(t *testing.T) {
-	alou := &AlouBox{
-		loudnessBaseBox: loudnessBaseBox{
-			Version: 1,
-			Flags:   0,
-			LoudnessBases: []*LoudnessBase{
-				{
-					EQSetID:                0,
-					DownmixID:              0,
-					DRCSetID:               0,
-					BsSamplePeakLevel:      1087,
-					BsTruePeakLevel:        1086,
-					MeasurementSystemForTP: 2,
-					ReliabilityForTP:       3,
-					Measurements: []Measurement{
-						{
-							MethodDefinition:  1,
-							MethodValue:       121,
-							MeasurementSystem: 2,
-							Reliability:       3,
-						},
-						{
-							MethodDefinition:  3,
-							MethodValue:       122,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
+			{
+				EQSetID:                0,
+				DownmixID:              0,
+				DRCSetID:               0,
+				BsSamplePeakLevel:      1087,
+				BsTruePeakLevel:        1086,
+				MeasurementSystemForTP: 2,
+				ReliabilityForTP:       3,
+				Measurements: []mp4.LoudnessMeasurement{
+					{
+						MethodDefinition:  4,
+						MethodValue:       124,
+						MeasurementSystem: 1,
+						Reliability:       3,
 					},
-				},
-				{
-					EQSetID:                0,
-					DownmixID:              0,
-					DRCSetID:               0,
-					BsSamplePeakLevel:      1087,
-					BsTruePeakLevel:        1086,
-					MeasurementSystemForTP: 2,
-					ReliabilityForTP:       3,
-					Measurements: []Measurement{
-						{
-							MethodDefinition:  4,
-							MethodValue:       124,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
-						{
-							MethodDefinition:  5,
-							MethodValue:       122,
-							MeasurementSystem: 1,
-							Reliability:       3,
-						},
+					{
+						MethodDefinition:  5,
+						MethodValue:       122,
+						MeasurementSystem: 1,
+						Reliability:       3,
 					},
 				},
 			},
 		},
 	}
-	boxDiffAfterEncodeAndDecode(t, alou)
+	boxDiffAfterEncodeAndDecode(t, &tlou)
 }
diff --git a/mp4/ludt_test.go b/mp4/ludt_test.go
index 75235da..5630a1b 100644
--- a/mp4/ludt_test.go
+++ b/mp4/ludt_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
diff --git a/mp4/mdat_test.go b/mp4/mdat_test.go
index 2e4e91d..d270f4b 100644
--- a/mp4/mdat_test.go
+++ b/mp4/mdat_test.go
@@ -1,15 +1,16 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestEncodeAndDecodeMdat(t *testing.T) {
 
-	mdat := &MdatBox{
+	mdat := &mp4.MdatBox{
 		StartPos: 4000,
 	}
 
@@ -29,12 +30,12 @@ func TestEncodeAndDecodeMdat(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	box, err := DecodeBox(0, &buf)
+	box, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Errorf("Could not decode written mdat box")
 	}
 
-	mdatDec := box.(*MdatBox)
+	mdatDec := box.(*mp4.MdatBox)
 	if mdatDec.Size() != uint64(expectedMdatSize) {
 		t.Errorf("Decoded mdat size is %d instead of expected %d", mdatDec.Size(), expectedMdatSize)
 	}
@@ -45,7 +46,7 @@ func TestEncodeAndDecodeMdat(t *testing.T) {
 
 func TestEncodeAndDecodeMdatLargeSize(t *testing.T) {
 
-	mdat := &MdatBox{
+	mdat := &mp4.MdatBox{
 		StartPos: 4000,
 	}
 
@@ -54,7 +55,7 @@ func TestEncodeAndDecodeMdatLargeSize(t *testing.T) {
 	mdat.AddSampleData(sample)
 	mdat.LargeSize = true
 
-	expectedMdatSize := 15 + largeSizeLen
+	expectedMdatSize := 15 + 8 // 8  is large size length
 	mdatSize := mdat.Size()
 	if mdatSize != uint64(expectedMdatSize) {
 		t.Errorf("mdat size is %d instead of expected %d", mdatSize, expectedMdatSize)
@@ -66,12 +67,12 @@ func TestEncodeAndDecodeMdatLargeSize(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	box, err := DecodeBox(0, &buf)
+	box, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Errorf("Could not decode written mdat box")
 	}
 
-	mdatDec := box.(*MdatBox)
+	mdatDec := box.(*mp4.MdatBox)
 	if mdatDec.Size() != uint64(expectedMdatSize) {
 		t.Errorf("Decoded mdat size is %d instead of expected %d", mdatDec.Size(), expectedMdatSize)
 	}
@@ -82,7 +83,7 @@ func TestEncodeAndDecodeMdatLargeSize(t *testing.T) {
 
 func TestReadData_NormalMode(t *testing.T) {
 
-	mdat := &MdatBox{
+	mdat := &mp4.MdatBox{
 		StartPos: 0,
 		Data:     []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
 	}
@@ -100,43 +101,41 @@ func TestReadData_NormalMode(t *testing.T) {
 
 }
 
-func TestReadData_LazyMdatMode(t *testing.T) {
+func TestLazyMdatMode(t *testing.T) {
 
-	// prepare encoded mdat box before testing read
-	mdat := &MdatBox{
-		StartPos: 4000,
+	mdatPayload := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
+	lazyMdat, testSeeker := createLazyMdat(t, mdatPayload)
+
+	if !lazyMdat.IsLazy() {
+		t.Error("expected lazy")
 	}
-	sample := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
-	mdat.AddSampleData(sample)
-	var buf bytes.Buffer
-	err := mdat.Encode(&buf)
+	data, err := lazyMdat.ReadData(8, 6, testSeeker)
 	if err != nil {
 		t.Error(err)
 	}
 
-	lazyMdat := &MdatBox{
-		StartPos:     0,
-		lazyDataSize: 6,
+	expected := mdatPayload
+
+	if !bytes.Equal(data, expected) {
+		t.Errorf("expected %v, got %v", expected, data)
 	}
 
-	// test ReadData with provided ReadSeeker
-	readSeeker := bytes.NewReader(buf.Bytes())
-	data, err := lazyMdat.ReadData(9, 5, readSeeker)
+	// Encode lazily does not write the mdat data, but just the header
+	var buf bytes.Buffer
+	err = lazyMdat.Encode(&buf)
 	if err != nil {
 		t.Error(err)
 	}
 
-	expected := sample[1:6]
-
-	if !bytes.Equal(data, expected) {
-		t.Errorf("expected %v, got %v", expected, data)
+	header := []byte{0x00, 0x00, 0x00, 0x0e, 'm', 'd', 'a', 't'}
+	if !bytes.Equal(buf.Bytes(), header) {
+		t.Errorf("expected %v, got %v", header, buf.Bytes())
 	}
-
 }
 
 func TestCopyData_NormalMode(t *testing.T) {
 
-	mdat := &MdatBox{
+	mdat := &mp4.MdatBox{
 		StartPos: 0,
 		Data:     []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
 	}
@@ -159,27 +158,14 @@ func TestCopyData_NormalMode(t *testing.T) {
 
 func TestCopyData_LazyMdatMode(t *testing.T) {
 
-	// prepare encoded mdat box before testing read
-	mdat := &MdatBox{
-		StartPos: 4000,
-	}
-	sample := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
-	mdat.AddSampleData(sample)
-	var buf bytes.Buffer
-	err := mdat.Encode(&buf)
-	if err != nil {
-		t.Error(err)
-	}
+	mdatPayload := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
+	lazyMdat, testReadSeeker := createLazyMdat(t, mdatPayload)
 
-	lazyMdat := &MdatBox{
-		StartPos:     0,
-		lazyDataSize: 6,
+	if !lazyMdat.IsLazy() {
+		t.Error("expected lazy")
 	}
-
-	// test ReadData with provided ReadSeeker
-	readSeeker := bytes.NewReader(buf.Bytes())
-	var outBuffer bytes.Buffer
-	n, err := lazyMdat.CopyData(9, 5, readSeeker, &outBuffer)
+	outBuf := bytes.Buffer{}
+	n, err := lazyMdat.CopyData(9, 5, testReadSeeker, &outBuf)
 	if n != 5 {
 		t.Errorf("did get %d bytes instead of 5", n)
 	}
@@ -187,22 +173,22 @@ func TestCopyData_LazyMdatMode(t *testing.T) {
 		t.Error(err)
 	}
 
-	expected := sample[1:6]
+	expected := mdatPayload[1:6]
 
-	if !bytes.Equal(outBuffer.Bytes(), expected) {
-		t.Errorf("expected %v, got %v", expected, outBuffer.Bytes())
+	if !bytes.Equal(outBuf.Bytes(), expected) {
+		t.Errorf("expected %v, got %v", expected, outBuf.Bytes())
 	}
 }
 
 // TestAddParts - adding parts to mdat should give the same result as one big slice
 func TestAddParts(t *testing.T) {
-	mdat := &MdatBox{}
+	mdat := &mp4.MdatBox{}
 	part1 := []byte{0, 1, 2, 3, 4}
 	part2 := []byte{5, 6, 7, 8}
 	mdat.AddSampleData(part1)
 	mdat.AddSampleData(part2)
 
-	expMdat := &MdatBox{Data: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8}}
+	expMdat := &mp4.MdatBox{Data: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8}}
 	out := make([]byte, 17)
 	outBuf := bytes.NewBuffer(out)
 	err := mdat.Encode(outBuf)
diff --git a/mp4/mdhd_test.go b/mp4/mdhd_test.go
index 1ece148..8567662 100644
--- a/mp4/mdhd_test.go
+++ b/mp4/mdhd_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestMdhd(t *testing.T) {
 
-	boxes := []*MdhdBox{
+	boxes := []*mp4.MdhdBox{
 		{
 			Version:          0,
 			Flags:            0,
@@ -32,7 +34,7 @@ func TestMdhd(t *testing.T) {
 		mdhd.SetLanguage(language)
 		boxDiffAfterEncodeAndDecode(t, mdhd)
 		outBox := boxAfterEncodeAndDecode(t, mdhd)
-		mdhdOut := outBox.(*MdhdBox)
+		mdhdOut := outBox.(*mp4.MdhdBox)
 		gotLanguage := mdhdOut.GetLanguage()
 		if gotLanguage != language {
 			t.Errorf("Got %q, want %q", gotLanguage, language)
diff --git a/mp4/mediasegment_test.go b/mp4/mediasegment_test.go
index c0b9f9a..2920a89 100644
--- a/mp4/mediasegment_test.go
+++ b/mp4/mediasegment_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,12 +6,13 @@ import (
 	"os"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestMediaSegmentFragmentation(t *testing.T) {
 
-	trex := &TrexBox{
+	trex := &mp4.TrexBox{
 		TrackID: 2,
 	}
 
@@ -25,7 +26,7 @@ func TestMediaSegmentFragmentation(t *testing.T) {
 	}
 	defer fd.Close()
 
-	f, err := DecodeFile(fd)
+	f, err := mp4.DecodeFile(fd)
 	if err != io.EOF && err != nil {
 		t.Error(err)
 	}
@@ -34,8 +35,8 @@ func TestMediaSegmentFragmentation(t *testing.T) {
 	}
 
 	var bufInSeg bytes.Buffer
-	f.EncOptimize = OptimizeNone // Avoid trun optimization
-	f.FragEncMode = EncModeBoxTree
+	f.EncOptimize = mp4.OptimizeNone // Avoid trun optimization
+	f.FragEncMode = mp4.EncModeBoxTree
 	err = f.Encode(&bufInSeg)
 	if err != nil {
 		t.Error(err)
@@ -70,8 +71,8 @@ func TestMediaSegmentFragmentation(t *testing.T) {
 	}
 
 	var bufFrag bytes.Buffer
-	fragmentedSegment := NewMediaSegment()
-	fragmentedSegment.EncOptimize = OptimizeTrun
+	fragmentedSegment := mp4.NewMediaSegment()
+	fragmentedSegment.EncOptimize = mp4.OptimizeTrun
 	fragmentedSegment.Styp = f.Segments[0].Styp
 	fragmentedSegment.Fragments = fragments
 
@@ -111,9 +112,9 @@ func TestDoubleDecodeEncodeOptimize(t *testing.T) {
 	}
 	defer fd.Close()
 
-	enc1 := decodeEncode(t, fd, OptimizeTrun)
+	enc1 := decodeEncode(t, fd, mp4.OptimizeTrun)
 	buf1 := bytes.NewBuffer(enc1)
-	enc2 := decodeEncode(t, buf1, OptimizeTrun)
+	enc2 := decodeEncode(t, buf1, mp4.OptimizeTrun)
 	diff := deep.Equal(enc2, enc1)
 	if diff != nil {
 		t.Errorf("Second write gives diff %s", diff)
@@ -129,15 +130,15 @@ func TestDecodeEncodeNoOptimize(t *testing.T) {
 		t.Fatal(err)
 	}
 	buf0 := bytes.NewBuffer(data)
-	enc := decodeEncode(t, buf0, OptimizeNone)
+	enc := decodeEncode(t, buf0, mp4.OptimizeNone)
 	diff := deep.Equal(enc, data)
 	if diff != nil {
 		t.Errorf("First encode gives diff %s", diff)
 	}
 }
 
-func decodeEncode(t *testing.T, r io.Reader, optimize EncOptimize) []byte {
-	f, err := DecodeFile(r)
+func decodeEncode(t *testing.T, r io.Reader, optimize mp4.EncOptimize) []byte {
+	f, err := mp4.DecodeFile(r)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -161,13 +162,13 @@ func TestMoofEncrypted(t *testing.T) {
 	}
 	defer fd.Close()
 
-	f, err := DecodeFile(fd)
+	f, err := mp4.DecodeFile(fd)
 	if err != io.EOF && err != nil {
 		t.Error(err)
 	}
 
 	var bufOut bytes.Buffer
-	f.FragEncMode = EncModeBoxTree
+	f.FragEncMode = mp4.EncModeBoxTree
 	err = f.Encode(&bufOut)
 	if err != nil {
 		t.Error(err)
@@ -201,13 +202,13 @@ func TestDecodeEncodeCencFragmentedFile(t *testing.T) {
 		t.Fatal(err)
 	}
 	inBuf := bytes.NewBuffer(inData)
-	decFile, err := DecodeFile(inBuf)
+	decFile, err := mp4.DecodeFile(inBuf)
 	if err != nil {
 		t.Error(err)
 	}
 	outSlice := make([]byte, 0, len(inData))
 	outBuf := bytes.NewBuffer(outSlice)
-	decFile.FragEncMode = EncFragFileMode(EncModeBoxTree)
+	decFile.FragEncMode = mp4.EncFragFileMode(mp4.EncModeBoxTree)
 	err = decFile.Encode(outBuf)
 	if err != nil {
 		t.Error(err)
@@ -235,11 +236,11 @@ func TestCommonSampleDuration(t *testing.T) {
 			t.Fatal(err)
 		}
 		defer fd.Close()
-		f, err := DecodeFile(fd)
+		f, err := mp4.DecodeFile(fd)
 		if err != nil {
 			t.Fatal(err)
 		}
-		trex := &TrexBox{
+		trex := &mp4.TrexBox{
 			TrackID: c.trackID,
 		}
 		for _, s := range f.Segments {
diff --git a/mp4/mehd_test.go b/mp4/mehd_test.go
index 29ea8d4..9f39400 100644
--- a/mp4/mehd_test.go
+++ b/mp4/mehd_test.go
@@ -1,10 +1,12 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestMehd(t *testing.T) {
-	mehd := &MehdBox{FragmentDuration: 1234}
+	mehd := &mp4.MehdBox{FragmentDuration: 1234}
 	boxDiffAfterEncodeAndDecode(t, mehd)
 }
diff --git a/mp4/meta_test.go b/mp4/meta_test.go
index b5715fc..8a3f686 100644
--- a/mp4/meta_test.go
+++ b/mp4/meta_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -7,14 +7,15 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestMeta(t *testing.T) {
-	hdlr, err := CreateHdlr("zzzz")
+	hdlr, err := mp4.CreateHdlr("zzzz")
 	if err != nil {
 		t.Error(err)
 	}
-	meta := CreateMetaBox(0, hdlr)
+	meta := mp4.CreateMetaBox(0, hdlr)
 	boxDiffAfterEncodeAndDecode(t, meta)
 }
 
@@ -26,11 +27,11 @@ func TestQuickTimeMeta(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(data)
-	box, err := DecodeBoxSR(0, sr)
+	box, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
-	meta, ok := box.(*MetaBox)
+	meta, ok := box.(*mp4.MetaBox)
 	if !ok {
 		t.Error("box is not meta")
 	}
diff --git a/mp4/mfhd_test.go b/mp4/mfhd_test.go
index 3d86a69..979d327 100644
--- a/mp4/mfhd_test.go
+++ b/mp4/mfhd_test.go
@@ -1,9 +1,13 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestEncodeDecodeMfhd(t *testing.T) {
-	mfhd := &MfhdBox{
+	mfhd := &mp4.MfhdBox{
 		Version:        0,
 		Flags:          0,
 		SequenceNumber: 1,
diff --git a/mp4/mfra_test.go b/mp4/mfra_test.go
index bca0b5a..ceca3cf 100644
--- a/mp4/mfra_test.go
+++ b/mp4/mfra_test.go
@@ -1,16 +1,20 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestMfra(t *testing.T) {
-	mfra := &MfraBox{}
-	tfra := &TfraBox{
+	mfra := &mp4.MfraBox{}
+	tfra := &mp4.TfraBox{
 		TrackID:               1,
 		LengthSizeOfTrafNum:   0,
 		LengthSizeOfTrunNum:   1,
 		LengthSizeOfSampleNum: 2,
 	}
-	te := TfraEntry{
+	te := mp4.TfraEntry{
 		Time:         3145,
 		MoofOffset:   1892,
 		TrafNumber:   1,
@@ -22,7 +26,7 @@ func TestMfra(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	mfro := &MfroBox{
+	mfro := &mp4.MfroBox{
 		ParentSize: 12345,
 	}
 	err = mfra.AddChild(mfro)
diff --git a/mp4/mime_test.go b/mp4/mime_test.go
index 16c02f5..c466ff8 100644
--- a/mp4/mime_test.go
+++ b/mp4/mime_test.go
@@ -1,9 +1,13 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestMimeBox(t *testing.T) {
-	mimeZeroTerminated := MimeBox{
+	mimeZeroTerminated := mp4.MimeBox{
 		Version:              0,
 		Flags:                0,
 		ContentType:          "image/png",
@@ -11,7 +15,7 @@ func TestMimeBox(t *testing.T) {
 	}
 	boxDiffAfterEncodeAndDecode(t, &mimeZeroTerminated)
 
-	mimeWithoutZeroTermination := MimeBox{
+	mimeWithoutZeroTermination := mp4.MimeBox{
 		Version:              0,
 		Flags:                0,
 		ContentType:          "image/png",
diff --git a/mp4/mvhd_test.go b/mp4/mvhd_test.go
index e2b8951..e69d4cb 100644
--- a/mp4/mvhd_test.go
+++ b/mp4/mvhd_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"os"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestMvhd(t *testing.T) {
-	mvhd := CreateMvhd()
+	mvhd := mp4.CreateMvhd()
 	boxDiffAfterEncodeAndDecode(t, mvhd)
 
 	recentTime := int64(1721459921)
@@ -27,11 +29,11 @@ func TestMvhdTimeDecodeS(t *testing.T) {
 		t.Error(err)
 	}
 	reader := bytes.NewReader(data)
-	box, err := DecodeBox(0, reader)
+	box, err := mp4.DecodeBox(0, reader)
 	if err != nil {
 		t.Error(err)
 	}
-	mvhd, ok := box.(*MvhdBox)
+	mvhd, ok := box.(*mp4.MvhdBox)
 	if !ok {
 		t.Errorf("Not a MvhdBox %+v", box)
 	}
diff --git a/mp4/nmhd_test.go b/mp4/nmhd_test.go
index a86824a..e2309e1 100644
--- a/mp4/nmhd_test.go
+++ b/mp4/nmhd_test.go
@@ -1,11 +1,13 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestNmhd(t *testing.T) {
 
-	encBox := &NmhdBox{}
+	encBox := &mp4.NmhdBox{}
 	boxDiffAfterEncodeAndDecode(t, encBox)
 }
diff --git a/mp4/pasp_test.go b/mp4/pasp_test.go
index a4340e8..ca39192 100644
--- a/mp4/pasp_test.go
+++ b/mp4/pasp_test.go
@@ -1,11 +1,13 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestEncDecPasp(t *testing.T) {
 
-	b := &PaspBox{HSpacing: 3, VSpacing: 2}
+	b := &mp4.PaspBox{HSpacing: 3, VSpacing: 2}
 	boxDiffAfterEncodeAndDecode(t, b)
 }
diff --git a/mp4/prft_test.go b/mp4/prft_test.go
index 5556c53..1e7dd1e 100644
--- a/mp4/prft_test.go
+++ b/mp4/prft_test.go
@@ -1,16 +1,17 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestPrft(t *testing.T) {
-	prfts := []*PrftBox{
-		CreatePrftBox(0, PrftTimeCaptured, 1, 8998, 98),
-		CreatePrftBox(1, PrftTimeEncoderOutput, 2, 8998, 98),
+	prfts := []*mp4.PrftBox{
+		mp4.CreatePrftBox(0, mp4.PrftTimeCaptured, 1, 8998, 98),
+		mp4.CreatePrftBox(1, mp4.PrftTimeEncoderOutput, 2, 8998, 98),
 	}
 	for _, prft := range prfts {
 		boxDiffAfterEncodeAndDecode(t, prft)
@@ -24,11 +25,11 @@ func TestPrftDecodeSize(t *testing.T) {
 		t.Error(err)
 	}
 	sr := bits.NewFixedSliceReader(data)
-	decBox, err := DecodeBoxSR(0, sr)
+	decBox, err := mp4.DecodeBoxSR(0, sr)
 	if err != nil {
 		t.Error(err)
 	}
-	prft, ok := decBox.(*PrftBox)
+	prft, ok := decBox.(*mp4.PrftBox)
 	if !ok {
 		t.Error("box is not PrftBox")
 	}
diff --git a/mp4/pssh_test.go b/mp4/pssh_test.go
index f10cdd2..53f3901 100644
--- a/mp4/pssh_test.go
+++ b/mp4/pssh_test.go
@@ -1,17 +1,18 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"strings"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestPsshFromBase64(t *testing.T) {
 	b64 := "AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoSEDEuM2I0EEaatTa5ydDK/DESEDEuM2I0EEaatTa5ydDK/DFI49yVmwY="
 	expected := "[pssh] size=74 version=0 flags=000000\n - systemID: edef8ba9-79d6-4ace-a3c8-27dcd51d21ed (Widevine)\n"
-	psshs, err := PsshBoxesFromBase64(b64)
+	psshs, err := mp4.PsshBoxesFromBase64(b64)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -32,26 +33,26 @@ func TestPsshFromBase64(t *testing.T) {
 }
 
 func TestEncodeDecodePSSH(t *testing.T) {
-	hPR := strings.ReplaceAll(UUIDPlayReady, "-", "")
-	pr, err := NewUUIDFromString(hPR)
+	hPR := strings.ReplaceAll(mp4.UUIDPlayReady, "-", "")
+	pr, err := mp4.NewUUIDFromString(hPR)
 	if err != nil {
 		t.Fatal(err)
 	}
 	kid := "00112233445566778899aabbccddeeff"
-	ku, err := NewUUIDFromString(kid)
+	ku, err := mp4.NewUUIDFromString(kid)
 	if err != nil {
 		t.Fatal(err)
 	}
-	pssh := &PsshBox{
+	pssh := &mp4.PsshBox{
 		Version:  0,
 		SystemID: pr,
 		Data:     []byte("some data"),
 	}
 	boxDiffAfterEncodeAndDecode(t, pssh)
-	pssh = &PsshBox{
+	pssh = &mp4.PsshBox{
 		Version:  1,
 		SystemID: pr,
-		KIDs:     []UUID{ku},
+		KIDs:     []mp4.UUID{ku},
 		Data:     []byte("some data"),
 	}
 	boxDiffAfterEncodeAndDecode(t, pssh)
@@ -71,12 +72,12 @@ func TestPsshUUIDs(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		u, err := NewUUIDFromString(c.hexUUIDs)
+		u, err := mp4.NewUUIDFromString(c.hexUUIDs)
 		if err != nil {
 			t.Fatal(err)
 		}
-		if ProtectionSystemName(u) != c.expectedName {
-			t.Errorf("Expected %s, got %s", c.expectedName, ProtectionSystemName(u))
+		if mp4.ProtectionSystemName(u) != c.expectedName {
+			t.Errorf("Expected %s, got %s", c.expectedName, mp4.ProtectionSystemName(u))
 		}
 	}
 }
diff --git a/mp4/saio_test.go b/mp4/saio_test.go
index b446494..b187b6f 100644
--- a/mp4/saio_test.go
+++ b/mp4/saio_test.go
@@ -1,17 +1,19 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSaio(t *testing.T) {
-	saioV0 := &SaioBox{
+	saioV0 := &mp4.SaioBox{
 		Version: 0,
 		Offset:  []int64{12},
 	}
 	boxDiffAfterEncodeAndDecode(t, saioV0)
 
-	saioV1 := &SaioBox{
+	saioV1 := &mp4.SaioBox{
 		Version: 0,
 		Offset:  []int64{12},
 	}
diff --git a/mp4/saiz_test.go b/mp4/saiz_test.go
index 9420b74..d6ed53a 100644
--- a/mp4/saiz_test.go
+++ b/mp4/saiz_test.go
@@ -1,10 +1,12 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSaiz(t *testing.T) {
-	saiz := &SaizBox{DefaultSampleInfoSize: 1}
+	saiz := &mp4.SaizBox{DefaultSampleInfoSize: 1}
 	boxDiffAfterEncodeAndDecode(t, saiz)
 }
diff --git a/mp4/sample_test.go b/mp4/sample_test.go
index 3109992..cd95cb9 100644
--- a/mp4/sample_test.go
+++ b/mp4/sample_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSample(t *testing.T) {
-	s := NewSample(SyncSampleFlags, 1000, 100, -1001)
-	fs := FullSample{
+	s := mp4.NewSample(mp4.SyncSampleFlags, 1000, 100, -1001)
+	fs := mp4.FullSample{
 		Sample:     s,
 		DecodeTime: 1000,
 		Data:       []byte{0x01, 0x02, 0x03, 0x04},
diff --git a/mp4/sampleflags_test.go b/mp4/sampleflags_test.go
index 7e4dc33..eace9b3 100644
--- a/mp4/sampleflags_test.go
+++ b/mp4/sampleflags_test.go
@@ -1,13 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestSampleFlags(t *testing.T) {
-	sf := SampleFlags{
+	sf := mp4.SampleFlags{
 		IsLeading:                 1,
 		SampleDependsOn:           2,
 		SampleIsDependedOn:        1,
@@ -18,7 +19,7 @@ func TestSampleFlags(t *testing.T) {
 	}
 
 	sfBin := sf.Encode()
-	sfDec := DecodeSampleFlags(sfBin)
+	sfDec := mp4.DecodeSampleFlags(sfBin)
 	diff := deep.Equal(sfDec, sf)
 	if diff != nil {
 		t.Error(diff)
diff --git a/mp4/sdtp_test.go b/mp4/sdtp_test.go
index 97752bd..9beb0ca 100644
--- a/mp4/sdtp_test.go
+++ b/mp4/sdtp_test.go
@@ -1,15 +1,17 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSdtp(t *testing.T) {
-	entries := []SdtpEntry{
-		NewSdtpEntry(0, 2, 0, 0),
-		NewSdtpEntry(0, 1, 2, 0),
-		NewSdtpEntry(1, 2, 1, 1),
+	entries := []mp4.SdtpEntry{
+		mp4.NewSdtpEntry(0, 2, 0, 0),
+		mp4.NewSdtpEntry(0, 1, 2, 0),
+		mp4.NewSdtpEntry(1, 2, 1, 1),
 	}
 
-	boxDiffAfterEncodeAndDecode(t, CreateSdtpBox(entries))
+	boxDiffAfterEncodeAndDecode(t, mp4.CreateSdtpBox(entries))
 }
diff --git a/mp4/senc_test.go b/mp4/senc_test.go
index f4335fa..ff85476 100644
--- a/mp4/senc_test.go
+++ b/mp4/senc_test.go
@@ -1,73 +1,76 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestSencDirectValues(t *testing.T) {
-	iv8 := InitializationVector("12345678")
-	iv16 := InitializationVector("0123456789abcdef")
+	iv8 := mp4.InitializationVector("12345678")
+	iv16 := mp4.InitializationVector("0123456789abcdef")
 	cases := []struct {
-		desc string
-		senc *SencBox
+		desc            string
+		senc            *mp4.SencBox
+		perSampleIVSize byte
 	}{
 		{
 			desc: "No perSampleIVs",
-			senc: &SencBox{
-				Version:         0,
-				Flags:           0,
-				SampleCount:     431, // No perSampleIVs
-				perSampleIVSize: 0,
+			senc: &mp4.SencBox{
+				Version:     0,
+				Flags:       0,
+				SampleCount: 431, // No perSampleIVs
 			},
+			perSampleIVSize: 0,
 		},
 		{
 			desc: "perSampleIVSize 8",
-			senc: &SencBox{
-				Version:         0,
-				Flags:           0,
-				SampleCount:     1,
-				perSampleIVSize: 8,
-				IVs:             []InitializationVector{iv8},
-				SubSamples:      [][]SubSamplePattern{{{10, 1000}}},
+			senc: &mp4.SencBox{
+				Version:     0,
+				Flags:       0,
+				SampleCount: 1,
+				IVs:         []mp4.InitializationVector{iv8},
+				SubSamples:  [][]mp4.SubSamplePattern{{{10, 1000}}},
 			},
+			perSampleIVSize: 8,
 		},
 		{
 			desc: "perSampleIVSize 16",
-			senc: &SencBox{
-				Version:         0,
-				Flags:           0,
-				SampleCount:     1,
-				perSampleIVSize: 16,
-				IVs:             []InitializationVector{iv16},
-				SubSamples:      [][]SubSamplePattern{{{10, 1000}, {20, 2000}}},
+			senc: &mp4.SencBox{
+				Version:     0,
+				Flags:       0,
+				SampleCount: 1,
+				IVs:         []mp4.InitializationVector{iv16},
+				SubSamples:  [][]mp4.SubSamplePattern{{{10, 1000}, {20, 2000}}},
 			},
+			perSampleIVSize: 16,
 		},
 		{
 			desc: "perSampleIVSize 16, 2 subsamples",
-			senc: &SencBox{
-				Version:         0,
-				Flags:           0,
-				SampleCount:     2,
-				perSampleIVSize: 16,
-				IVs:             []InitializationVector{iv16, iv16},
-				SubSamples:      [][]SubSamplePattern{{{10, 1000}}, {{20, 2000}}},
+			senc: &mp4.SencBox{
+				Version:     0,
+				Flags:       0,
+				SampleCount: 2,
+				IVs:         []mp4.InitializationVector{iv16, iv16},
+				SubSamples:  [][]mp4.SubSamplePattern{{{10, 1000}}, {{20, 2000}}},
 			},
+			perSampleIVSize: 16,
 		},
 	}
 
 	for _, c := range cases {
 		t.Run(c.desc, func(t *testing.T) {
+			c.senc.SetPerSampleIVSize(c.perSampleIVSize)
 			sencDiffAfterEncodeAndDecode(t, c.senc, 0)
-			sencDiffAfterEncodeAndDecode(t, c.senc, c.senc.perSampleIVSize)
+			sencDiffAfterEncodeAndDecode(t, c.senc, c.perSampleIVSize)
 		})
 	}
 }
 
-func sencDiffAfterEncodeAndDecode(t *testing.T, senc *SencBox, perSampleIVSize byte) {
+func sencDiffAfterEncodeAndDecode(t *testing.T, senc *mp4.SencBox, perSampleIVSize byte) {
 	t.Helper()
 	buf := bytes.Buffer{}
 	err := senc.Encode(&buf)
@@ -75,14 +78,14 @@ func sencDiffAfterEncodeAndDecode(t *testing.T, senc *SencBox, perSampleIVSize b
 		t.Error(err)
 	}
 
-	boxDec, err := DecodeBox(0, &buf)
+	boxDec, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error(err)
 	}
-	decSenc := boxDec.(*SencBox)
-	var saizBox *SaizBox
+	decSenc := boxDec.(*mp4.SencBox)
+	var saizBox *mp4.SaizBox
 
-	if decSenc.readButNotParsed {
+	if decSenc.ReadButNotParsed() {
 		err = decSenc.ParseReadBox(perSampleIVSize, saizBox)
 		if err != nil {
 			t.Error(err)
@@ -95,51 +98,51 @@ func sencDiffAfterEncodeAndDecode(t *testing.T, senc *SencBox, perSampleIVSize b
 }
 
 func TestAddSamples(t *testing.T) {
-	iv0 := InitializationVector("")
-	iv8 := InitializationVector("01234567")
-	iv16 := InitializationVector("0123456789abcdef")
+	iv0 := mp4.InitializationVector("")
+	iv8 := mp4.InitializationVector("01234567")
+	iv16 := mp4.InitializationVector("0123456789abcdef")
 
-	senc := CreateSencBox()
-	err := senc.AddSample(SencSample{iv0, []SubSamplePattern{{10, 1000}}})
+	senc := mp4.CreateSencBox()
+	err := senc.AddSample(mp4.SencSample{iv0, []mp4.SubSamplePattern{{10, 1000}}})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv8, nil})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv8, nil})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 	sencDiffAfterEncodeAndDecode(t, senc, 8)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv8, []SubSamplePattern{{10, 1000}}})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv8, []mp4.SubSamplePattern{{10, 1000}}})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 	sencDiffAfterEncodeAndDecode(t, senc, 8)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv8, []SubSamplePattern{{10, 1000}}})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv8, []mp4.SubSamplePattern{{10, 1000}}})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 	sencDiffAfterEncodeAndDecode(t, senc, 8)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv16, []SubSamplePattern{{10, 1000}, {20, 2000}}})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv16, []mp4.SubSamplePattern{{10, 1000}, {20, 2000}}})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 	sencDiffAfterEncodeAndDecode(t, senc, 16)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv16, []SubSamplePattern{{10, 1000}}})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv16, []mp4.SubSamplePattern{{10, 1000}}})
 	assertNoError(t, err)
-	err = senc.AddSample(SencSample{iv16, []SubSamplePattern{{20, 2000}}})
+	err = senc.AddSample(mp4.SencSample{iv16, []mp4.SubSamplePattern{{20, 2000}}})
 	assertNoError(t, err)
 	sencDiffAfterEncodeAndDecode(t, senc, 0)
 	sencDiffAfterEncodeAndDecode(t, senc, 16)
 
-	senc = CreateSencBox()
-	err = senc.AddSample(SencSample{iv16, []SubSamplePattern{{10, 1000}}})
+	senc = mp4.CreateSencBox()
+	err = senc.AddSample(mp4.SencSample{iv16, []mp4.SubSamplePattern{{10, 1000}}})
 	assertNoError(t, err)
-	err = senc.AddSample(SencSample{iv8, []SubSamplePattern{{20, 2000}}})
+	err = senc.AddSample(mp4.SencSample{iv8, []mp4.SubSamplePattern{{20, 2000}}})
 	assertError(t, err, "Should have got error due to different iv size")
 }
 
@@ -154,7 +157,7 @@ func TestImplicitIVSize(t *testing.T) {
 
 	for _, tc := range testCases {
 		// Read the file
-		m, err := ReadMP4File(tc.inputFile)
+		m, err := mp4.ReadMP4File(tc.inputFile)
 		if err != nil {
 			t.Error(err)
 		}
@@ -193,7 +196,7 @@ func TestBadSencData(t *testing.T) {
 	for _, c := range cases {
 		t.Run(c.desc, func(t *testing.T) {
 			buf := bytes.NewBuffer(c.raw)
-			_, err := DecodeBox(0, buf)
+			_, err := mp4.DecodeBox(0, buf)
 			if err == nil {
 				t.Errorf("expected error %q, but got nil", c.err)
 			}
@@ -202,7 +205,7 @@ func TestBadSencData(t *testing.T) {
 			}
 
 			sr := bits.NewFixedSliceReader(c.raw)
-			_, err = DecodeBoxSR(0, sr)
+			_, err = mp4.DecodeBoxSR(0, sr)
 			if err == nil {
 				t.Errorf("expected error %q, but got nil", c.err)
 			}
diff --git a/mp4/sgpd_test.go b/mp4/sgpd_test.go
index f76539d..0d2aae8 100644
--- a/mp4/sgpd_test.go
+++ b/mp4/sgpd_test.go
@@ -1,22 +1,24 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSgpd(t *testing.T) {
 
-	rollEntry := &RollSampleGroupEntry{RollDistance: -1}
-	rapEntry := &RapSampleGroupEntry{NumLeadingSamplesKnown: 1, NumLeadingSamples: 12}
-	alstEntry := &AlstSampleGroupEntry{RollCount: 2, FirstOutputSample: 1, SampleOffset: []uint32{7000, 1234}}
-	unknownEntry := &UnknownSampleGroupEntry{Name: "tele", Data: []byte{0x80}}
-	unknownEntry2 := &UnknownSampleGroupEntry{Name: "tele", Data: []byte{0x00}}
+	rollEntry := &mp4.RollSampleGroupEntry{RollDistance: -1}
+	rapEntry := &mp4.RapSampleGroupEntry{NumLeadingSamplesKnown: 1, NumLeadingSamples: 12}
+	alstEntry := &mp4.AlstSampleGroupEntry{RollCount: 2, FirstOutputSample: 1, SampleOffset: []uint32{7000, 1234}}
+	unknownEntry := &mp4.UnknownSampleGroupEntry{Name: "tele", Data: []byte{0x80}}
+	unknownEntry2 := &mp4.UnknownSampleGroupEntry{Name: "tele", Data: []byte{0x00}}
 
-	sgpds := []*SgpdBox{
-		{Version: 1, GroupingType: "roll", DefaultLength: 2, SampleGroupEntries: []SampleGroupEntry{rollEntry}},
-		{Version: 1, GroupingType: "rap ", DefaultLength: 1, SampleGroupEntries: []SampleGroupEntry{rapEntry}},
-		{Version: 1, GroupingType: "alst", DefaultLength: 12, SampleGroupEntries: []SampleGroupEntry{alstEntry}},
-		{Version: 1, GroupingType: "tele", DefaultLength: 1, SampleGroupEntries: []SampleGroupEntry{unknownEntry, unknownEntry2}},
+	sgpds := []*mp4.SgpdBox{
+		{Version: 1, GroupingType: "roll", DefaultLength: 2, SampleGroupEntries: []mp4.SampleGroupEntry{rollEntry}},
+		{Version: 1, GroupingType: "rap ", DefaultLength: 1, SampleGroupEntries: []mp4.SampleGroupEntry{rapEntry}},
+		{Version: 1, GroupingType: "alst", DefaultLength: 12, SampleGroupEntries: []mp4.SampleGroupEntry{alstEntry}},
+		{Version: 1, GroupingType: "tele", DefaultLength: 1, SampleGroupEntries: []mp4.SampleGroupEntry{unknownEntry, unknownEntry2}},
 	}
 
 	for _, sgpd := range sgpds {
diff --git a/mp4/sidx_test.go b/mp4/sidx_test.go
index 80776e4..4285776 100644
--- a/mp4/sidx_test.go
+++ b/mp4/sidx_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSidx(t *testing.T) {
 
-	sidx := &SidxBox{}
+	sidx := &mp4.SidxBox{}
 
 	sidx.ReferenceID = 1
 	sidx.Timescale = 48000
@@ -14,7 +16,7 @@ func TestSidx(t *testing.T) {
 	sidx.FirstOffset = 1024
 	sidx.AnchorPoint = 1068
 
-	ref := SidxRef{
+	ref := mp4.SidxRef{
 		ReferenceType:      0, // Media
 		ReferencedSize:     2048,
 		SubSegmentDuration: 1024 * 15,
diff --git a/mp4/smdm_test.go b/mp4/smdm_test.go
index 6ffa8ea..6441e81 100644
--- a/mp4/smdm_test.go
+++ b/mp4/smdm_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"fmt"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSmDm(t *testing.T) {
 	// Create a sample SmDm box with test values
-	smdm := CreateSmDmBox(
+	smdm := mp4.CreateSmDmBox(
 		1000, 2000, // Primary R
 		3000, 4000, // Primary G
 		5000, 6000, // Primary B
diff --git a/mp4/ssix_test.go b/mp4/ssix_test.go
index 3dfd8b0..61156ba 100644
--- a/mp4/ssix_test.go
+++ b/mp4/ssix_test.go
@@ -1,19 +1,23 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestSsix(t *testing.T) {
-	ssix := SsixBox{}
-	ss := SubSegment{
-		Ranges: []SubSegmentRange{
-			NewSubSegmentRange(1, 2),
-			NewSubSegmentRange(3, 4),
+	ssix := mp4.SsixBox{}
+	ss := mp4.SubSegment{
+		Ranges: []mp4.SubSegmentRange{
+			mp4.NewSubSegmentRange(1, 2),
+			mp4.NewSubSegmentRange(3, 4),
 		}}
 	ssix.SubSegments = append(ssix.SubSegments, ss)
-	ss = SubSegment{
-		Ranges: []SubSegmentRange{
-			NewSubSegmentRange(2, 2),
-			NewSubSegmentRange(5, 4),
+	ss = mp4.SubSegment{
+		Ranges: []mp4.SubSegmentRange{
+			mp4.NewSubSegmentRange(2, 2),
+			mp4.NewSubSegmentRange(5, 4),
 		}}
 	ssix.SubSegments = append(ssix.SubSegments, ss)
 	boxDiffAfterEncodeAndDecode(t, &ssix)
diff --git a/mp4/sthd_test.go b/mp4/sthd_test.go
index c60e9e6..8be51b6 100644
--- a/mp4/sthd_test.go
+++ b/mp4/sthd_test.go
@@ -1,15 +1,16 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 func TestSthd(t *testing.T) {
 
-	encBox := &SthdBox{}
+	encBox := &mp4.SthdBox{}
 
 	buf := bytes.Buffer{}
 	err := encBox.Encode(&buf)
@@ -17,7 +18,7 @@ func TestSthd(t *testing.T) {
 		t.Error(err)
 	}
 
-	decBox, err := DecodeBox(0, &buf)
+	decBox, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/stpp_test.go b/mp4/stpp_test.go
index 07af404..9f6dd67 100644
--- a/mp4/stpp_test.go
+++ b/mp4/stpp_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestStpp(t *testing.T) {
@@ -44,9 +45,9 @@ func TestStpp(t *testing.T) {
 		}
 		for _, tc := range testCases {
 			t.Logf("Test case: %+v", tc)
-			stpp := NewStppBox(tc.namespace, tc.schemaLocation, tc.mimeTypes)
+			stpp := mp4.NewStppBox(tc.namespace, tc.schemaLocation, tc.mimeTypes)
 			if tc.hasBtrt {
-				btrt := &BtrtBox{}
+				btrt := &mp4.BtrtBox{}
 				stpp.AddChild(btrt)
 				if stpp.Btrt != btrt {
 					t.Error("Btrt link is broken")
@@ -65,11 +66,11 @@ func TestStpp(t *testing.T) {
 			t.Error(err)
 		}
 		sr := bits.NewFixedSliceReader(data)
-		box, err := DecodeBoxSR(0, sr)
+		box, err := mp4.DecodeBoxSR(0, sr)
 		if err != nil {
 			t.Error(err)
 		}
-		stpp, ok := box.(*StppBox)
+		stpp, ok := box.(*mp4.StppBox)
 		if !ok {
 			t.Error("not an stpp box")
 		}
@@ -96,11 +97,11 @@ func TestStpp(t *testing.T) {
 			t.Error(err)
 		}
 		sr := bits.NewFixedSliceReader(data)
-		box, err := DecodeBoxSR(0, sr)
+		box, err := mp4.DecodeBoxSR(0, sr)
 		if err != nil {
 			t.Error(err)
 		}
-		stpp, ok := box.(*StppBox)
+		stpp, ok := box.(*mp4.StppBox)
 		if !ok {
 			t.Error("not an stpp box")
 		}
diff --git a/mp4/stsc_test.go b/mp4/stsc_test.go
index e5ed5fe..09a70bb 100644
--- a/mp4/stsc_test.go
+++ b/mp4/stsc_test.go
@@ -1,9 +1,10 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
@@ -14,7 +15,7 @@ func TestStsc(t *testing.T) {
 		// 2 chunks with 256 samples followed
 		// by an unknown number of chunks with 1000 elements.
 		// The chunks should therefore start on sample 1, 257, 513, 1513, 2513 etc
-		stsc := &StscBox{}
+		stsc := &mp4.StscBox{}
 		err := stsc.AddEntry(1, 256, 1)
 		if err != nil {
 			t.Error(err)
@@ -76,7 +77,7 @@ func TestStsc(t *testing.T) {
 	})
 
 	t.Run("encode and decode", func(t *testing.T) {
-		stsc := &StscBox{}
+		stsc := &mp4.StscBox{}
 		err := stsc.AddEntry(1, 256, 1)
 		if err != nil {
 			t.Error(err)
@@ -91,7 +92,7 @@ func TestStsc(t *testing.T) {
 }
 
 func TestStscContainingChunks(t *testing.T) {
-	stsc := &StscBox{}
+	stsc := &mp4.StscBox{}
 	err := stsc.AddEntry(1, 256, 1)
 	if err != nil {
 		t.Error(err)
@@ -104,25 +105,25 @@ func TestStscContainingChunks(t *testing.T) {
 	testCases := []struct {
 		startSampleNr uint32
 		endSampleNr   uint32
-		wantedChunks  []Chunk
+		wantedChunks  []mp4.Chunk
 	}{
 		{
-			2, 2, []Chunk{{1, 1, 256}},
+			2, 2, []mp4.Chunk{{1, 1, 256}},
 		},
 		{
-			3, 22, []Chunk{{1, 1, 256}},
+			3, 22, []mp4.Chunk{{1, 1, 256}},
 		},
 		{
-			237, 256, []Chunk{{1, 1, 256}},
+			237, 256, []mp4.Chunk{{1, 1, 256}},
 		},
 		{
-			237, 257, []Chunk{{1, 1, 256}, {2, 257, 256}},
+			237, 257, []mp4.Chunk{{1, 1, 256}, {2, 257, 256}},
 		},
 		{
-			257, 276, []Chunk{{2, 257, 256}},
+			257, 276, []mp4.Chunk{{2, 257, 256}},
 		},
 		{
-			260, 1759, []Chunk{{2, 257, 256}, {3, 513, 1000}, {4, 1513, 1000}},
+			260, 1759, []mp4.Chunk{{2, 257, 256}, {3, 513, 1000}, {4, 1513, 1000}},
 		},
 	}
 	for i, tc := range testCases {
@@ -137,7 +138,7 @@ func TestStscContainingChunks(t *testing.T) {
 	}
 }
 func TestGetChunk(t *testing.T) {
-	stsc := &StscBox{}
+	stsc := &mp4.StscBox{}
 	err := stsc.AddEntry(1, 256, 1)
 	if err != nil {
 		t.Error(err)
@@ -149,19 +150,19 @@ func TestGetChunk(t *testing.T) {
 
 	testCases := []struct {
 		chunkNr     uint32
-		wantedChunk Chunk
+		wantedChunk mp4.Chunk
 	}{
 		{
-			1, Chunk{1, 1, 256},
+			1, mp4.Chunk{1, 1, 256},
 		},
 		{
-			2, Chunk{2, 257, 256},
+			2, mp4.Chunk{2, 257, 256},
 		},
 		{
-			3, Chunk{3, 513, 1000},
+			3, mp4.Chunk{3, 513, 1000},
 		},
 		{
-			4, Chunk{4, 1513, 1000},
+			4, mp4.Chunk{4, 1513, 1000},
 		},
 	}
 
@@ -174,7 +175,7 @@ func TestGetChunk(t *testing.T) {
 }
 
 func TestStscSampleDescriptionID(t *testing.T) {
-	box := StscBox{}
+	box := mp4.StscBox{}
 	_ = box.AddEntry(1, 256, 1)
 	_ = box.AddEntry(2, 192, 1)
 	_ = box.AddEntry(3, 128, 2)
@@ -185,7 +186,7 @@ func TestBadSizeStsc(t *testing.T) {
 	// raw stsc box with size 16, but with one entry, so its size should be 28ß
 	raw := []byte{0x00, 0x00, 0x00, 0x10, 's', 't', 's', 'c', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
 	buf := bytes.NewBuffer(raw)
-	_, err := DecodeBox(0, buf)
+	_, err := mp4.DecodeBox(0, buf)
 	if err == nil {
 		t.Error("expected invalid size error")
 	}
diff --git a/mp4/stsd_test.go b/mp4/stsd_test.go
index 3cbd800..e8675e2 100644
--- a/mp4/stsd_test.go
+++ b/mp4/stsd_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,10 +6,11 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/aac"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestStsd(t *testing.T) {
-	stsd := StsdBox{}
+	stsd := mp4.StsdBox{}
 	samplingFrequency := 48000
 	asc := &aac.AudioSpecificConfig{
 		ObjectType:           2,
@@ -25,11 +26,11 @@ func TestStsd(t *testing.T) {
 		t.Error(err)
 	}
 	ascBytes := buf.Bytes()
-	esds := CreateEsdsBox(ascBytes)
-	mp4a := CreateAudioSampleEntryBox("mp4a",
+	esds := mp4.CreateEsdsBox(ascBytes)
+	mp4a := mp4.CreateAudioSampleEntryBox("mp4a",
 		uint16(asc.ChannelConfiguration),
 		16, uint16(samplingFrequency), esds)
-	btrt := BtrtBox{
+	btrt := mp4.BtrtBox{
 		BufferSizeDB: 1536,
 		MaxBitrate:   96000,
 		AvgBitrate:   96000,
@@ -53,8 +54,8 @@ func TestStsd(t *testing.T) {
 }
 
 func TestStsdEncodeDecode(t *testing.T) {
-	stsd := &StsdBox{}
-	evte := &EvteBox{}
+	stsd := &mp4.StsdBox{}
+	evte := &mp4.EvteBox{}
 	stsd.AddChild(evte)
 	boxDiffAfterEncodeAndDecode(t, stsd)
 	b, err := stsd.GetSampleDescription(0)
diff --git a/mp4/stss_test.go b/mp4/stss_test.go
index 2b8e859..fe5e450 100644
--- a/mp4/stss_test.go
+++ b/mp4/stss_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestStss(t *testing.T) {
 
 	// The following stss box has two sync samples
-	stss := &StssBox{
+	stss := &mp4.StssBox{
 		SampleNumber: []uint32{1, 26},
 	}
 
@@ -42,7 +44,7 @@ func TestStss(t *testing.T) {
 }
 
 func TestStssEncodeDecode(t *testing.T) {
-	stss := &StssBox{
+	stss := &mp4.StssBox{
 		SampleNumber: []uint32{1, 26},
 	}
 
@@ -51,7 +53,7 @@ func TestStssEncodeDecode(t *testing.T) {
 
 func TestStssNoSamples(t *testing.T) {
 	// The following pathological stss box has no samples
-	stss := &StssBox{
+	stss := &mp4.StssBox{
 		SampleNumber: nil,
 	}
 
diff --git a/mp4/stsz_test.go b/mp4/stsz_test.go
index aa033af..108810b 100644
--- a/mp4/stsz_test.go
+++ b/mp4/stsz_test.go
@@ -1,16 +1,20 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestStszEncDec(t *testing.T) {
-	stsz := StszBox{
+	stsz := mp4.StszBox{
 		SampleUniformSize: 0,
 		SampleNumber:      3,
 		SampleSize:        []uint32{112, 234, 120},
 	}
 	boxDiffAfterEncodeAndDecode(t, &stsz)
 
-	stsz = StszBox{
+	stsz = mp4.StszBox{
 		SampleUniformSize: 512,
 		SampleNumber:      1, // One sample with uniform size
 		SampleSize:        nil,
@@ -21,14 +25,14 @@ func TestStszEncDec(t *testing.T) {
 func TestStszGetTotalSize(t *testing.T) {
 	testCases := []struct {
 		name       string
-		stsz       StszBox
+		stsz       mp4.StszBox
 		startNr    uint32
 		endNr      uint32
 		wantedSize uint64
 	}{
 		{
 			name: "uniform size",
-			stsz: StszBox{
+			stsz: mp4.StszBox{
 				SampleUniformSize: 512,
 				SampleNumber:      4,
 			},
@@ -38,7 +42,7 @@ func TestStszGetTotalSize(t *testing.T) {
 		},
 		{
 			name: "sample sizes",
-			stsz: StszBox{
+			stsz: mp4.StszBox{
 				SampleUniformSize: 0,
 				SampleNumber:      4,
 				SampleSize:        []uint32{1, 2, 3, 4},
diff --git a/mp4/stts_test.go b/mp4/stts_test.go
index fa2f3cd..b6d613a 100644
--- a/mp4/stts_test.go
+++ b/mp4/stts_test.go
@@ -1,9 +1,13 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestSttsEncDec(t *testing.T) {
-	stts := SttsBox{
+	stts := mp4.SttsBox{
 		SampleCount:     []uint32{3, 2},
 		SampleTimeDelta: []uint32{10, 14},
 	}
@@ -12,18 +16,18 @@ func TestSttsEncDec(t *testing.T) {
 
 func TestGetSampleNrAtTime(t *testing.T) {
 
-	stts := SttsBox{
+	stts := mp4.SttsBox{
 		SampleCount:     []uint32{3, 2},
 		SampleTimeDelta: []uint32{10, 14},
 	}
 
-	sttsZero := SttsBox{
+	sttsZero := mp4.SttsBox{
 		SampleCount:     []uint32{2, 1},
 		SampleTimeDelta: []uint32{10, 0}, // Single zero duration at end
 	}
 
 	testCases := []struct {
-		stts        SttsBox
+		stts        mp4.SttsBox
 		startTime   uint64
 		sampleNr    uint32
 		expectError bool
@@ -64,7 +68,7 @@ func TestGetSampleNrAtTime(t *testing.T) {
 }
 
 func TestGetDecodeTime(t *testing.T) {
-	stts := SttsBox{
+	stts := mp4.SttsBox{
 		SampleCount:     []uint32{3, 1, 1},
 		SampleTimeDelta: []uint32{1024, 1025, 1024},
 	}
diff --git a/mp4/subs_test.go b/mp4/subs_test.go
index e98f56d..b46ba30 100644
--- a/mp4/subs_test.go
+++ b/mp4/subs_test.go
@@ -1,22 +1,24 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestSubs(t *testing.T) {
 
-	subs := &SubsBox{}
-	e := SubsSample{SubsampleSize: 1000, SubsamplePriority: 255, Discardable: 0, CodecSpecificParameters: 0}
-	subs.Entries = append(subs.Entries, SubsEntry{SampleDelta: 100, SubSamples: []SubsSample{e}})
+	subs := &mp4.SubsBox{}
+	e := mp4.SubsSample{SubsampleSize: 1000, SubsamplePriority: 255, Discardable: 0, CodecSpecificParameters: 0}
+	subs.Entries = append(subs.Entries, mp4.SubsEntry{SampleDelta: 100, SubSamples: []mp4.SubsSample{e}})
 	boxDiffAfterEncodeAndDecode(t, subs)
 }
 
 func TestSubsInfo(t *testing.T) {
 	goldenDumpPath := "testdata/golden_subs_dump.txt"
-	subs := &SubsBox{}
-	e := SubsSample{SubsampleSize: 1000, SubsamplePriority: 255, Discardable: 0, CodecSpecificParameters: 0}
-	subs.Entries = append(subs.Entries, SubsEntry{SampleDelta: 100, SubSamples: []SubsSample{e}})
+	subs := &mp4.SubsBox{}
+	e := mp4.SubsSample{SubsampleSize: 1000, SubsamplePriority: 255, Discardable: 0, CodecSpecificParameters: 0}
+	subs.Entries = append(subs.Entries, mp4.SubsEntry{SampleDelta: 100, SubSamples: []mp4.SubsSample{e}})
 
 	err := compareOrUpdateInfo(t, subs, goldenDumpPath)
 	if err != nil {
diff --git a/mp4/tfdt_test.go b/mp4/tfdt_test.go
index 0d0595f..7fbd7f6 100644
--- a/mp4/tfdt_test.go
+++ b/mp4/tfdt_test.go
@@ -1,22 +1,24 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestTfdtReadingV0(t *testing.T) {
 	byteData, _ := hex.DecodeString("00000010746664740000000000ffffff")
 
 	r := bytes.NewReader(byteData[8:]) // Don't include header
-	bHdr := BoxHeader{
+	bHdr := mp4.BoxHeader{
 		Name:   "tfdt",
 		Size:   uint64(len(byteData)),
 		Hdrlen: 8,
 	}
-	box, _ := DecodeTfdt(bHdr, 0, r)
-	tfdt := box.(*TfdtBox)
+	box, _ := mp4.DecodeTfdt(bHdr, 0, r)
+	tfdt := box.(*mp4.TfdtBox)
 
 	if tfdt.Version != 0 {
 		t.Errorf("Tfdt version is not 0")
@@ -30,13 +32,13 @@ func TestTfdtReadingV1(t *testing.T) {
 	byteData, _ := hex.DecodeString("0000001474666474010000000000000000ffffff")
 
 	r := bytes.NewReader(byteData[8:]) // Don't include header
-	bHdr := BoxHeader{
+	bHdr := mp4.BoxHeader{
 		Name:   "tfdt",
 		Size:   uint64(len(byteData)),
 		Hdrlen: 8,
 	}
-	box, _ := DecodeTfdt(bHdr, 0, r)
-	tfdt := box.(*TfdtBox)
+	box, _ := mp4.DecodeTfdt(bHdr, 0, r)
+	tfdt := box.(*mp4.TfdtBox)
 
 	if tfdt.Version != 1 {
 		t.Errorf("Tfdt version is not 1")
@@ -50,16 +52,16 @@ func TestTfdtWriteV1(t *testing.T) {
 	byteData, _ := hex.DecodeString("0000001474666474010000000000000000ffffff")
 
 	r := bytes.NewReader(byteData[8:]) // Don't include header
-	bHdr := BoxHeader{
+	bHdr := mp4.BoxHeader{
 		Name:   "tfdt",
 		Size:   uint64(len(byteData)),
 		Hdrlen: 8,
 	}
-	box, err := DecodeTfdt(bHdr, 0, r)
+	box, err := mp4.DecodeTfdt(bHdr, 0, r)
 	if err != nil {
 		t.Error(err)
 	}
-	tfdt := box.(*TfdtBox)
+	tfdt := box.(*mp4.TfdtBox)
 
 	outBuf := make([]byte, 0, tfdt.Size())
 
diff --git a/mp4/tfhd_test.go b/mp4/tfhd_test.go
index 07972d5..f081a79 100644
--- a/mp4/tfhd_test.go
+++ b/mp4/tfhd_test.go
@@ -1,10 +1,11 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/hex"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
@@ -14,11 +15,11 @@ func TestTfhd(t *testing.T) {
 
 	inRawBox, _ := hex.DecodeString(tfhdRawBox)
 	inbuf := bytes.NewBuffer(inRawBox)
-	hdr, err := DecodeHeader(inbuf)
+	hdr, err := mp4.DecodeHeader(inbuf)
 	if err != nil {
 		t.Error(err)
 	}
-	tfhdRead, err := DecodeTfhd(hdr, 0, inbuf)
+	tfhdRead, err := mp4.DecodeTfhd(hdr, 0, inbuf)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/tkhd_test.go b/mp4/tkhd_test.go
index 547b289..2c508a1 100644
--- a/mp4/tkhd_test.go
+++ b/mp4/tkhd_test.go
@@ -1,15 +1,17 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"reflect"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestTkhd(t *testing.T) {
 	var buf bytes.Buffer
 
-	tkhdCreated := CreateTkhd()
+	tkhdCreated := mp4.CreateTkhd()
 	err := tkhdCreated.Encode(&buf)
 	if err != nil {
 		t.Error(err)
@@ -20,11 +22,11 @@ func TestTkhd(t *testing.T) {
 	}
 
 	reader := &buf
-	hdr, err := DecodeHeader(reader)
+	hdr, err := mp4.DecodeHeader(reader)
 	if err != nil {
 		t.Error(err)
 	}
-	tkhdRead, err := DecodeTkhd(hdr, 0, reader)
+	tkhdRead, err := mp4.DecodeTkhd(hdr, 0, reader)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/mp4/topboxinfo_test.go b/mp4/topboxinfo_test.go
index 777610f..43a13c5 100644
--- a/mp4/topboxinfo_test.go
+++ b/mp4/topboxinfo_test.go
@@ -1,10 +1,11 @@
-package mp4
+package mp4_test
 
 import (
 	"os"
 	"reflect"
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
@@ -14,13 +15,13 @@ func TestTopBoxInfo(t *testing.T) {
 	testCases := []struct {
 		name        string
 		stopBoxType string
-		wantedTBI   []TopBoxInfo
+		wantedTBI   []mp4.TopBoxInfo
 	}{
 		{
-			"before moov", "moov", []TopBoxInfo{{"ftyp", 24, 0}},
+			"before moov", "moov", []mp4.TopBoxInfo{{"ftyp", 24, 0}},
 		},
 		{
-			"all", "", []TopBoxInfo{{"ftyp", 24, 0}, {"moov", 5089, 24}},
+			"all", "", []mp4.TopBoxInfo{{"ftyp", 24, 0}, {"moov", 5089, 24}},
 		},
 	}
 
@@ -29,7 +30,7 @@ func TestTopBoxInfo(t *testing.T) {
 		if err != nil {
 			t.Error(err)
 		}
-		gotTBI, err := GetTopBoxInfoList(fh, tc.stopBoxType)
+		gotTBI, err := mp4.GetTopBoxInfoList(fh, tc.stopBoxType)
 		if err != nil {
 			t.Error(err)
 		}
diff --git a/mp4/traf_test.go b/mp4/traf_test.go
index ddb821d..e10bed6 100644
--- a/mp4/traf_test.go
+++ b/mp4/traf_test.go
@@ -1,23 +1,25 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"reflect"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
-func createTestTrafBox() *TrafBox {
-	traf := &TrafBox{}
-	tfhd := &TfhdBox{}
+func createTestTrafBox() *mp4.TrafBox {
+	traf := &mp4.TrafBox{}
+	tfhd := &mp4.TfhdBox{}
 	_ = traf.AddChild(tfhd)
-	trun := CreateTrun(0)
+	trun := mp4.CreateTrun(0)
 	_ = traf.AddChild(trun)
 	return traf
 }
 
 type testSamples struct {
 	name    string
-	samples []Sample
+	samples []mp4.Sample
 }
 
 func TestTrafTrunWithoutOptimization(t *testing.T) {
@@ -25,39 +27,39 @@ func TestTrafTrunWithoutOptimization(t *testing.T) {
 	tests := []testSamples{
 		{
 			"audioSamples",
-			[]Sample{
-				{SyncSampleFlags, 1024, 234, 0},
-				{SyncSampleFlags, 1024, 235, 0},
-				{SyncSampleFlags, 1024, 235, 0},
+			[]mp4.Sample{
+				{mp4.SyncSampleFlags, 1024, 234, 0},
+				{mp4.SyncSampleFlags, 1024, 235, 0},
+				{mp4.SyncSampleFlags, 1024, 235, 0},
 			},
 		},
 		{
 			"videoWithInitialSyncSample",
-			[]Sample{
-				{SyncSampleFlags, 1024, 234, 0},
-				{NonSyncSampleFlags, 1024, 235, 0},
-				{NonSyncSampleFlags, 1024, 235, 0},
+			[]mp4.Sample{
+				{mp4.SyncSampleFlags, 1024, 234, 0},
+				{mp4.NonSyncSampleFlags, 1024, 235, 0},
+				{mp4.NonSyncSampleFlags, 1024, 235, 0},
 			},
 		},
 		{
 			"videoWithMultipleSyncSamplesAndCto",
-			[]Sample{
-				{SyncSampleFlags, 1024, 234, 0},
-				{NonSyncSampleFlags, 1024, 235, 2048},
-				{SyncSampleFlags, 1024, 235, -1024},
+			[]mp4.Sample{
+				{mp4.SyncSampleFlags, 1024, 234, 0},
+				{mp4.NonSyncSampleFlags, 1024, 235, 2048},
+				{mp4.SyncSampleFlags, 1024, 235, -1024},
 			},
 		},
 		{
 			"singleSample",
-			[]Sample{
-				{SyncSampleFlags, 1024, 234, 0},
+			[]mp4.Sample{
+				{mp4.SyncSampleFlags, 1024, 234, 0},
 			},
 		},
 		{
 			"sameSize",
-			[]Sample{
-				{SyncSampleFlags, 1024, 234, 0},
-				{SyncSampleFlags, 1024, 234, 0},
+			[]mp4.Sample{
+				{mp4.SyncSampleFlags, 1024, 234, 0},
+				{mp4.SyncSampleFlags, 1024, 234, 0},
 			},
 		},
 	}
@@ -91,13 +93,13 @@ func runEncodeDecode(t *testing.T, test testSamples, withOptimization bool) {
 	if err != nil {
 		t.Error(err)
 	}
-	box, err := DecodeBox(0, &buf)
+	box, err := mp4.DecodeBox(0, &buf)
 	if err != nil {
 		t.Error(err)
 	}
-	outTraf := box.(*TrafBox)
+	outTraf := box.(*mp4.TrafBox)
 	outTrun := outTraf.Trun
-	trex := &TrexBox{}
+	trex := &mp4.TrexBox{}
 	outTrun.AddSampleDefaultValues(outTraf.Tfhd, trex)
 	outSamples := outTrun.Samples
 	if !reflect.DeepEqual(outSamples, test.samples) {
diff --git a/mp4/trak_test.go b/mp4/trak_test.go
index b9a4d94..b7d5365 100644
--- a/mp4/trak_test.go
+++ b/mp4/trak_test.go
@@ -1,8 +1,10 @@
-package mp4
+package mp4_test
 
 import (
 	"os"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestTrakSampleFunctions(t *testing.T) {
@@ -12,7 +14,7 @@ func TestTrakSampleFunctions(t *testing.T) {
 		t.Fatal(err)
 	}
 	defer f.Close()
-	mf, err := DecodeFile(f)
+	mf, err := mp4.DecodeFile(f)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/mp4/tref_test.go b/mp4/tref_test.go
index e2cae07..f9afc47 100644
--- a/mp4/tref_test.go
+++ b/mp4/tref_test.go
@@ -1,22 +1,24 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestTref(t *testing.T) {
-	tref := TrefBox{}
-	tref.AddChild(&TrefTypeBox{Name: "hint", TrackIDs: []uint32{1}})
-	tref.AddChild(&TrefTypeBox{Name: "cdsc", TrackIDs: []uint32{2}})
-	tref.AddChild(&TrefTypeBox{Name: "font", TrackIDs: []uint32{3}})
-	tref.AddChild(&TrefTypeBox{Name: "hind", TrackIDs: []uint32{4}})
-	tref.AddChild(&TrefTypeBox{Name: "vdep", TrackIDs: []uint32{5}})
-	tref.AddChild(&TrefTypeBox{Name: "vdep", TrackIDs: []uint32{6}})
-	tref.AddChild(&TrefTypeBox{Name: "vplx", TrackIDs: []uint32{7}})
-	tref.AddChild(&TrefTypeBox{Name: "subt", TrackIDs: []uint32{8}})
-	tref.AddChild(&TrefTypeBox{Name: "dpnd", TrackIDs: []uint32{9}})
-	tref.AddChild(&TrefTypeBox{Name: "ipir", TrackIDs: []uint32{10}})
-	tref.AddChild(&TrefTypeBox{Name: "mpod", TrackIDs: []uint32{11}})
-	tref.AddChild(&TrefTypeBox{Name: "sync", TrackIDs: []uint32{12, 13}})
+	tref := mp4.TrefBox{}
+	tref.AddChild(&mp4.TrefTypeBox{Name: "hint", TrackIDs: []uint32{1}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "cdsc", TrackIDs: []uint32{2}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "font", TrackIDs: []uint32{3}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "hind", TrackIDs: []uint32{4}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "vdep", TrackIDs: []uint32{5}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "vdep", TrackIDs: []uint32{6}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "vplx", TrackIDs: []uint32{7}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "subt", TrackIDs: []uint32{8}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "dpnd", TrackIDs: []uint32{9}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "ipir", TrackIDs: []uint32{10}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "mpod", TrackIDs: []uint32{11}})
+	tref.AddChild(&mp4.TrefTypeBox{Name: "sync", TrackIDs: []uint32{12, 13}})
 	boxDiffAfterEncodeAndDecode(t, &tref)
 }
diff --git a/mp4/trep_test.go b/mp4/trep_test.go
index 2365995..adfc5b4 100644
--- a/mp4/trep_test.go
+++ b/mp4/trep_test.go
@@ -1,11 +1,13 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestTrep(t *testing.T) {
-	trep := &TrepBox{TrackID: 1}
-	trep.AddChild(&KindBox{SchemeURI: "X", Value: "Y"})
+	trep := &mp4.TrepBox{TrackID: 1}
+	trep.AddChild(&mp4.KindBox{SchemeURI: "X", Value: "Y"})
 	boxDiffAfterEncodeAndDecode(t, trep)
 }
diff --git a/mp4/trun_test.go b/mp4/trun_test.go
index e84c2a0..8af0aa9 100644
--- a/mp4/trun_test.go
+++ b/mp4/trun_test.go
@@ -1,19 +1,20 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
 
+	"github.com/Eyevinn/mp4ff/mp4"
 	"github.com/go-test/deep"
 )
 
 // TestTrunDump versus golden file. Can be regenerated with -update
 func TestTrunInfo(t *testing.T) {
 	goldenDumpPath := "testdata/golden_trun_dump.txt"
-	trun := CreateTrun(0)
+	trun := mp4.CreateTrun(0)
 	trun.DataOffset = 314159
-	fs := FullSample{
-		Sample: Sample{
-			Flags:                 SyncSampleFlags,
+	fs := mp4.FullSample{
+		Sample: mp4.Sample{
+			Flags:                 mp4.SyncSampleFlags,
 			Dur:                   1024,
 			Size:                  4,
 			CompositionTimeOffset: -512,
@@ -30,9 +31,8 @@ func TestTrunInfo(t *testing.T) {
 }
 
 func TestGetSampleNrForRelativeTime(t *testing.T) {
-	trun := CreateTrun(0)
-	trun.AddSamples([]Sample{
-		{0, 1024, 100, 0},
+	trun := mp4.CreateTrun(0)
+	trun.AddSamples([]mp4.Sample{
 		{0, 1024, 100, 0},
 		{0, 1024, 100, 0},
 		{0, 1024, 100, 0},
@@ -40,7 +40,7 @@ func TestGetSampleNrForRelativeTime(t *testing.T) {
 		{0, 1024, 100, 0},
 		{0, 1024, 100, 0},
 	})
-	trun.Flags |= TrunSampleSizePresentFlag | TrunSampleDurationPresentFlag
+	trun.Flags |= mp4.TrunSampleSizePresentFlag | mp4.TrunSampleDurationPresentFlag
 
 	testCases := []struct {
 		sampleTime     uint64
@@ -52,10 +52,10 @@ func TestGetSampleNrForRelativeTime(t *testing.T) {
 		{5 * 1024, 6, 0, false},
 		{1023, 0, 0, true},
 		{7 * 1024, 0, 0, true},
-		{0, 1, TrunSampleDurationPresentFlag, false},
-		{5 * 1024, 6, TrunSampleDurationPresentFlag, false},
-		{1023, 0, TrunSampleDurationPresentFlag, true},
-		{7 * 1024, 0, TrunSampleDurationPresentFlag, true},
+		{0, 1, mp4.TrunSampleDurationPresentFlag, false},
+		{5 * 1024, 6, mp4.TrunSampleDurationPresentFlag, false},
+		{1023, 0, mp4.TrunSampleDurationPresentFlag, true},
+		{7 * 1024, 0, mp4.TrunSampleDurationPresentFlag, true},
 	}
 
 	const defaultSampleDuration = 1024
@@ -80,8 +80,8 @@ func TestGetSampleNrForRelativeTime(t *testing.T) {
 }
 
 func TestGetSampleInterval(t *testing.T) {
-	trun := CreateTrun(0)
-	trun.AddSamples([]Sample{
+	trun := mp4.CreateTrun(0)
+	trun.AddSamples([]mp4.Sample{
 		{0, 100, 1000, 0},
 		{0, 200, 2000, 0},
 		{0, 300, 3000, 0},
@@ -91,21 +91,28 @@ func TestGetSampleInterval(t *testing.T) {
 		{0, 700, 7000, 0},
 	})
 
-	mdat := MdatBox{lazyDataSize: 28000}
+	// Use lazyMdat since we don't care about the actual data
+	raw := []byte{0x00, 0x00, 0x00, 0x0e, 0x6d, 0x64, 0x61, 0x74, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
+	testSeeker := newTestReadSeeker(raw)
+	box, err := mp4.DecodeBoxLazyMdat(4000, testSeeker)
+	if err != nil {
+		t.Error(err)
+	}
+	lazyMdat := box.(*mp4.MdatBox)
 
 	testCases := []struct {
 		startSampleNr  uint32
 		endSampleNr    uint32
 		baseDecodeTime uint64
-		mdat           *MdatBox
+		mdat           *mp4.MdatBox
 		offsetInMdat   uint32
-		wantedSItvl    SampleInterval
+		wantedSItvl    mp4.SampleInterval
 	}{
 		{
-			1, 2, 10000, &mdat, 0, SampleInterval{10000, []Sample{{0, 100, 1000, 0}, {0, 200, 2000, 0}}, 0, 3000, nil},
+			1, 2, 10000, lazyMdat, 0, mp4.SampleInterval{10000, []mp4.Sample{{0, 100, 1000, 0}, {0, 200, 2000, 0}}, 0, 3000, nil},
 		},
 		{
-			3, 4, 10000, &mdat, 0, SampleInterval{10300, []Sample{{0, 300, 3000, 0}, {0, 400, 4000, 0}}, 3000, 7000, nil},
+			3, 4, 10000, lazyMdat, 0, mp4.SampleInterval{10300, []mp4.Sample{{0, 300, 3000, 0}, {0, 400, 4000, 0}}, 3000, 7000, nil},
 		},
 	}
 
@@ -121,16 +128,16 @@ func TestGetSampleInterval(t *testing.T) {
 }
 
 func TestFirstSampleFlags(t *testing.T) {
-	trun := CreateTrun(0)
+	trun := mp4.CreateTrun(0)
 	trun.DataOffset = 314159
-	trun.AddSample(Sample{
-		Flags:                 NonSyncSampleFlags,
+	trun.AddSample(mp4.Sample{
+		Flags:                 mp4.NonSyncSampleFlags,
 		Dur:                   1000,
 		Size:                  1000,
 		CompositionTimeOffset: 0,
 	})
-	trun.AddSample(Sample{
-		Flags:                 NonSyncSampleFlags,
+	trun.AddSample(mp4.Sample{
+		Flags:                 mp4.NonSyncSampleFlags,
 		Dur:                   1000,
 		Size:                  1000,
 		CompositionTimeOffset: 0,
@@ -139,13 +146,13 @@ func TestFirstSampleFlags(t *testing.T) {
 	if present {
 		t.Error("firstSampleFlags present")
 	}
-	trun.SetFirstSampleFlags(SyncSampleFlags)
+	trun.SetFirstSampleFlags(mp4.SyncSampleFlags)
 	gotFirstFlags, present := trun.FirstSampleFlags()
 	if !present {
 		t.Error("firstSampleFlags absent")
 	}
-	if gotFirstFlags != SyncSampleFlags {
-		t.Errorf("got firstSampleFlags %02x instead of %02x", gotFirstFlags, SyncSampleFlags)
+	if gotFirstFlags != mp4.SyncSampleFlags {
+		t.Errorf("got firstSampleFlags %02x instead of %02x", gotFirstFlags, mp4.SyncSampleFlags)
 	}
 	trun.RemoveFirstSampleFlags()
 	_, present = trun.FirstSampleFlags()
@@ -177,12 +184,12 @@ func TestCommonDuration(t *testing.T) {
 		},
 	}
 	for _, c := range cases {
-		trun := CreateTrun(0)
+		trun := mp4.CreateTrun(0)
 		for _, s := range c.sampleDurs {
-			trun.AddSample(Sample{Dur: s})
+			trun.AddSample(mp4.Sample{Dur: s})
 		}
 		if c.commonDur != 0 {
-			trun.Flags &= ^TrunSampleDurationPresentFlag
+			trun.Flags &= ^mp4.TrunSampleDurationPresentFlag
 		}
 		gotCommonDur := trun.CommonSampleDuration(c.commonDur)
 		if gotCommonDur != c.wantedCommonDur {
diff --git a/mp4/udta_test.go b/mp4/udta_test.go
index b38184f..ed2641d 100644
--- a/mp4/udta_test.go
+++ b/mp4/udta_test.go
@@ -1,15 +1,14 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
 
-func TestUdta(t *testing.T) {
-	udta := &UdtaBox{}
-	unknown := &UnknownBox{
-		name:       "\xa9enc",
-		size:       12,
-		notDecoded: []byte{0, 0, 0, 0},
-	}
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
+func TestUdta(t *testing.T) {
+	udta := &mp4.UdtaBox{}
+	unknown := mp4.CreateUnknownBox("\xa9enc", 12, []byte{0, 0, 0, 0})
 	udta.AddChild(unknown) // Any arbitrary box
 	boxDiffAfterEncodeAndDecode(t, udta)
 }
diff --git a/mp4/unknown_test.go b/mp4/unknown_test.go
index 5989d5b..edfec69 100644
--- a/mp4/unknown_test.go
+++ b/mp4/unknown_test.go
@@ -1,17 +1,22 @@
-package mp4
+package mp4_test
 
 import (
+	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 // TestUnknown including non-ascii character in name (box typs is uint32 according to spec)
 func TestUnknown(t *testing.T) {
 
-	unknownBox := &UnknownBox{
-		name:       "\xa9enc",
-		size:       12,
-		notDecoded: []byte{0, 0, 0, 0},
-	}
+	payload := []byte{0, 0, 0, 0}
+
+	unknownBox := mp4.CreateUnknownBox("\xa9enc", 12, payload)
 
 	boxDiffAfterEncodeAndDecode(t, unknownBox)
+
+	if !bytes.Equal(unknownBox.Payload(), payload) {
+		t.Errorf("Payload not decoded correctly")
+	}
 }
diff --git a/mp4/url_test.go b/mp4/url_test.go
index 73012c8..bd08e83 100644
--- a/mp4/url_test.go
+++ b/mp4/url_test.go
@@ -1,4 +1,4 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
@@ -6,11 +6,12 @@ import (
 	"testing"
 
 	"github.com/Eyevinn/mp4ff/bits"
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestUrl(t *testing.T) {
 
-	urlBox := &URLBox{
+	urlBox := &mp4.URLBox{
 		Version:  0,
 		Flags:    0,
 		Location: "location",
@@ -60,14 +61,14 @@ func TestUrlDecode(t *testing.T) {
 				t.Error(err)
 			}
 			sr := bits.NewFixedSliceReader(d)
-			box, err := DecodeBoxSR(0, sr)
+			box, err := mp4.DecodeBoxSR(0, sr)
 			if err != nil {
 				t.Error(err)
 			}
 			if box.Type() != "url " {
 				t.Errorf("Expected 'url ', got %s", box.Type())
 			}
-			urlBox := box.(*URLBox)
+			urlBox := box.(*mp4.URLBox)
 			o := bytes.Buffer{}
 			err = urlBox.Encode(&o)
 			if err != nil {
diff --git a/mp4/uuid_test.go b/mp4/uuid_test.go
index 823225c..0e6cf1e 100644
--- a/mp4/uuid_test.go
+++ b/mp4/uuid_test.go
@@ -1,9 +1,11 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestUUIDVariants(t *testing.T) {
@@ -26,15 +28,15 @@ func TestUUIDVariants(t *testing.T) {
 	for _, ti := range testInputs {
 		inRawBox, _ := hex.DecodeString(ti.rawData)
 		inbuf := bytes.NewBuffer(inRawBox)
-		hdr, err := DecodeHeader(inbuf)
+		hdr, err := mp4.DecodeHeader(inbuf)
 		if err != nil {
 			t.Error(err)
 		}
-		uuidRead, err := DecodeUUIDBox(hdr, 0, inbuf)
+		uuidRead, err := mp4.DecodeUUIDBox(hdr, 0, inbuf)
 		if err != nil {
 			t.Error(err)
 		}
-		uBox := uuidRead.(*UUIDBox)
+		uBox := uuidRead.(*mp4.UUIDBox)
 		if uBox.SubType() != ti.expectedSubType {
 			t.Errorf("got subtype %s instead of %s", uBox.SubType(), ti.expectedSubType)
 		}
@@ -60,7 +62,7 @@ func TestUUIDVariants(t *testing.T) {
 func TestSetUUID(t *testing.T) {
 	testCases := []struct {
 		uuidStr    string
-		expected   UUID
+		expected   mp4.UUID
 		shouldFail bool
 	}{
 		{
@@ -73,7 +75,7 @@ func TestSetUUID(t *testing.T) {
 		},
 	}
 	for i, tc := range testCases {
-		u := UUIDBox{}
+		u := mp4.UUIDBox{}
 		err := u.SetUUID(tc.uuidStr)
 		if tc.shouldFail {
 			if err == nil {
@@ -89,24 +91,10 @@ func TestSetUUID(t *testing.T) {
 
 func TestUUIDEncodeDecoder(t *testing.T) {
 
-	tfrf := &UUIDBox{
-		uuid: mustCreateUUID(UUIDTfrf),
-		Tfrf: &TfrfData{
-			FragmentCount:             1,
-			FragmentAbsoluteTimes:     []uint64{0},
-			FragmentAbsoluteDurations: []uint64{1000000},
-		},
-	}
-
+	tfrf := mp4.NewTfrfBox(1, []uint64{0}, []uint64{1000000})
 	boxDiffAfterEncodeAndDecode(t, tfrf)
 
-	tfxd := &UUIDBox{
-		uuid: mustCreateUUID(UUIDTfxd),
-		Tfxd: &TfxdData{
-			FragmentAbsoluteTime:     0,
-			FragmentAbsoluteDuration: 1000000,
-		},
-	}
+	tfxd := mp4.NewTfxdBox(0, 1_000_000)
 	boxDiffAfterEncodeAndDecode(t, tfxd)
 }
 
@@ -164,7 +152,7 @@ func TestUnpackKey(t *testing.T) {
 	}
 	for _, c := range cases {
 		t.Run(c.desc, func(t *testing.T) {
-			key, err := UnpackKey(c.keyStr)
+			key, err := mp4.UnpackKey(c.keyStr)
 			if c.expectedErr != "" {
 				if err == nil {
 					t.Error("expected error but got nil")
diff --git a/mp4/visualsampleentry_test.go b/mp4/visualsampleentry_test.go
index 400785d..070539f 100644
--- a/mp4/visualsampleentry_test.go
+++ b/mp4/visualsampleentry_test.go
@@ -1,12 +1,14 @@
-package mp4
+package mp4_test
 
 import (
 	"encoding/hex"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestVisualSampleEntryBoxVP9(t *testing.T) {
-	vppC := &VppCBox{
+	vppC := &mp4.VppCBox{
 		Version:                 1,
 		Flags:                   0,
 		Profile:                 1,
@@ -19,17 +21,17 @@ func TestVisualSampleEntryBoxVP9(t *testing.T) {
 		MatrixCoefficients:      0,
 		CodecInitData:           nil,
 	}
-	vp9 := CreateVisualSampleEntryBox("vp09", 1280, 720, vppC)
-	smdm := CreateSmDmBox(0, 1, 2, 3, 4, 5, 6, 7, 255, 255)
+	vp9 := mp4.CreateVisualSampleEntryBox("vp09", 1280, 720, vppC)
+	smdm := mp4.CreateSmDmBox(0, 1, 2, 3, 4, 5, 6, 7, 255, 255)
 	vp9.AddChild(smdm)
-	coll := CreateCoLLBox(1000, 500)
+	coll := mp4.CreateCoLLBox(1000, 500)
 	vp9.AddChild(coll)
 	boxDiffAfterEncodeAndDecode(t, vp9)
 
-	minFilled := NewVisualSampleEntryBox("avc3")
+	minFilled := mp4.NewVisualSampleEntryBox("avc3")
 	boxDiffAfterEncodeAndDecode(t, minFilled)
 
-	minAvc1 := NewVisualSampleEntryBox("avc1")
+	minAvc1 := mp4.NewVisualSampleEntryBox("avc1")
 	err := minAvc1.ConvertAvc3ToAvc1(nil, nil)
 	if err == nil {
 		t.Error("ConvertAvc3ToAvc1 should return error")
@@ -45,12 +47,12 @@ func TestVisualSampleEntryBoxVP9(t *testing.T) {
 	}
 	spss := [][]byte{sps1}
 	ppss := [][]byte{pps1}
-	avcC, err := CreateAvcC(spss, ppss, false /* includePS */)
+	avcC, err := mp4.CreateAvcC(spss, ppss, false /* includePS */)
 	if err != nil {
 		t.Errorf("error creating avcC: %s", err.Error())
 		t.Fail()
 	}
-	avcx := CreateVisualSampleEntryBox("avc3", 1280, 720, avcC)
+	avcx := mp4.CreateVisualSampleEntryBox("avc3", 1280, 720, avcC)
 	err = avcx.ConvertAvc3ToAvc1(spss, ppss)
 	if err != nil {
 		t.Errorf("")
diff --git a/mp4/vmhd_test.go b/mp4/vmhd_test.go
index edc9b4a..2ca936a 100644
--- a/mp4/vmhd_test.go
+++ b/mp4/vmhd_test.go
@@ -1,10 +1,14 @@
-package mp4
+package mp4_test
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
+)
 
 func TestVmhd(t *testing.T) {
 
-	vmhd := CreateVmhd()
+	vmhd := mp4.CreateVmhd()
 
 	boxDiffAfterEncodeAndDecode(t, vmhd)
 }
diff --git a/mp4/vppc_test.go b/mp4/vppc_test.go
index 3bf609b..13694d3 100644
--- a/mp4/vppc_test.go
+++ b/mp4/vppc_test.go
@@ -1,13 +1,15 @@
-package mp4
+package mp4_test
 
 import (
 	"bytes"
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestVppC(t *testing.T) {
 	// Create a sample VppC box
-	vppc := &VppCBox{
+	vppc := &mp4.VppCBox{
 		Version:                 1,
 		Flags:                   0,
 		Profile:                 1,
@@ -35,7 +37,7 @@ func TestVppC(t *testing.T) {
 	raw := make([]byte, len(data))
 	copy(raw, data)
 	raw[8] = 0
-	_, err = DecodeBox(0, bytes.NewBuffer(raw))
+	_, err = mp4.DecodeBox(0, bytes.NewBuffer(raw))
 	errMsg := "decode vpcC pos 0: version 0 not supported"
 	if err == nil || err.Error() != errMsg {
 		t.Errorf("Expected error msg: %q", errMsg)
diff --git a/mp4/wvtt_test.go b/mp4/wvtt_test.go
index c34a602..f3c7d1d 100644
--- a/mp4/wvtt_test.go
+++ b/mp4/wvtt_test.go
@@ -1,29 +1,31 @@
-package mp4
+package mp4_test
 
 import (
 	"testing"
+
+	"github.com/Eyevinn/mp4ff/mp4"
 )
 
 func TestVttc(t *testing.T) {
 
-	vttc := &VttcBox{}
-	vttc.AddChild(&VsidBox{SourceID: 42})
-	vttc.AddChild(&CtimBox{CueCurrentTime: "00:00:00.120"})
-	vttc.AddChild(&IdenBox{CueID: "ten"})
-	vttc.AddChild(&SttgBox{Settings: "line:20%"})
-	vttc.AddChild(&PaylBox{CueText: "A line"})
+	vttc := &mp4.VttcBox{}
+	vttc.AddChild(&mp4.VsidBox{SourceID: 42})
+	vttc.AddChild(&mp4.CtimBox{CueCurrentTime: "00:00:00.120"})
+	vttc.AddChild(&mp4.IdenBox{CueID: "ten"})
+	vttc.AddChild(&mp4.SttgBox{Settings: "line:20%"})
+	vttc.AddChild(&mp4.PaylBox{CueText: "A line"})
 
 	boxDiffAfterEncodeAndDecode(t, vttc)
 }
 
 func TestWvtt(t *testing.T) {
 
-	wvtt := NewWvttBox()
-	vttC := &VttCBox{Config: "WEBVTT"}
+	wvtt := mp4.NewWvttBox()
+	vttC := &mp4.VttCBox{Config: "WEBVTT"}
 	wvtt.AddChild(vttC)
-	vlab := &VlabBox{SourceLabel: "Swedish news"}
+	vlab := &mp4.VlabBox{SourceLabel: "Swedish news"}
 	wvtt.AddChild(vlab)
-	btrt := &BtrtBox{}
+	btrt := &mp4.BtrtBox{}
 	wvtt.AddChild(btrt)
 	if vttC != wvtt.VttC || vlab != wvtt.Vlab || btrt != wvtt.Btrt {
 		t.Error("Pointers not set")
@@ -33,21 +35,21 @@ func TestWvtt(t *testing.T) {
 }
 
 func TestVtte(t *testing.T) {
-	vtte := &VtteBox{}
+	vtte := &mp4.VtteBox{}
 	boxDiffAfterEncodeAndDecode(t, vtte)
 }
 
 func TestVtta(t *testing.T) {
-	vtta := &VttaBox{CueAdditionalText: "This is a comment"}
+	vtta := &mp4.VttaBox{CueAdditionalText: "This is a comment"}
 	boxDiffAfterEncodeAndDecode(t, vtta)
 }
 
 func TestVlab(t *testing.T) {
-	vlab := &VlabBox{SourceLabel: "Swedish news"}
+	vlab := &mp4.VlabBox{SourceLabel: "Swedish news"}
 	boxDiffAfterEncodeAndDecode(t, vlab)
 }
 
 func TestVttC(t *testing.T) {
-	vttC := &VttCBox{Config: "..."}
+	vttC := &mp4.VttCBox{Config: "..."}
 	boxDiffAfterEncodeAndDecode(t, vttC)
 }