Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
AudioSpecificConfig fields (object type including the 31-escape, base
sampling frequency, channel configuration) for every audio object type,
not just the AAC-LC and HE-AAC types the full decoder supports
- `ElstEntry.MediaRateFixed32` and `SetMediaRateFixed32` combine and split
the media rate halves as one signed 16.16 fixed-point number, so callers
no longer need to know the bit layout

### Changed

Expand Down
12 changes: 12 additions & 0 deletions mp4/elst.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ type ElstEntry struct {
MediaRateFraction int16
}

// MediaRateFixed32 - the media rate as one signed 16.16 fixed-point number (65536 is the normal rate 1.0).
// The return type is a plain int32 rather than Fixed32, since Fixed32 is unsigned and the media rate is signed.
func (e ElstEntry) MediaRateFixed32() int32 {
return int32(e.MediaRateInteger)<<16 | int32(uint16(e.MediaRateFraction))
}

// SetMediaRateFixed32 - set the media rate from a signed 16.16 fixed-point number.
func (e *ElstEntry) SetMediaRateFixed32(rate int32) {
e.MediaRateInteger = int16(rate >> 16)
e.MediaRateFraction = int16(uint16(rate))
}

// DecodeElst - box-specific decode
func DecodeElst(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
data, err := readBoxBody(r, hdr)
Expand Down
28 changes: 28 additions & 0 deletions mp4/elst_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,31 @@ func TestElst(t *testing.T) {
boxDiffAfterEncodeAndDecode(t, elst)
}
}

func TestElstMediaRateFixed32(t *testing.T) {
cases := []struct {
integer int16
fraction int16
fixed int32
}{
{1, 0, 1 << 16}, // rate 1.0
{0, 0x4000, 0x4000}, // rate 0.25
{2, -0x8000, 2<<16 | 0x8000}, // rate 2.5 (fraction bits 0x8000)
{-1, 0, -65536}, // rate -1.0
{-1, -0x8000, -0x8000}, // rate -0.5
{-2, -0x8000, int32(-2)<<16 | 0x8000}, // negative with fraction bits
{0x7fff, -1, 0x7fff<<16 | 0xffff}, // extremes
}
for _, c := range cases {
entry := mp4.ElstEntry{MediaRateInteger: c.integer, MediaRateFraction: c.fraction}
if got := entry.MediaRateFixed32(); got != c.fixed {
t.Errorf("(%d, %d): got %#x, wanted %#x", c.integer, c.fraction, got, c.fixed)
}
var back mp4.ElstEntry
back.SetMediaRateFixed32(c.fixed)
if back.MediaRateInteger != c.integer || back.MediaRateFraction != c.fraction {
t.Errorf("%#x: got (%d, %d), wanted (%d, %d)",
c.fixed, back.MediaRateInteger, back.MediaRateFraction, c.integer, c.fraction)
}
}
}
Loading