Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change target duration alg from 'ceiling' to 'round' #109

Closed
wants to merge 1 commit into from
Closed
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
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