Implement frame by frame advance using keyboard shortcuts (#758)

* Added frame by frame advance functionality.

* Changed keybindings for frame by frame advancing.

* Fix comments.

* On Invidious videos using dash at high qualities the default is now skipping 1 frame at 60fps instead of 30fps. Avoided error on trying to read non-local dash manifest.

* On dash reading error, defaults to 60fps within determineMaxFramerate. maxFrameRate initialised in data object.

* Cleanup of framebyframe logic.
This commit is contained in:
Hiers 2020-11-13 22:29:41 +00:00 committed by GitHub
parent 758796c515
commit 1495699d22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 43 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import FtCard from '../ft-card/ft-card.vue'
import $ from 'jquery' import $ from 'jquery'
import videojs from 'video.js' import videojs from 'video.js'
import qualitySelector from '@silvermine/videojs-quality-selector' import qualitySelector from '@silvermine/videojs-quality-selector'
import fs from 'fs'
import 'videojs-vtt-thumbnails-freetube' import 'videojs-vtt-thumbnails-freetube'
import 'videojs-contrib-quality-levels' import 'videojs-contrib-quality-levels'
import 'videojs-http-source-selector' import 'videojs-http-source-selector'
@ -60,6 +61,7 @@ export default Vue.extend({
useDash: false, useDash: false,
useHls: false, useHls: false,
selectedDefaultQuality: '', selectedDefaultQuality: '',
maxFramerate: 0,
activeSourceList: [], activeSourceList: [],
mouseTimeout: null, mouseTimeout: null,
dataSetup: { dataSetup: {
@ -142,6 +144,7 @@ export default Vue.extend({
} }
this.determineFormatType() this.determineFormatType()
this.determineMaxFramerate()
}, },
beforeDestroy: function () { beforeDestroy: function () {
if (this.player !== null && !this.player.isInPictureInPicture()) { if (this.player !== null && !this.player.isInPictureInPicture()) {
@ -251,6 +254,20 @@ export default Vue.extend({
} }
}, },
determineMaxFramerate: function() {
fs.readFile(this.dashSrc[0].url, (err, data) => {
if (err) {
this.maxFramerate = 60
return
}
if (data.includes('frameRate="60"')) {
this.maxFramerate = 60
} else {
this.maxFramerate = 30
}
})
},
determineDefaultQualityLegacy: function () { determineDefaultQualityLegacy: function () {
if (this.useDash) { if (this.useDash) {
return return
@ -426,6 +443,22 @@ export default Vue.extend({
} }
}, },
framebyframe: function (step) {
this.player.pause()
const qualityHeight = this.useDash ? this.player.qualityLevels()[this.player.qualityLevels().selectedIndex].height : 0
let fps
// Non-Dash formats are 30fps only
if (qualityHeight >= 480 && this.maxFramerate === 60) {
fps = 60
} else {
fps = 30
}
// The 3 lines below were taken from the videojs-framebyframe node module by Helena Rasche
const frameTime = 1 / fps
const dist = frameTime * step
this.player.currentTime(this.player.currentTime() + dist)
},
changeVolume: function (volume) { changeVolume: function (volume) {
const currentVolume = this.player.volume() const currentVolume = this.player.volume()
const newVolume = currentVolume + volume const newVolume = currentVolume + volume
@ -637,6 +670,16 @@ export default Vue.extend({
event.preventDefault() event.preventDefault()
this.changeDurationByPercentage(0) this.changeDurationByPercentage(0)
break break
case 188:
// , Key
// Return to previous frame
this.framebyframe(-1)
break
case 190:
// . Key
// Advance to next frame
this.framebyframe(1)
break
} }
} }
} }