mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Make fragments of ~6 seconds instead of a fragment per keyframe
This commit is contained in:
parent
0579afe02b
commit
f6dab80a98
@ -4,12 +4,16 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// In seconds, the spec recomands 6 but since we don't control keyframes we go over more often than not.
|
||||||
|
const OptimalFragmentDuration = float64(5)
|
||||||
|
|
||||||
type Keyframe struct {
|
type Keyframe struct {
|
||||||
Sha string
|
Sha string
|
||||||
Keyframes []float64
|
Keyframes []float64
|
||||||
@ -97,7 +101,7 @@ func GetKeyframes(sha string, path string) *Keyframe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getKeyframes(path string, kf *Keyframe, sha string) error {
|
func getKeyframes(path string, kf *Keyframe, sha string) error {
|
||||||
defer printExecTime("ffprobe analysis for %s", path)()
|
defer printExecTime("keyframe extraction for %s", path)()
|
||||||
// run ffprobe to return all IFrames, IFrames are points where we can split the video in segments.
|
// run ffprobe to return all IFrames, IFrames are points where we can split the video in segments.
|
||||||
// We ask ffprobe to return the time of each frame and it's flags
|
// We ask ffprobe to return the time of each frame and it's flags
|
||||||
// We could ask it to return only i-frames (keyframes) with the -skip_frame nokey but using it is extremly slow
|
// We could ask it to return only i-frames (keyframes) with the -skip_frame nokey but using it is extremly slow
|
||||||
@ -123,6 +127,7 @@ func getKeyframes(path string, kf *Keyframe, sha string) error {
|
|||||||
|
|
||||||
ret := make([]float64, 0, 1000)
|
ret := make([]float64, 0, 1000)
|
||||||
max := 100
|
max := 100
|
||||||
|
last_frame := math.Inf(-1)
|
||||||
done := 0
|
done := 0
|
||||||
// sometimes, videos can start at a timing greater than 0:00. We need to take that into account
|
// sometimes, videos can start at a timing greater than 0:00. We need to take that into account
|
||||||
// and only list keyframes that come after the start of the video (without that, our segments count
|
// and only list keyframes that come after the start of the video (without that, our segments count
|
||||||
@ -154,12 +159,14 @@ func getKeyframes(path string, kf *Keyframe, sha string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before, we wanted to only save keyframes with at least 3s betweens
|
// The -f hls encoder decides to not cut at every keyframes (even if we ask it to) when they are too close by.
|
||||||
// to prevent segments of 0.2s but sometimes, the -f segment muxer discards
|
// Instead we can cut every X seconds at the next keyframe, we'll use that as a marker.
|
||||||
// the segment time and decide to cut at a random keyframe. Having every keyframe
|
if fpts < (last_frame+OptimalFragmentDuration) {
|
||||||
// handled as a segment prevents that.
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ret = append(ret, fpts)
|
ret = append(ret, fpts)
|
||||||
|
last_frame = fpts
|
||||||
|
|
||||||
if len(ret) == max {
|
if len(ret) == max {
|
||||||
kf.add(ret)
|
kf.add(ret)
|
||||||
@ -190,7 +197,7 @@ func getKeyframes(path string, kf *Keyframe, sha string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDummyKeyframes(path string, sha string) ([]float64, error) {
|
func getDummyKeyframes(path string, sha string) ([]float64, error) {
|
||||||
dummyKeyframeDuration := float64(2)
|
dummyKeyframeDuration := OptimalFragmentDuration
|
||||||
info, err := GetInfo(path, sha)
|
info, err := GetInfo(path, sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -267,8 +267,7 @@ func (ts *Stream) run(start int32) error {
|
|||||||
args = append(args, ts.handle.getTranscodeArgs(toSegmentStr(segments))...)
|
args = append(args, ts.handle.getTranscodeArgs(toSegmentStr(segments))...)
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-f", "hls",
|
"-f", "hls",
|
||||||
// Cut at every keyframes.
|
"-hls_time", fmt.Sprint(OptimalFragmentDuration),
|
||||||
"-hls_time", "0",
|
|
||||||
"-start_number", fmt.Sprint(start_segment),
|
"-start_number", fmt.Sprint(start_segment),
|
||||||
"-hls_segment_type", "fmp4",
|
"-hls_segment_type", "fmp4",
|
||||||
"-hls_fmp4_init_filename", fmt.Sprintf("%s/init.mp4", outpath),
|
"-hls_fmp4_init_filename", fmt.Sprintf("%s/init.mp4", outpath),
|
||||||
@ -361,7 +360,7 @@ func (ts *Stream) run(start int32) error {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := cmd.Wait()
|
err := cmd.Wait()
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok && exiterr.ExitCode() == 255 {
|
if exiterr, ok := err.(*exec.ExitError); ok && (exiterr.ExitCode() == 255 || exiterr.ExitCode() == -1) {
|
||||||
log.Printf("ffmpeg %d was killed by us", encoder_id)
|
log.Printf("ffmpeg %d was killed by us", encoder_id)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Printf("ffmpeg %d occurred an error: %v: %s", encoder_id, err, stderr.String())
|
log.Printf("ffmpeg %d occurred an error: %v: %s", encoder_id, err, stderr.String())
|
||||||
@ -385,11 +384,11 @@ func (ts *Stream) GetIndex() (string, error) {
|
|||||||
#EXT-X-VERSION:7
|
#EXT-X-VERSION:7
|
||||||
#EXT-X-PLAYLIST-TYPE:EVENT
|
#EXT-X-PLAYLIST-TYPE:EVENT
|
||||||
#EXT-X-START:TIME-OFFSET=0
|
#EXT-X-START:TIME-OFFSET=0
|
||||||
#EXT-X-TARGETDURATION:4
|
|
||||||
#EXT-X-MEDIA-SEQUENCE:0
|
#EXT-X-MEDIA-SEQUENCE:0
|
||||||
#EXT-X-INDEPENDENT-SEGMENTS
|
#EXT-X-INDEPENDENT-SEGMENTS
|
||||||
#EXT-X-MAP:URI="init.mp4"
|
#EXT-X-MAP:URI="init.mp4"
|
||||||
`
|
`
|
||||||
|
index += fmt.Sprintf("#EXT-X-TARGETDURATION:%d\n", int(OptimalFragmentDuration))
|
||||||
length, is_done := ts.file.Keyframes.Length()
|
length, is_done := ts.file.Keyframes.Length()
|
||||||
|
|
||||||
for segment := int32(0); segment < length-1; segment++ {
|
for segment := int32(0); segment < length-1; segment++ {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user