Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

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