Skip to content

Commit

Permalink
Change target duration alg from 'ceiling' to 'round'
Browse files Browse the repository at this point in the history
  • Loading branch information
sparrc committed Jan 25, 2018
1 parent 6ab8f28 commit 2a386bb
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
56 changes: 56 additions & 0 deletions round.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package m3u8

import (
"math"
)

// some constants copied from https://github.com/golang/go/blob/master/src/math/bits.go
const (
shift = 64 - 11 - 1
bias = 1023
mask = 0x7FF
)

// round returns the nearest integer, rounding half away from zero.
// This function is available natively in Go 1.10
//
// Special cases are:
// round(±0) = ±0
// round(±Inf) = ±Inf
// round(NaN) = NaN
func round(x float64) float64 {
// Round is a faster implementation of:
//
// func Round(x float64) float64 {
// t := Trunc(x)
// if Abs(x-t) >= 0.5 {
// return t + Copysign(1, x)
// }
// return t
// }
const (
signMask = 1 << 63
fracMask = 1<<shift - 1
half = 1 << (shift - 1)
one = bias << shift
)

bits := math.Float64bits(x)
e := uint(bits>>shift) & mask
if e < bias {
// Round abs(x) < 1 including denormals.
bits &= signMask // +-0
if e == bias-1 {
bits |= one // +-1
}
} else if e < bias+shift {
// Round any abs(x) >= 1 containing a fractional component [0,1).
//
// Numbers with larger exponents are returned unchanged since they
// must be either an integer, infinity, or NaN.
e -= bias
bits += half >> e
bits &^= fracMask >> e
}
return math.Float64frombits(bits)
}
6 changes: 5 additions & 1 deletion writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,11 @@ func (p *MediaPlaylist) AppendSegment(seg *MediaSegment) error {
p.tail = (p.tail + 1) % p.capacity
p.count++
if p.TargetDuration < seg.Duration {
p.TargetDuration = math.Ceil(seg.Duration)
if p.durationAsInt {
p.TargetDuration = math.Ceil(seg.Duration)
} else {
p.TargetDuration = round(seg.Duration)
}
}
p.buf.Reset()
return nil
Expand Down
4 changes: 2 additions & 2 deletions writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ func TestTargetDurationForMediaPlaylist(t *testing.T) {
if e != nil {
t.Errorf("Add 2nd segment to a media playlist failed: %s", e)
}
if p.TargetDuration < 10.0 {
t.Errorf("Target duration must = 10 (nearest greater integer to durations 9.0 and 9.1)")
if p.TargetDuration != 9.0 {
t.Errorf("Target duration must = 9 (nearest integer to durations 9.0 and 9.1)")
}
}

Expand Down

0 comments on commit 2a386bb

Please sign in to comment.