From 9a0fa098798f5ce6dbf925eaf4c681726f176c13 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 20 Jan 2020 17:40:45 +1030 Subject: [PATCH 01/22] revid/senders.go,revid.go: Added bitrate calculations to revid. --- revid/revid.go | 12 +++++++---- revid/senders.go | 53 ++++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/revid/revid.go b/revid/revid.go index 8b1b42da..5cd0fbfc 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -7,6 +7,7 @@ AUTHORS Alan Noble Dan Kortschak Trek Hopton + Scott Barnard LICENSE revid is Copyright (C) 2017-2020 the Australian Ocean Lab (AusOcean) @@ -52,6 +53,7 @@ import ( "bitbucket.org/ausocean/av/filter" "bitbucket.org/ausocean/av/revid/config" "bitbucket.org/ausocean/iot/pi/netsender" + "bitbucket.org/ausocean/utils/bitrate" "bitbucket.org/ausocean/utils/ioext" "bitbucket.org/ausocean/utils/logger" "bitbucket.org/ausocean/utils/vring" @@ -115,6 +117,9 @@ type Revid struct { // err will channel errors from revid routines to the handle errors routine. err chan error + + // bitrate is used for bitrate calculations. + bitrate bitrate.Calculator } // New returns a pointer to a new Revid with the desired configuration, and/or @@ -148,10 +153,8 @@ func (r *Revid) handleErrors() { } // Bitrate returns the result of the most recent bitrate check. -// -// TODO: get this working again. func (r *Revid) Bitrate() int { - return -1 + return r.bitrate.Bitrate() } // reset swaps the current config of a Revid with the passed @@ -266,7 +269,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. return fmt.Errorf("could not initialise MTS ring buffer: %w", err) } w = newMtsSender( - newHttpSender(r.ns, r.cfg.Logger.Log), + newHttpSender(r.ns, r.cfg.Logger.Log, r.bitrate.Report), r.cfg.Logger.Log, rb, r.cfg.ClipDuration, @@ -295,6 +298,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. rtmpConnectionMaxTries, rb, r.cfg.Logger.Log, + r.bitrate.Report, ) if err != nil { r.cfg.Logger.Log(logger.Warning, pkg+"rtmp connect error", "error", err.Error()) diff --git a/revid/senders.go b/revid/senders.go index 4871ddb5..216b191b 100644 --- a/revid/senders.go +++ b/revid/senders.go @@ -59,21 +59,27 @@ const ( // httpSender provides an implemntation of io.Writer to perform sends to a http // destination. type httpSender struct { - client *netsender.Sender - log func(lvl int8, msg string, args ...interface{}) + client *netsender.Sender + log func(lvl int8, msg string, args ...interface{}) + reportSent func(sent int) } // newHttpSender returns a pointer to a new httpSender. -func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ...interface{})) *httpSender { +func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ...interface{}), reportSent func(sent int)) *httpSender { return &httpSender{ - client: ns, - log: log, + client: ns, + log: log, + reportSent: reportSent, } } // Write implements io.Writer. func (s *httpSender) Write(d []byte) (int, error) { - return len(d), httpSend(d, s.client, s.log) + err := httpSend(d, s.client, s.log) + if err == nil { + s.reportSent(len(d)) + } + return len(d), err } func (s *httpSender) Close() error { return nil } @@ -268,17 +274,18 @@ func (s *mtsSender) Close() error { // rtmpSender implements loadSender for a native RTMP destination. type rtmpSender struct { - conn *rtmp.Conn - url string - timeout uint - retries int - log func(lvl int8, msg string, args ...interface{}) - ring *vring.Buffer - done chan struct{} - wg sync.WaitGroup + conn *rtmp.Conn + url string + timeout uint + retries int + log func(lvl int8, msg string, args ...interface{}) + ring *vring.Buffer + done chan struct{} + wg sync.WaitGroup + reportSent func(sent int) } -func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log func(lvl int8, msg string, args ...interface{})) (*rtmpSender, error) { +func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log func(lvl int8, msg string, args ...interface{}), reportSent func(sent int)) (*rtmpSender, error) { var conn *rtmp.Conn var err error for n := 0; n < retries; n++ { @@ -292,13 +299,14 @@ func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log } } s := &rtmpSender{ - conn: conn, - url: url, - timeout: timeout, - retries: retries, - log: log, - ring: rb, - done: make(chan struct{}), + conn: conn, + url: url, + timeout: timeout, + retries: retries, + log: log, + ring: rb, + done: make(chan struct{}), + reportSent: reportSent, } s.wg.Add(1) go s.output() @@ -364,6 +372,7 @@ func (s *rtmpSender) Write(d []byte) (int, error) { if err != nil { s.log(logger.Warning, pkg+"rtmpSender: ring buffer write error", "error", err.Error()) } + s.reportSent(len(d)) return len(d), nil } From cdd74c7a22625e59caf47b18510aa5d7f2c2e484 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 22 Jan 2020 15:26:14 +1030 Subject: [PATCH 02/22] revid/senders.go: reportSent -> report --- revid/senders.go | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/revid/senders.go b/revid/senders.go index 216b191b..6e74d519 100644 --- a/revid/senders.go +++ b/revid/senders.go @@ -59,17 +59,17 @@ const ( // httpSender provides an implemntation of io.Writer to perform sends to a http // destination. type httpSender struct { - client *netsender.Sender - log func(lvl int8, msg string, args ...interface{}) - reportSent func(sent int) + client *netsender.Sender + log func(lvl int8, msg string, args ...interface{}) + report func(sent int) } // newHttpSender returns a pointer to a new httpSender. -func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ...interface{}), reportSent func(sent int)) *httpSender { +func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ...interface{}), report func(sent int)) *httpSender { return &httpSender{ - client: ns, - log: log, - reportSent: reportSent, + client: ns, + log: log, + report: report, } } @@ -77,7 +77,7 @@ func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ... func (s *httpSender) Write(d []byte) (int, error) { err := httpSend(d, s.client, s.log) if err == nil { - s.reportSent(len(d)) + s.report(len(d)) } return len(d), err } @@ -274,18 +274,18 @@ func (s *mtsSender) Close() error { // rtmpSender implements loadSender for a native RTMP destination. type rtmpSender struct { - conn *rtmp.Conn - url string - timeout uint - retries int - log func(lvl int8, msg string, args ...interface{}) - ring *vring.Buffer - done chan struct{} - wg sync.WaitGroup - reportSent func(sent int) + conn *rtmp.Conn + url string + timeout uint + retries int + log func(lvl int8, msg string, args ...interface{}) + ring *vring.Buffer + done chan struct{} + wg sync.WaitGroup + report func(sent int) } -func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log func(lvl int8, msg string, args ...interface{}), reportSent func(sent int)) (*rtmpSender, error) { +func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log func(lvl int8, msg string, args ...interface{}), report func(sent int)) (*rtmpSender, error) { var conn *rtmp.Conn var err error for n := 0; n < retries; n++ { @@ -299,14 +299,14 @@ func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log } } s := &rtmpSender{ - conn: conn, - url: url, - timeout: timeout, - retries: retries, - log: log, - ring: rb, - done: make(chan struct{}), - reportSent: reportSent, + conn: conn, + url: url, + timeout: timeout, + retries: retries, + log: log, + ring: rb, + done: make(chan struct{}), + report: report, } s.wg.Add(1) go s.output() @@ -372,7 +372,7 @@ func (s *rtmpSender) Write(d []byte) (int, error) { if err != nil { s.log(logger.Warning, pkg+"rtmpSender: ring buffer write error", "error", err.Error()) } - s.reportSent(len(d)) + s.report(len(d)) return len(d), nil } From 1876fe9dea14bbd950f00608565517b9608df5ab Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 23 Jan 2020 10:07:28 +1030 Subject: [PATCH 03/22] Added bitrate reporting to RTP sender. --- revid/revid.go | 2 +- revid/senders.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/revid/revid.go b/revid/revid.go index 5cd0fbfc..1c95f05a 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -276,7 +276,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. ) mtsSenders = append(mtsSenders, w) case config.OutputRTP: - w, err := newRtpSender(r.cfg.RTPAddress, r.cfg.Logger.Log, r.cfg.FrameRate) + w, err := newRtpSender(r.cfg.RTPAddress, r.cfg.Logger.Log, r.cfg.FrameRate, r.bitrate.Report) if err != nil { r.cfg.Logger.Log(logger.Warning, pkg+"rtp connect error", "error", err.Error()) } diff --git a/revid/senders.go b/revid/senders.go index 6e74d519..4929bd40 100644 --- a/revid/senders.go +++ b/revid/senders.go @@ -413,9 +413,10 @@ type rtpSender struct { log func(lvl int8, msg string, args ...interface{}) encoder *rtp.Encoder data []byte + report func(sent int) } -func newRtpSender(addr string, log func(lvl int8, msg string, args ...interface{}), fps uint) (*rtpSender, error) { +func newRtpSender(addr string, log func(lvl int8, msg string, args ...interface{}), fps uint, report func(sent int)) (*rtpSender, error) { conn, err := net.Dial("udp", addr) if err != nil { return nil, err @@ -423,6 +424,7 @@ func newRtpSender(addr string, log func(lvl int8, msg string, args ...interface{ s := &rtpSender{ log: log, encoder: rtp.NewEncoder(conn, int(fps)), + report: report, } return s, nil } @@ -435,6 +437,7 @@ func (s *rtpSender) Write(d []byte) (int, error) { if err != nil { s.log(logger.Warning, pkg+"rtpSender: write error", err.Error()) } + s.report(len(d)) return len(d), nil } From 7419bdff7ad579a373b3983a9c7128ddd47d7ae1 Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 23 Jan 2020 14:28:21 +1030 Subject: [PATCH 04/22] Using utils v1.2.13 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2ed4c734..dfa6f093 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( bitbucket.org/ausocean/iot v1.2.13 - bitbucket.org/ausocean/utils v1.2.12 + bitbucket.org/ausocean/utils v1.2.13 github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7 github.com/go-audio/audio v0.0.0-20181013203223-7b2a6ca21480 github.com/go-audio/wav v0.0.0-20181013172942-de841e69b884 diff --git a/go.sum b/go.sum index ef1fb9ff..d74fe617 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ bitbucket.org/ausocean/utils v1.2.11 h1:zA0FOaPjN960ryp8PKCkV5y50uWBYrIxCVnXjwbv bitbucket.org/ausocean/utils v1.2.11/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8= bitbucket.org/ausocean/utils v1.2.12 h1:VnskjWTDM475TnQRhBQE0cNp9D6Y6OELrd4UkD2VVIQ= bitbucket.org/ausocean/utils v1.2.12/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8= +bitbucket.org/ausocean/utils v1.2.13 h1:tUaIywtoMc1+zl1GCVQokX4mL5X7LNHX5O51AgAPrWA= +bitbucket.org/ausocean/utils v1.2.13/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7 h1:LdOc9B9Bj6LEsKiXShkLA3/kpxXb6LJpH+ekU2krbzw= From 99b931f948f875cb1b61d95aab8dc4670c9fd2e8 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 24 Jan 2020 19:21:18 +1030 Subject: [PATCH 05/22] revid & cmd/revid-cli: added loop mode so that input may be restarted after completion Loop flag has been added to command line flags and in turn sets the Loop field that has been added to the config.Config struct. mode variable now also checked to see if value set to Loop, in which case revid config.Config.Loop = true. Revid.processFrom modified so that when input source has completed Revid.cfg.Loop is checked and input restarted if true. --- cmd/revid-cli/main.go | 3 +++ revid/config/config.go | 3 +++ revid/revid.go | 43 +++++++++++++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index bced0a4f..fc4d863f 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -122,6 +122,7 @@ func handleFlags() config.Config { httpAddressPtr = flag.String("HttpAddress", "", "Destination address of http posts") verticalFlipPtr = flag.Bool("VerticalFlip", false, "Flip video vertically: Yes, No") horizontalFlipPtr = flag.Bool("HorizontalFlip", false, "Flip video horizontally: Yes, No") + loopPtr = flag.Bool("Loop", false, "Loop video if EOF encountered: true, false") bitratePtr = flag.Uint("Bitrate", 0, "Bitrate of recorded video") heightPtr = flag.Uint("Height", 0, "Height in pixels") widthPtr = flag.Uint("Width", 0, "Width in pixels") @@ -179,6 +180,8 @@ func handleFlags() config.Config { } } + cfg.Loop = *loopPtr + switch *inputPtr { case "Raspivid": cfg.Input = config.InputRaspivid diff --git a/revid/config/config.go b/revid/config/config.go index 194faf33..47a8eaf9 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -297,6 +297,9 @@ type Config struct { MOGMinArea float64 // Used to ignore small areas of motion detection. MOGThreshold float64 // Intensity value from the KNN motion detection algorithm that is considered motion. MOGHistory uint // Length of MOG filter's history + + // If true will restart reading of input after an io.EOF. + Loop bool } // TypeData contains information about all of the variables that diff --git a/revid/revid.go b/revid/revid.go index 8b1b42da..9c414480 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -428,13 +428,8 @@ func (r *Revid) Start() error { return err } - err = r.input.Start() - if err != nil { - return fmt.Errorf("could not start input device: %w", err) - } - r.wg.Add(1) - go r.processFrom(r.input, 0) + go r.processFrom(r.input, (1000/25)*time.Millisecond) r.running = true return nil @@ -845,6 +840,11 @@ func (r *Revid) Update(vars map[string]string) error { break } r.cfg.MOGHistory = uint(v) + case "mode": + r.cfg.Loop = false + if value == "Loop" { + r.cfg.Loop = true + } } } r.cfg.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.cfg)) @@ -853,14 +853,35 @@ func (r *Revid) Update(vars map[string]string) error { // processFrom is run as a routine to read from a input data source, lex and // then send individual access units to revid's encoders. -func (r *Revid) processFrom(read io.Reader, delay time.Duration) { - err := r.lexTo(r.filters[0], read, delay) - r.cfg.Logger.Log(logger.Debug, pkg+"finished lexing") +func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) { +restart: + err := in.Start() + if err != nil { + r.err <- fmt.Errorf("could not start input device: %w", err) + r.wg.Done() + return + } + + // Lex data from input device, in, until finished or an error is encountered. + // For a continuous source e.g. a camera or microphone, we should remain + // in this call indefinitely unless in.Stop() is called and an io.EOF is forced. + err = r.lexTo(r.filters[0], in, delay) switch err { - case nil: // Do nothing. - case io.EOF: // TODO: handle this depending on loop mode. + case nil, io.EOF, io.ErrUnexpectedEOF: default: r.err <- err } + + err = in.Stop() + if err != nil { + r.err <- fmt.Errorf("could not stop input source: %w", err) + } + + if r.cfg.Loop { + r.cfg.Logger.Log(logger.Info, pkg+"looping input") + goto restart + } + + r.cfg.Logger.Log(logger.Info, pkg+"finished lexing") r.wg.Done() } From 179f9cfa034aca07c48fa1bfd2ecdc185276b890 Mon Sep 17 00:00:00 2001 From: Trek H Date: Fri, 24 Jan 2020 19:41:43 +1030 Subject: [PATCH 06/22] mjpeg-player: reduced hlsjs code Reduced the lengthy lists of config vars and events used by hlsjs player that we no longer need. Also removed typescript typing from config.js --- cmd/mjpeg-player/hlsjs/config.js | 215 ++++--------------------------- cmd/mjpeg-player/hlsjs/events.js | 103 ++++----------- 2 files changed, 50 insertions(+), 268 deletions(-) diff --git a/cmd/mjpeg-player/hlsjs/config.js b/cmd/mjpeg-player/hlsjs/config.js index efc8e27c..ed548ff9 100644 --- a/cmd/mjpeg-player/hlsjs/config.js +++ b/cmd/mjpeg-player/hlsjs/config.js @@ -1,170 +1,32 @@ -/** - * HLS config - */ +/* +AUTHOR + Trek Hopton -import AbrController from './controller/abr-controller'; -import BufferController from './controller/buffer-controller'; -import CapLevelController from './controller/cap-level-controller'; -import FPSController from './controller/fps-controller'; -import XhrLoader from './utils/xhr-loader'; -// import FetchLoader from './utils/fetch-loader'; +LICENSE + This file is Copyright (C) 2020 the Australian Ocean Lab (AusOcean) -import AudioTrackController from './controller/audio-track-controller'; -import AudioStreamController from './controller/audio-stream-controller'; + It is free software: you can redistribute it and/or modify them + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. -import * as Cues from './utils/cues'; -import TimelineController from './controller/timeline-controller'; -import SubtitleTrackController from './controller/subtitle-track-controller'; -import { SubtitleStreamController } from './controller/subtitle-stream-controller'; -import EMEController from './controller/eme-controller'; -import { requestMediaKeySystemAccess, MediaKeyFunc } from './utils/mediakeys-helper'; + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. -type ABRControllerConfig = { - abrEwmaFastLive: number, - abrEwmaSlowLive: number, - abrEwmaFastVoD: number, - abrEwmaSlowVoD: number, - abrEwmaDefaultEstimate: number, - abrBandWidthFactor: number, - abrBandWidthUpFactor: number, - abrMaxWithRealBitrate: boolean, - maxStarvationDelay: number, - maxLoadingDelay: number, -}; + You should have received a copy of the GNU General Public License in gpl.txt. + If not, see http://www.gnu.org/licenses. -export type BufferControllerConfig = { - appendErrorMaxRetry: number, - liveDurationInfinity: boolean, - liveBackBufferLength: number, -}; + For hls.js Copyright notice and license, see LICENSE file. +*/ -type CapLevelControllerConfig = { - capLevelToPlayerSize: boolean -}; - -export type EMEControllerConfig = { - licenseXhrSetup?: (xhr: XMLHttpRequest, url: string) => void, - emeEnabled: boolean, - widevineLicenseUrl?: string, - requestMediaKeySystemAccessFunc: MediaKeyFunc | null, -}; - -type FragmentLoaderConfig = { - fLoader: any, // TODO(typescript-loader): Once Loader is typed fill this in - - fragLoadingTimeOut: number, - fragLoadingMaxRetry: number, - fragLoadingRetryDelay: number, - fragLoadingMaxRetryTimeout: number, -}; - -type FPSControllerConfig = { - capLevelOnFPSDrop: boolean, - fpsDroppedMonitoringPeriod: number, - fpsDroppedMonitoringThreshold: number, -}; - -type LevelControllerConfig = { - startLevel?: number -}; - -type MP4RemuxerConfig = { - stretchShortVideoTrack: boolean, - maxAudioFramesDrift: number, -}; - -type PlaylistLoaderConfig = { - pLoader: any, // TODO(typescript-loader): Once Loader is typed fill this in - - manifestLoadingTimeOut: number, - manifestLoadingMaxRetry: number, - manifestLoadingRetryDelay: number, - manifestLoadingMaxRetryTimeout: number, - - levelLoadingTimeOut: number, - levelLoadingMaxRetry: number, - levelLoadingRetryDelay: number, - levelLoadingMaxRetryTimeout: number -}; - -type StreamControllerConfig = { - autoStartLoad: boolean, - startPosition: number, - defaultAudioCodec?: string, - initialLiveManifestSize: number, - maxBufferLength: number, - maxBufferSize: number, - maxBufferHole: number, - - lowBufferWatchdogPeriod: number, - highBufferWatchdogPeriod: number, - nudgeOffset: number, - nudgeMaxRetry: number, - maxFragLookUpTolerance: number, - liveSyncDurationCount: number, - liveMaxLatencyDurationCount: number, - liveSyncDuration?: number, - liveMaxLatencyDuration?: number, - maxMaxBufferLength: number, - - startFragPrefetch: boolean, -}; - -type TimelineControllerConfig = { - cueHandler: any, // TODO(typescript-cues): Type once file is done - enableCEA708Captions: boolean, - enableWebVTT: boolean, - captionsTextTrack1Label: string, - captionsTextTrack1LanguageCode: string, - captionsTextTrack2Label: string, - captionsTextTrack2LanguageCode: string, -}; - -type TSDemuxerConfig = { - forceKeyFrameOnDiscontinuity: boolean, -}; - -export type HlsConfig = - { - debug: boolean, - enableWorker: boolean, - enableSoftwareAES: boolean, - minAutoBitrate: number, - loader: any, // TODO(typescript-xhrloader): Type once XHR is done - xhrSetup?: (xhr: XMLHttpRequest, url: string) => void, - - // Alt Audio - audioStreamController?: any, // TODO(typescript-audiostreamcontroller): Type once file is done - audioTrackController?: any, // TODO(typescript-audiotrackcontroller): Type once file is done - // Subtitle - subtitleStreamController?: any, // TODO(typescript-subtitlestreamcontroller): Type once file is done - subtitleTrackController?: any, // TODO(typescript-subtitletrackcontroller): Type once file is done - timelineController?: any, // TODO(typescript-timelinecontroller): Type once file is done - // EME - emeController?: typeof EMEController, - - abrController: any, // TODO(typescript-abrcontroller): Type once file is done - bufferController: typeof BufferController, - capLevelController: any, // TODO(typescript-caplevelcontroller): Type once file is done - fpsController: any, // TODO(typescript-fpscontroller): Type once file is done - } & - ABRControllerConfig & - BufferControllerConfig & - CapLevelControllerConfig & - EMEControllerConfig & - FPSControllerConfig & - FragmentLoaderConfig & - LevelControllerConfig & - MP4RemuxerConfig & - PlaylistLoaderConfig & - StreamControllerConfig & - Partial & - TSDemuxerConfig; +import XhrLoader from './utils/xhr-loader.js'; // If possible, keep hlsDefaultConfig shallow // It is cloned whenever a new Hls instance is created, by keeping the config // shallow the properties are cloned, and we don't end up manipulating the default -export const hlsDefaultConfig: HlsConfig = { +export const hlsDefaultConfig = { autoStartLoad: true, // used by stream-controller startPosition: -1, // used by stream-controller defaultAudioCodec: void 0, // used by stream-controller @@ -213,11 +75,11 @@ export const hlsDefaultConfig: HlsConfig = { pLoader: void 0, // used by playlist-loader xhrSetup: void 0, // used by xhr-loader licenseXhrSetup: void 0, // used by eme-controller - // fetchSetup: void 0, - abrController: AbrController, - bufferController: BufferController, - capLevelController: CapLevelController, - fpsController: FPSController, + fetchSetup: void 0, + // abrController: AbrController, + // bufferController: BufferController, + // capLevelController: CapLevelController, + // fpsController: FPSController, stretchShortVideoTrack: false, // used by mp4-remuxer maxAudioFramesDrift: 1, // used by mp4-remuxer forceKeyFrameOnDiscontinuity: true, // used by ts-demuxer @@ -234,31 +96,6 @@ export const hlsDefaultConfig: HlsConfig = { minAutoBitrate: 0, // used by hls emeEnabled: false, // used by eme-controller widevineLicenseUrl: void 0, // used by eme-controller - requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess, // used by eme-controller + // requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess, // used by eme-controller - // Dynamic Modules - ...timelineConfig(), - subtitleStreamController: (__USE_SUBTITLES__) ? SubtitleStreamController : void 0, - subtitleTrackController: (__USE_SUBTITLES__) ? SubtitleTrackController : void 0, - timelineController: (__USE_SUBTITLES__) ? TimelineController : void 0, - audioStreamController: (__USE_ALT_AUDIO__) ? AudioStreamController : void 0, - audioTrackController: (__USE_ALT_AUDIO__) ? AudioTrackController : void 0, - emeController: (__USE_EME_DRM__) ? EMEController : void 0 -}; - -function timelineConfig (): TimelineControllerConfig { - if (!__USE_SUBTITLES__) { - // intentionally doing this over returning Partial above - // this has the added nice property of still requiring the object below to completely define all props. - return {} as any; - } - return { - cueHandler: Cues, // used by timeline-controller - enableCEA708Captions: true, // used by timeline-controller - enableWebVTT: true, // used by timeline-controller - captionsTextTrack1Label: 'English', // used by timeline-controller - captionsTextTrack1LanguageCode: 'en', // used by timeline-controller - captionsTextTrack2Label: 'Spanish', // used by timeline-controller - captionsTextTrack2LanguageCode: 'es' // used by timeline-controller - }; -} +}; \ No newline at end of file diff --git a/cmd/mjpeg-player/hlsjs/events.js b/cmd/mjpeg-player/hlsjs/events.js index 82314117..e71d71c5 100644 --- a/cmd/mjpeg-player/hlsjs/events.js +++ b/cmd/mjpeg-player/hlsjs/events.js @@ -1,110 +1,55 @@ +/* +AUTHOR + Trek Hopton + +LICENSE + This file is Copyright (C) 2020 the Australian Ocean Lab (AusOcean) + + It is free software: you can redistribute it and/or modify them + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License in gpl.txt. + If not, see http://www.gnu.org/licenses. + + For hls.js Copyright notice and license, see LICENSE file. +*/ + /** * @readonly * @enum {string} */ const HlsEvents = { - // fired before MediaSource is attaching to media element - data: { media } - MEDIA_ATTACHING: 'hlsMediaAttaching', - // fired when MediaSource has been succesfully attached to media element - data: { } - MEDIA_ATTACHED: 'hlsMediaAttached', - // fired before detaching MediaSource from media element - data: { } - MEDIA_DETACHING: 'hlsMediaDetaching', - // fired when MediaSource has been detached from media element - data: { } - MEDIA_DETACHED: 'hlsMediaDetached', - // fired when we buffer is going to be reset - data: { } - BUFFER_RESET: 'hlsBufferReset', - // fired when we know about the codecs that we need buffers for to push into - data: {tracks : { container, codec, levelCodec, initSegment, metadata }} - BUFFER_CODECS: 'hlsBufferCodecs', - // fired when sourcebuffers have been created - data: { tracks : tracks } - BUFFER_CREATED: 'hlsBufferCreated', - // fired when we append a segment to the buffer - data: { segment: segment object } - BUFFER_APPENDING: 'hlsBufferAppending', - // fired when we are done with appending a media segment to the buffer - data : { parent : segment parent that triggered BUFFER_APPENDING, pending : nb of segments waiting for appending for this segment parent} - BUFFER_APPENDED: 'hlsBufferAppended', - // fired when the stream is finished and we want to notify the media buffer that there will be no more data - data: { } - BUFFER_EOS: 'hlsBufferEos', - // fired when the media buffer should be flushed - data { startOffset, endOffset } - BUFFER_FLUSHING: 'hlsBufferFlushing', - // fired when the media buffer has been flushed - data: { } - BUFFER_FLUSHED: 'hlsBufferFlushed', // fired to signal that a manifest loading starts - data: { url : manifestURL} MANIFEST_LOADING: 'hlsManifestLoading', // fired after manifest has been loaded - data: { levels : [available quality levels], audioTracks : [ available audio tracks], url : manifestURL, stats : { trequest, tfirst, tload, mtime}} MANIFEST_LOADED: 'hlsManifestLoaded', - // fired after manifest has been parsed - data: { levels : [available quality levels], firstLevel : index of first quality level appearing in Manifest} - MANIFEST_PARSED: 'hlsManifestParsed', - // fired when a level switch is requested - data: { level : id of new level } - LEVEL_SWITCHING: 'hlsLevelSwitching', - // fired when a level switch is effective - data: { level : id of new level } - LEVEL_SWITCHED: 'hlsLevelSwitched', // fired when a level playlist loading starts - data: { url : level URL, level : id of level being loaded} LEVEL_LOADING: 'hlsLevelLoading', // fired when a level playlist loading finishes - data: { details : levelDetails object, level : id of loaded level, stats : { trequest, tfirst, tload, mtime} } LEVEL_LOADED: 'hlsLevelLoaded', // fired when a level's details have been updated based on previous details, after it has been loaded - data: { details : levelDetails object, level : id of updated level } LEVEL_UPDATED: 'hlsLevelUpdated', - // fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment } - LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated', - // fired to notify that audio track lists has been updated - data: { audioTracks : audioTracks } - AUDIO_TRACKS_UPDATED: 'hlsAudioTracksUpdated', - // fired when an audio track switching is requested - data: { id : audio track id } - AUDIO_TRACK_SWITCHING: 'hlsAudioTrackSwitching', - // fired when an audio track switch actually occurs - data: { id : audio track id } - AUDIO_TRACK_SWITCHED: 'hlsAudioTrackSwitched', // fired when an audio track loading starts - data: { url : audio track URL, id : audio track id } AUDIO_TRACK_LOADING: 'hlsAudioTrackLoading', // fired when an audio track loading finishes - data: { details : levelDetails object, id : audio track id, stats : { trequest, tfirst, tload, mtime } } AUDIO_TRACK_LOADED: 'hlsAudioTrackLoaded', - // fired to notify that subtitle track lists has been updated - data: { subtitleTracks : subtitleTracks } - SUBTITLE_TRACKS_UPDATED: 'hlsSubtitleTracksUpdated', - // fired when an subtitle track switch occurs - data: { id : subtitle track id } - SUBTITLE_TRACK_SWITCH: 'hlsSubtitleTrackSwitch', // fired when a subtitle track loading starts - data: { url : subtitle track URL, id : subtitle track id } SUBTITLE_TRACK_LOADING: 'hlsSubtitleTrackLoading', // fired when a subtitle track loading finishes - data: { details : levelDetails object, id : subtitle track id, stats : { trequest, tfirst, tload, mtime } } SUBTITLE_TRACK_LOADED: 'hlsSubtitleTrackLoaded', - // fired when a subtitle fragment has been processed - data: { success : boolean, frag : the processed frag } - SUBTITLE_FRAG_PROCESSED: 'hlsSubtitleFragProcessed', - // fired when the first timestamp is found - data: { id : demuxer id, initPTS: initPTS, frag : fragment object } - INIT_PTS_FOUND: 'hlsInitPtsFound', // fired when a fragment loading starts - data: { frag : fragment object } FRAG_LOADING: 'hlsFragLoading', // fired when a fragment loading is progressing - data: { frag : fragment object, { trequest, tfirst, loaded } } FRAG_LOAD_PROGRESS: 'hlsFragLoadProgress', - // Identifier for fragment load aborting for emergency switch down - data: { frag : fragment object } - FRAG_LOAD_EMERGENCY_ABORTED: 'hlsFragLoadEmergencyAborted', // fired when a fragment loading is completed - data: { frag : fragment object, payload : fragment payload, stats : { trequest, tfirst, tload, length } } - FRAG_LOADED: 'hlsFragLoaded', - // fired when a fragment has finished decrypting - data: { id : demuxer id, frag: fragment object, payload : fragment payload, stats : { tstart, tdecrypt } } - FRAG_DECRYPTED: 'hlsFragDecrypted', - // fired when Init Segment has been extracted from fragment - data: { id : demuxer id, frag: fragment object, moov : moov MP4 box, codecs : codecs found while parsing fragment } - FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment', - // fired when parsing sei text is completed - data: { id : demuxer id, frag: fragment object, samples : [ sei samples pes ] } - FRAG_PARSING_USERDATA: 'hlsFragParsingUserdata', - // fired when parsing id3 is completed - data: { id : demuxer id, frag: fragment object, samples : [ id3 samples pes ] } - FRAG_PARSING_METADATA: 'hlsFragParsingMetadata', - // fired when data have been extracted from fragment - data: { id : demuxer id, frag: fragment object, data1 : moof MP4 box or TS fragments, data2 : mdat MP4 box or null} - FRAG_PARSING_DATA: 'hlsFragParsingData', - // fired when fragment parsing is completed - data: { id : demuxer id, frag: fragment object } - FRAG_PARSED: 'hlsFragParsed', - // fired when fragment remuxed MP4 boxes have all been appended into SourceBuffer - data: { id : demuxer id, frag : fragment object, stats : { trequest, tfirst, tload, tparsed, tbuffered, length, bwEstimate } } - FRAG_BUFFERED: 'hlsFragBuffered', - // fired when fragment matching with current media position is changing - data : { id : demuxer id, frag : fragment object } - FRAG_CHANGED: 'hlsFragChanged', - // Identifier for a FPS drop event - data: { curentDropped, currentDecoded, totalDroppedFrames } - FPS_DROP: 'hlsFpsDrop', - // triggered when FPS drop triggers auto level capping - data: { level, droppedlevel } - FPS_DROP_LEVEL_CAPPING: 'hlsFpsDropLevelCapping', - // Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data } - ERROR: 'hlsError', - // fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example - data: { } - DESTROYING: 'hlsDestroying', - // fired when a decrypt key loading starts - data: { frag : fragment object } - KEY_LOADING: 'hlsKeyLoading', - // fired when a decrypt key loading is completed - data: { frag : fragment object, payload : key payload, stats : { trequest, tfirst, tload, length } } - KEY_LOADED: 'hlsKeyLoaded', - // fired upon stream controller state transitions - data: { previousState, nextState } - STREAM_STATE_TRANSITION: 'hlsStreamStateTransition' + FRAG_LOADED: 'hlsFragLoaded' }; export default HlsEvents; From 0f5aaf6cb5afac81fbb1d1b871d4d08313db3681 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 24 Jan 2020 20:05:43 +1030 Subject: [PATCH 07/22] revid & cmd/revid-cli: added InputFPS config.Config field The InputFPS field can control rate at which we lex frames from the input source. This has not been a useful feature until now; we now want to simulate realtime input device using file input. This requires firstly the Loop mode, and now also realistic input rate. --- cmd/revid-cli/main.go | 5 +++-- revid/config/config.go | 14 +++++++++++++- revid/revid.go | 5 ++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index fc4d863f..d0b32e9f 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -133,6 +133,7 @@ func handleFlags() config.Config { saturationPtr = flag.Int("Saturation", 0, "Set Saturation. (100-100)") exposurePtr = flag.String("Exposure", "auto", "Set exposure mode. ("+strings.Join(raspivid.ExposureModes[:], ",")+")") autoWhiteBalancePtr = flag.String("Awb", "auto", "Set automatic white balance mode. ("+strings.Join(raspivid.AutoWhiteBalanceModes[:], ",")+")") + inputFPSPtr = flag.Int("InputFPS", 0, "Input source processing FPS") // Audio specific flags. sampleRatePtr = flag.Int("SampleRate", 48000, "Sample rate of recorded audio") @@ -180,8 +181,6 @@ func handleFlags() config.Config { } } - cfg.Loop = *loopPtr - switch *inputPtr { case "Raspivid": cfg.Input = config.InputRaspivid @@ -238,6 +237,8 @@ func handleFlags() config.Config { netsender.ConfigFile = *configFilePtr } + cfg.InputFPS = *inputFPSPtr + cfg.Loop = *loopPtr cfg.CameraIP = *cameraIPPtr cfg.Rotation = *rotationPtr cfg.HorizontalFlip = *horizontalFlipPtr diff --git a/revid/config/config.go b/revid/config/config.go index 47a8eaf9..8ee31ee5 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -86,6 +86,7 @@ const ( defaultAudioInputCodec = codecutil.ADPCM defaultPSITime = 2 defaultMotionInterval = 5 + defaultInputFPS = 0 // Ring buffer defaults. defaultRBMaxElements = 10000 @@ -300,6 +301,10 @@ type Config struct { // If true will restart reading of input after an io.EOF. Loop bool + + // Defines the rate at which an input source is processed. If reading + // from a realtime source, InputFPS is not necessary and should be 0 (default). + InputFPS int } // TypeData contains information about all of the variables that @@ -321,15 +326,17 @@ var TypeData = map[string]string{ "HTTPAddress": "string", "Input": "enum:raspivid,rtsp,v4l,file", "InputCodec": "enum:H264,MJPEG", + "InputFPS": "int", "InputPath": "string", "KNNHistory": "uint", "KNNKernel": "float", "KNNMinArea": "float", "KNNThreshold": "float", "logging": "enum:Debug,Info,Warning,Error,Fatal", + "Loop": "bool", "MinFPS": "float", "MinFrames": "uint", - "mode": "enum:Normal,Paused,Burst", + "mode": "enum:Normal,Paused,Burst,Loop", "MOGHistory": "uint", "MOGMinArea": "float", "MOGThreshold": "float", @@ -524,6 +531,11 @@ func (c *Config) Validate() error { } } + if c.InputFPS <= 0 { + c.Logger.Log(logger.Info, pkg+"InputFPS bad or unset, defaulting", "InputFPS", defaultInputFPS) + c.InputFPS = defaultInputFPS + } + return nil } diff --git a/revid/revid.go b/revid/revid.go index 9c414480..b442e34a 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -428,8 +428,11 @@ func (r *Revid) Start() error { return err } + // Calculate delay between frames based on InputFPS. + d := time.Duration(1000/r.cfg.InputFPS) * time.Millisecond + r.wg.Add(1) - go r.processFrom(r.input, (1000/25)*time.Millisecond) + go r.processFrom(r.input, d) r.running = true return nil From 4e7e5ebca3cd5fa95f448dbf3f3baf7cb7788639 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 24 Jan 2020 20:15:40 +1030 Subject: [PATCH 08/22] revid/revid.go: cleaned up prcoessFrom (added deger for waitgroup.Done and added info log) --- revid/revid.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/revid/revid.go b/revid/revid.go index b442e34a..7aca384e 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -857,17 +857,19 @@ func (r *Revid) Update(vars map[string]string) error { // processFrom is run as a routine to read from a input data source, lex and // then send individual access units to revid's encoders. func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) { + defer r.wg.Done() + restart: err := in.Start() if err != nil { r.err <- fmt.Errorf("could not start input device: %w", err) - r.wg.Done() return } // Lex data from input device, in, until finished or an error is encountered. // For a continuous source e.g. a camera or microphone, we should remain // in this call indefinitely unless in.Stop() is called and an io.EOF is forced. + r.cfg.Logger.Log(logger.Info, pkg+"lexing") err = r.lexTo(r.filters[0], in, delay) switch err { case nil, io.EOF, io.ErrUnexpectedEOF: @@ -886,5 +888,4 @@ restart: } r.cfg.Logger.Log(logger.Info, pkg+"finished lexing") - r.wg.Done() } From 0e14c0a056966b82a269d0124b3914cf7e666570 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 24 Jan 2020 20:24:23 +1030 Subject: [PATCH 09/22] cmd/revid-cli: improved commentfor Loop flag description --- cmd/revid-cli/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index d0b32e9f..3d03916b 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -122,7 +122,7 @@ func handleFlags() config.Config { httpAddressPtr = flag.String("HttpAddress", "", "Destination address of http posts") verticalFlipPtr = flag.Bool("VerticalFlip", false, "Flip video vertically: Yes, No") horizontalFlipPtr = flag.Bool("HorizontalFlip", false, "Flip video horizontally: Yes, No") - loopPtr = flag.Bool("Loop", false, "Loop video if EOF encountered: true, false") + loopPtr = flag.Bool("Loop", false, "Loop input source on completion (true/false)") bitratePtr = flag.Uint("Bitrate", 0, "Bitrate of recorded video") heightPtr = flag.Uint("Height", 0, "Height in pixels") widthPtr = flag.Uint("Width", 0, "Width in pixels") From 64754f7e0f33a6ae37000ed732a4f70d9a2f2771 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 24 Jan 2020 21:25:27 +1030 Subject: [PATCH 10/22] revid: use loop in processFrom instead of goto --- revid/revid.go | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/revid/revid.go b/revid/revid.go index 7aca384e..3d9d26c5 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -859,32 +859,28 @@ func (r *Revid) Update(vars map[string]string) error { func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) { defer r.wg.Done() -restart: - err := in.Start() - if err != nil { - r.err <- fmt.Errorf("could not start input device: %w", err) - return - } + for l := true; l; l = r.cfg.Loop { + err := in.Start() + if err != nil { + r.err <- fmt.Errorf("could not start input device: %w", err) + return + } - // Lex data from input device, in, until finished or an error is encountered. - // For a continuous source e.g. a camera or microphone, we should remain - // in this call indefinitely unless in.Stop() is called and an io.EOF is forced. - r.cfg.Logger.Log(logger.Info, pkg+"lexing") - err = r.lexTo(r.filters[0], in, delay) - switch err { - case nil, io.EOF, io.ErrUnexpectedEOF: - default: - r.err <- err - } + // Lex data from input device, in, until finished or an error is encountered. + // For a continuous source e.g. a camera or microphone, we should remain + // in this call indefinitely unless in.Stop() is called and an io.EOF is forced. + r.cfg.Logger.Log(logger.Info, pkg+"lexing") + err = r.lexTo(r.filters[0], in, delay) + switch err { + case nil, io.EOF, io.ErrUnexpectedEOF: + default: + r.err <- err + } - err = in.Stop() - if err != nil { - r.err <- fmt.Errorf("could not stop input source: %w", err) - } - - if r.cfg.Loop { - r.cfg.Logger.Log(logger.Info, pkg+"looping input") - goto restart + err = in.Stop() + if err != nil { + r.err <- fmt.Errorf("could not stop input source: %w", err) + } } r.cfg.Logger.Log(logger.Info, pkg+"finished lexing") From f82ab422463dcc7db3fccc335011bc0b0754212c Mon Sep 17 00:00:00 2001 From: Saxon Date: Sat, 25 Jan 2020 09:39:42 +1030 Subject: [PATCH 11/22] revid & cmd/revid-cli: InputFPS field now FileFPS and added check so that only used with File input --- cmd/revid-cli/main.go | 2 +- revid/config/config.go | 15 +++++++-------- revid/revid.go | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index 3d03916b..5db8e9a1 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -133,7 +133,7 @@ func handleFlags() config.Config { saturationPtr = flag.Int("Saturation", 0, "Set Saturation. (100-100)") exposurePtr = flag.String("Exposure", "auto", "Set exposure mode. ("+strings.Join(raspivid.ExposureModes[:], ",")+")") autoWhiteBalancePtr = flag.String("Awb", "auto", "Set automatic white balance mode. ("+strings.Join(raspivid.AutoWhiteBalanceModes[:], ",")+")") - inputFPSPtr = flag.Int("InputFPS", 0, "Input source processing FPS") + fileFPSPtr = flag.Int("FileFPS", 0, "File source frame processing FPS") // Audio specific flags. sampleRatePtr = flag.Int("SampleRate", 48000, "Sample rate of recorded audio") diff --git a/revid/config/config.go b/revid/config/config.go index 8ee31ee5..b70a01b3 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -86,7 +86,7 @@ const ( defaultAudioInputCodec = codecutil.ADPCM defaultPSITime = 2 defaultMotionInterval = 5 - defaultInputFPS = 0 + defaultFileFPS = 0 // Ring buffer defaults. defaultRBMaxElements = 10000 @@ -302,9 +302,8 @@ type Config struct { // If true will restart reading of input after an io.EOF. Loop bool - // Defines the rate at which an input source is processed. If reading - // from a realtime source, InputFPS is not necessary and should be 0 (default). - InputFPS int + // Defines the rate at which frames from a file source are processed. + FileFPS int } // TypeData contains information about all of the variables that @@ -319,6 +318,7 @@ var TypeData = map[string]string{ "CBR": "bool", "ClipDuration": "uint", "Exposure": "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks", + "FileFPS": "int", "Filters": "enums:NoOp,MOG,VariableFPS,KNN", "FrameRate": "uint", "Height": "uint", @@ -326,7 +326,6 @@ var TypeData = map[string]string{ "HTTPAddress": "string", "Input": "enum:raspivid,rtsp,v4l,file", "InputCodec": "enum:H264,MJPEG", - "InputFPS": "int", "InputPath": "string", "KNNHistory": "uint", "KNNKernel": "float", @@ -531,9 +530,9 @@ func (c *Config) Validate() error { } } - if c.InputFPS <= 0 { - c.Logger.Log(logger.Info, pkg+"InputFPS bad or unset, defaulting", "InputFPS", defaultInputFPS) - c.InputFPS = defaultInputFPS + if c.FileFPS <= 0 || (c.FileFPS > 0 && c.Input != InputFile) { + c.Logger.Log(logger.Info, pkg+"FileFPS bad or unset, defaulting", "FileFPS", defaultFileFPS) + c.FileFPS = defaultFileFPS } return nil diff --git a/revid/revid.go b/revid/revid.go index 3d9d26c5..5d8c81d0 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -429,7 +429,7 @@ func (r *Revid) Start() error { } // Calculate delay between frames based on InputFPS. - d := time.Duration(1000/r.cfg.InputFPS) * time.Millisecond + d := time.Duration(1000/r.cfg.FileFPS) * time.Millisecond r.wg.Add(1) go r.processFrom(r.input, d) From a0a99e17dbf62ca7534b869475fdddf14f0af1c5 Mon Sep 17 00:00:00 2001 From: Saxon Date: Sat, 25 Jan 2020 09:42:32 +1030 Subject: [PATCH 12/22] revid/revid.go: logging unexpected EOF from input source --- revid/revid.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/revid/revid.go b/revid/revid.go index 5d8c81d0..aa94daf0 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -872,7 +872,9 @@ func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) { r.cfg.Logger.Log(logger.Info, pkg+"lexing") err = r.lexTo(r.filters[0], in, delay) switch err { - case nil, io.EOF, io.ErrUnexpectedEOF: + case nil, io.EOF: + case io.ErrUnexpectedEOF: + r.cfg.Logger.Log(logger.Info, pkg+"unexpected EOF from input") default: r.err <- err } From dcafcbf69ebc83b500eb4a6edcb649b849188744 Mon Sep 17 00:00:00 2001 From: Saxon Date: Sat, 25 Jan 2020 09:53:21 +1030 Subject: [PATCH 13/22] cmd/revid-cli: fixed build error --- cmd/revid-cli/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/revid-cli/main.go b/cmd/revid-cli/main.go index 5db8e9a1..abc049ed 100644 --- a/cmd/revid-cli/main.go +++ b/cmd/revid-cli/main.go @@ -237,7 +237,7 @@ func handleFlags() config.Config { netsender.ConfigFile = *configFilePtr } - cfg.InputFPS = *inputFPSPtr + cfg.FileFPS = *fileFPSPtr cfg.Loop = *loopPtr cfg.CameraIP = *cameraIPPtr cfg.Rotation = *rotationPtr From cfd3f0fc3c62d961ac906fe81f789717dd1e8a68 Mon Sep 17 00:00:00 2001 From: Saxon Date: Sat, 25 Jan 2020 10:15:27 +1030 Subject: [PATCH 14/22] revid: consider when r.cfg.FileFPS ==0 --- revid/revid.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/revid/revid.go b/revid/revid.go index aa94daf0..94bd4a6f 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -428,8 +428,11 @@ func (r *Revid) Start() error { return err } - // Calculate delay between frames based on InputFPS. - d := time.Duration(1000/r.cfg.FileFPS) * time.Millisecond + // Calculate delay between frames based on FileFPS. + d := time.Duration(0) + if r.cfg.FileFPS != 0 { + d = time.Duration(1000/r.cfg.FileFPS) * time.Millisecond + } r.wg.Add(1) go r.processFrom(r.input, d) From ced8727c070b2077366ab4329e2e639a6923098a Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 22 Jan 2020 12:06:14 +1030 Subject: [PATCH 15/22] filter: create a simple difference motion filter using gocv --- filter/difference.go | 114 +++++++++++++++++++++++++++++++++++++++++ revid/config/config.go | 12 +++-- revid/revid.go | 11 +++- 3 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 filter/difference.go diff --git a/filter/difference.go b/filter/difference.go new file mode 100644 index 00000000..97df94b9 --- /dev/null +++ b/filter/difference.go @@ -0,0 +1,114 @@ +// +build !circleci + +/* +DESCRIPTION + A filter that detects motion and discards frames without motion. The + algorithm calculates the absolute difference for each pixel between + two frames, then finds the mean. If the mean is above a given threshold, + then it is considered motion. + +AUTHORS + Scott Barnard + +LICENSE + difference.go is Copyright (C) 2020 the Australian Ocean Lab (AusOcean) + + It is free software: you can redistribute it and/or modify them + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + in gpl.txt. If not, see http://www.gnu.org/licenses. +*/ + +package filter + +import ( + "fmt" + "image" + "image/color" + "io" + + "gocv.io/x/gocv" +) + +// DiffFilter is a filter that provides basic motion detection. DiffFilter calculates +// the absolute difference for each pixel between two frames, then finds the mean. If +// the mean is above a given threshold, then it is considered motion. +type DiffFilter struct { + dst io.WriteCloser + thresh float64 + prev gocv.Mat + debug bool + windows []*gocv.Window +} + +// NewDiffFilter returns a pointer to a new DiffFilter. +func NewDiffFilter(dst io.WriteCloser, debug bool, threshold float64) *DiffFilter { + var windows []*gocv.Window + if debug { + windows = []*gocv.Window{gocv.NewWindow("Diff: Bounding boxes"), gocv.NewWindow("Diff: Motion")} + } + return &DiffFilter{dst, threshold, gocv.NewMat(), debug, windows} +} + +// Implements io.Closer. +// Close frees resources used by gocv, because it has to be done manually, due to +// it using c-go. +func (d *DiffFilter) Close() error { + d.prev.Close() + for _, window := range d.windows { + window.Close() + } + return nil +} + +// Implements io.Writer. +// Write applies the motion filter to the video stream. Only frames with motion +// are written to the destination encoder, frames without are discarded. +func (d *DiffFilter) Write(f []byte) (int, error) { + if d.prev.Empty() { + d.prev, _ = gocv.IMDecode(f, gocv.IMReadColor) + return 0, nil + } + + img, _ := gocv.IMDecode(f, gocv.IMReadColor) + defer img.Close() + + imgDelta := gocv.NewMat() + defer imgDelta.Close() + + // Seperate foreground and background. + gocv.AbsDiff(img, d.prev, &imgDelta) + gocv.CvtColor(imgDelta, &imgDelta, gocv.ColorBGRToGray) + + mean := imgDelta.Mean().Val1 + + // Update History + d.prev = img.Clone() + + // Draw debug information. + if d.debug { + if mean >= d.thresh { + gocv.PutText(&img, fmt.Sprintf("motion - mean:%f", mean), image.Pt(32, 32), gocv.FontHersheyPlain, 2.0, color.RGBA{255, 0, 0, 0}, 2) + } + + d.windows[0].IMShow(img) + d.windows[1].IMShow(imgDelta) + d.windows[0].WaitKey(1) + } + + // Don't write to destination if there is no motion. + if mean < d.thresh { + return 0, nil + } + + // Write to destination. + return d.dst.Write(f) +} diff --git a/revid/config/config.go b/revid/config/config.go index b70a01b3..0192b1bd 100644 --- a/revid/config/config.go +++ b/revid/config/config.go @@ -127,6 +127,7 @@ const ( FilterMOG FilterVariableFPS FilterKNN + FilterDifference ) // OS names @@ -304,6 +305,8 @@ type Config struct { // Defines the rate at which frames from a file source are processed. FileFPS int + // Difference filter parameters. + DiffThreshold float64 // Intensity value from the Difference motion detection algorithm that is considered motion. } // TypeData contains information about all of the variables that @@ -317,9 +320,10 @@ var TypeData = map[string]string{ "CameraIP": "string", "CBR": "bool", "ClipDuration": "uint", + "DiffThreshold": "float", "Exposure": "enum:auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,antishake,fireworks", "FileFPS": "int", - "Filters": "enums:NoOp,MOG,VariableFPS,KNN", + "Filters": "enums:NoOp,MOG,VariableFPS,KNN,Difference", "FrameRate": "uint", "Height": "uint", "HorizontalFlip": "bool", @@ -340,13 +344,13 @@ var TypeData = map[string]string{ "MOGMinArea": "float", "MOGThreshold": "float", "MotionInterval": "int", - "RBCapacity": "uint", - "RBMaxElements": "uint", - "RBWriteTimeout": "uint", "Output": "enum:File,Http,Rtmp,Rtp", "OutputPath": "string", "Outputs": "enums:File,Http,Rtmp,Rtp", "Quantization": "uint", + "RBCapacity": "uint", + "RBMaxElements": "uint", + "RBWriteTimeout": "uint", "Rotation": "uint", "RTMPURL": "string", "RTPAddress": "string", diff --git a/revid/revid.go b/revid/revid.go index 94bd4a6f..fd7614f1 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -342,6 +342,8 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. r.filters[i] = filter.NewVariableFPSFilter(dst, r.cfg.MinFPS, filter.NewMOGFilter(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval)) case config.FilterKNN: r.filters[i] = filter.NewKNNFilter(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.ShowWindows, r.cfg.MotionInterval) + case config.FilterDifference: + r.filters[i] = filter.NewDiffFilter(dst, r.cfg.ShowWindows, r.cfg.DiffThreshold) default: panic("Undefined Filter") } @@ -663,7 +665,7 @@ func (r *Revid) Update(vars map[string]string) error { } case "Filters": filters := strings.Split(value, ",") - m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG, "VariableFPS": config.FilterVariableFPS, "KNN": config.FilterKNN} + m := map[string]int{"NoOp": config.FilterNoOp, "MOG": config.FilterMOG, "VariableFPS": config.FilterVariableFPS, "KNN": config.FilterKNN, "Difference": config.FilterDifference} r.cfg.Filters = make([]int, len(filters)) for i, filter := range filters { v, ok := m[filter] @@ -811,6 +813,13 @@ func (r *Revid) Update(vars map[string]string) error { break } r.cfg.KNNThreshold = v + case "DiffThreshold": + v, err := strconv.ParseFloat(value, 64) + if err != nil { + r.cfg.Logger.Log(logger.Warning, pkg+"invalid DiffThreshold var", "value", value) + break + } + r.cfg.DiffThreshold = v case "KNNKernel": v, err := strconv.Atoi(value) if err != nil { From 458933babb95bb105a7f6ffc7a39b509787ea27f Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 23 Jan 2020 14:03:08 +1030 Subject: [PATCH 16/22] filter: create function for satisfying circleci tests --- filter/filters_circleci.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/filter/filters_circleci.go b/filter/filters_circleci.go index 374e8b0a..d4c427d7 100644 --- a/filter/filters_circleci.go +++ b/filter/filters_circleci.go @@ -36,6 +36,12 @@ func NewMOGFilter(dst io.WriteCloser, area, threshold float64, history int, debu return &NoOp{dst: dst} } +// NewKNNFilter returns a pointer to a new NoOp struct for testing purposes only. func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSize int, debug bool, hf int) *NoOp { return &NoOp{dst: dst} } + +// NewDiffFilter returns a pointer to a new NoOp struct for testing purposes only. +func NewDiffFilter(dst io.WriteCloser, debug bool, threshold float64) *NoOp { + return &NoOp{dst: dst} +} From e0fa47490671fdbca93d70023e6c25cb97ca568d Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 24 Jan 2020 16:05:35 +1030 Subject: [PATCH 17/22] =?UTF-8?q?filter:=20DiffFilter=20=E2=86=92=20Differ?= =?UTF-8?q?ence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filter/difference.go | 14 +++++++------- filter/filters_circleci.go | 4 ++-- revid/revid.go | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/filter/difference.go b/filter/difference.go index 97df94b9..00de000a 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -38,10 +38,10 @@ import ( "gocv.io/x/gocv" ) -// DiffFilter is a filter that provides basic motion detection. DiffFilter calculates +// Difference is a filter that provides basic motion detection. Difference calculates // the absolute difference for each pixel between two frames, then finds the mean. If // the mean is above a given threshold, then it is considered motion. -type DiffFilter struct { +type Difference struct { dst io.WriteCloser thresh float64 prev gocv.Mat @@ -49,19 +49,19 @@ type DiffFilter struct { windows []*gocv.Window } -// NewDiffFilter returns a pointer to a new DiffFilter. -func NewDiffFilter(dst io.WriteCloser, debug bool, threshold float64) *DiffFilter { +// NewDifference returns a pointer to a new Difference struct. +func NewDifference(dst io.WriteCloser, debug bool, threshold float64) *Difference { var windows []*gocv.Window if debug { windows = []*gocv.Window{gocv.NewWindow("Diff: Bounding boxes"), gocv.NewWindow("Diff: Motion")} } - return &DiffFilter{dst, threshold, gocv.NewMat(), debug, windows} + return &Difference{dst, threshold, gocv.NewMat(), debug, windows} } // Implements io.Closer. // Close frees resources used by gocv, because it has to be done manually, due to // it using c-go. -func (d *DiffFilter) Close() error { +func (d *Difference) Close() error { d.prev.Close() for _, window := range d.windows { window.Close() @@ -72,7 +72,7 @@ func (d *DiffFilter) Close() error { // Implements io.Writer. // Write applies the motion filter to the video stream. Only frames with motion // are written to the destination encoder, frames without are discarded. -func (d *DiffFilter) Write(f []byte) (int, error) { +func (d *Difference) Write(f []byte) (int, error) { if d.prev.Empty() { d.prev, _ = gocv.IMDecode(f, gocv.IMReadColor) return 0, nil diff --git a/filter/filters_circleci.go b/filter/filters_circleci.go index d4c427d7..aaca83f6 100644 --- a/filter/filters_circleci.go +++ b/filter/filters_circleci.go @@ -41,7 +41,7 @@ func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSi return &NoOp{dst: dst} } -// NewDiffFilter returns a pointer to a new NoOp struct for testing purposes only. -func NewDiffFilter(dst io.WriteCloser, debug bool, threshold float64) *NoOp { +// NewDiffference returns a pointer to a new NoOp struct for testing purposes only. +func NewDifference(dst io.WriteCloser, debug bool, threshold float64) *NoOp { return &NoOp{dst: dst} } diff --git a/revid/revid.go b/revid/revid.go index fd7614f1..b5f31a6e 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -343,7 +343,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io. case config.FilterKNN: r.filters[i] = filter.NewKNNFilter(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.ShowWindows, r.cfg.MotionInterval) case config.FilterDifference: - r.filters[i] = filter.NewDiffFilter(dst, r.cfg.ShowWindows, r.cfg.DiffThreshold) + r.filters[i] = filter.NewDifference(dst, r.cfg.ShowWindows, r.cfg.DiffThreshold) default: panic("Undefined Filter") } From b15b649151d394d25d4313d8f66182595ada3d8b Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 24 Jan 2020 16:10:08 +1030 Subject: [PATCH 18/22] filter: check for errors after decoding --- filter/difference.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/filter/difference.go b/filter/difference.go index 00de000a..581cc8bf 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -74,12 +74,16 @@ func (d *Difference) Close() error { // are written to the destination encoder, frames without are discarded. func (d *Difference) Write(f []byte) (int, error) { if d.prev.Empty() { - d.prev, _ = gocv.IMDecode(f, gocv.IMReadColor) - return 0, nil + var err error + d.prev, err = gocv.IMDecode(f, gocv.IMReadColor) + return 0, err } - img, _ := gocv.IMDecode(f, gocv.IMReadColor) + img, err := gocv.IMDecode(f, gocv.IMReadColor) defer img.Close() + if err != nil { + return 0, err + } imgDelta := gocv.NewMat() defer imgDelta.Close() From fb43e9214ae5fb11d67e92ea4e2c1cec0ee9d40f Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 24 Jan 2020 16:29:06 +1030 Subject: [PATCH 19/22] filter: change formatting of code --- filter/difference.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/filter/difference.go b/filter/difference.go index 581cc8bf..4504c6ef 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -100,7 +100,15 @@ func (d *Difference) Write(f []byte) (int, error) { // Draw debug information. if d.debug { if mean >= d.thresh { - gocv.PutText(&img, fmt.Sprintf("motion - mean:%f", mean), image.Pt(32, 32), gocv.FontHersheyPlain, 2.0, color.RGBA{255, 0, 0, 0}, 2) + gocv.PutText( + &img, + fmt.Sprintf("motion - mean:%f", mean), + image.Pt(32, 32), + gocv.FontHersheyPlain, + 2.0, + color.RGBA{255, 0, 0, 0}, + 2, + ) } d.windows[0].IMShow(img) From a111f214279966885d1af40766dabd0ee9867453 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 27 Jan 2020 11:23:56 +1030 Subject: [PATCH 20/22] filter: return length from the filter's Write method --- filter/difference.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/filter/difference.go b/filter/difference.go index 4504c6ef..d01cf0a7 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -76,7 +76,10 @@ func (d *Difference) Write(f []byte) (int, error) { if d.prev.Empty() { var err error d.prev, err = gocv.IMDecode(f, gocv.IMReadColor) - return 0, err + if err != nil { + return 0, err + } + return len(f), nil } img, err := gocv.IMDecode(f, gocv.IMReadColor) @@ -94,7 +97,7 @@ func (d *Difference) Write(f []byte) (int, error) { mean := imgDelta.Mean().Val1 - // Update History + // Update History. d.prev = img.Clone() // Draw debug information. @@ -118,7 +121,7 @@ func (d *Difference) Write(f []byte) (int, error) { // Don't write to destination if there is no motion. if mean < d.thresh { - return 0, nil + return len(f), nil } // Write to destination. From cae7e55723f7ce5ed032218354165f56e4354b4a Mon Sep 17 00:00:00 2001 From: Saxon Date: Mon, 27 Jan 2020 13:54:43 +1030 Subject: [PATCH 21/22] revid/revid.go: added handling for FileFPS var from vidgrind --- revid/revid.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/revid/revid.go b/revid/revid.go index 5e3a035d..5eb5b7bf 100644 --- a/revid/revid.go +++ b/revid/revid.go @@ -859,6 +859,13 @@ func (r *Revid) Update(vars map[string]string) error { break } r.cfg.MOGHistory = uint(v) + case "FileFPS": + v, err := strconv.Atoi(value) + if err != nil { + r.cfg.Logger.Log(logger.Warning, pkg+"invalid FileFPS var", "value", value) + break + } + r.cfg.FileFPS = v case "mode": r.cfg.Loop = false if value == "Loop" { From d10a59631b3bbde164b7fbe5e2d9751d413e9274 Mon Sep 17 00:00:00 2001 From: Trek H Date: Tue, 28 Jan 2020 15:12:30 +1030 Subject: [PATCH 22/22] mjpeg-player: reduced more config variables --- cmd/mjpeg-player/hlsjs/config.js | 53 -------------------------------- 1 file changed, 53 deletions(-) diff --git a/cmd/mjpeg-player/hlsjs/config.js b/cmd/mjpeg-player/hlsjs/config.js index ed548ff9..94797f6b 100644 --- a/cmd/mjpeg-player/hlsjs/config.js +++ b/cmd/mjpeg-player/hlsjs/config.js @@ -27,31 +27,7 @@ import XhrLoader from './utils/xhr-loader.js'; // It is cloned whenever a new Hls instance is created, by keeping the config // shallow the properties are cloned, and we don't end up manipulating the default export const hlsDefaultConfig = { - autoStartLoad: true, // used by stream-controller startPosition: -1, // used by stream-controller - defaultAudioCodec: void 0, // used by stream-controller - debug: false, // used by logger - capLevelOnFPSDrop: false, // used by fps-controller - capLevelToPlayerSize: false, // used by cap-level-controller - initialLiveManifestSize: 1, // used by stream-controller - maxBufferLength: 30, // used by stream-controller - maxBufferSize: 60 * 1000 * 1000, // used by stream-controller - maxBufferHole: 0.5, // used by stream-controller - - lowBufferWatchdogPeriod: 0.5, // used by stream-controller - highBufferWatchdogPeriod: 3, // used by stream-controller - nudgeOffset: 0.1, // used by stream-controller - nudgeMaxRetry: 3, // used by stream-controller - maxFragLookUpTolerance: 0.25, // used by stream-controller - liveSyncDurationCount: 3, // used by stream-controller - liveMaxLatencyDurationCount: Infinity, // used by stream-controller - liveSyncDuration: void 0, // used by stream-controller - liveMaxLatencyDuration: void 0, // used by stream-controller - liveDurationInfinity: false, // used by buffer-controller - liveBackBufferLength: Infinity, // used by buffer-controller - maxMaxBufferLength: 600, // used by stream-controller - enableWorker: true, // used by demuxer - enableSoftwareAES: true, // used by decrypter manifestLoadingTimeOut: 10000, // used by playlist-loader manifestLoadingMaxRetry: 1, // used by playlist-loader manifestLoadingRetryDelay: 1000, // used by playlist-loader @@ -65,37 +41,8 @@ export const hlsDefaultConfig = { fragLoadingMaxRetry: 6, // used by fragment-loader fragLoadingRetryDelay: 1000, // used by fragment-loader fragLoadingMaxRetryTimeout: 64000, // used by fragment-loader - startFragPrefetch: false, // used by stream-controller - fpsDroppedMonitoringPeriod: 5000, // used by fps-controller - fpsDroppedMonitoringThreshold: 0.2, // used by fps-controller - appendErrorMaxRetry: 3, // used by buffer-controller loader: XhrLoader, - // loader: FetchLoader, fLoader: void 0, // used by fragment-loader pLoader: void 0, // used by playlist-loader xhrSetup: void 0, // used by xhr-loader - licenseXhrSetup: void 0, // used by eme-controller - fetchSetup: void 0, - // abrController: AbrController, - // bufferController: BufferController, - // capLevelController: CapLevelController, - // fpsController: FPSController, - stretchShortVideoTrack: false, // used by mp4-remuxer - maxAudioFramesDrift: 1, // used by mp4-remuxer - forceKeyFrameOnDiscontinuity: true, // used by ts-demuxer - abrEwmaFastLive: 3, // used by abr-controller - abrEwmaSlowLive: 9, // used by abr-controller - abrEwmaFastVoD: 3, // used by abr-controller - abrEwmaSlowVoD: 9, // used by abr-controller - abrEwmaDefaultEstimate: 5e5, // 500 kbps // used by abr-controller - abrBandWidthFactor: 0.95, // used by abr-controller - abrBandWidthUpFactor: 0.7, // used by abr-controller - abrMaxWithRealBitrate: false, // used by abr-controller - maxStarvationDelay: 4, // used by abr-controller - maxLoadingDelay: 4, // used by abr-controller - minAutoBitrate: 0, // used by hls - emeEnabled: false, // used by eme-controller - widevineLicenseUrl: void 0, // used by eme-controller - // requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess, // used by eme-controller - }; \ No newline at end of file