2022-04-29 11:49:32 +00:00
|
|
|
|
<template>
|
2022-05-28 05:16:27 +00:00
|
|
|
|
<div>
|
|
|
|
|
<video
|
|
|
|
|
ref="playerfake"
|
|
|
|
|
muted
|
|
|
|
|
autoplay
|
|
|
|
|
style="display: none"
|
|
|
|
|
:src="vidWrs"
|
|
|
|
|
/>
|
|
|
|
|
<!-- Scrubber -->
|
|
|
|
|
<v-slider
|
2022-05-29 17:08:21 +00:00
|
|
|
|
id="scrubber"
|
2022-05-28 05:16:27 +00:00
|
|
|
|
hide-details
|
|
|
|
|
height="2"
|
|
|
|
|
dense
|
2022-06-07 17:16:26 +00:00
|
|
|
|
color="transparent"
|
|
|
|
|
thumb-color="primary"
|
2022-05-29 17:08:21 +00:00
|
|
|
|
track-color="transparent"
|
2022-06-08 19:24:47 +00:00
|
|
|
|
:class="!controls && !fullscreen && !seeking ? 'invisible' : ''"
|
2022-06-09 05:36:01 +00:00
|
|
|
|
style="position: absolute; z-index: 69420"
|
2022-05-28 22:15:25 +00:00
|
|
|
|
:style="
|
|
|
|
|
fullscreen
|
2022-06-08 20:15:15 +00:00
|
|
|
|
? 'width: calc(100% - 2rem); left: 1rem; bottom: 55px;'
|
2022-06-08 16:55:10 +00:00
|
|
|
|
: 'width: calc(100% - 0.5rem); left: 0.25rem; bottom: 0;'
|
2022-05-28 22:15:25 +00:00
|
|
|
|
"
|
2022-05-28 05:16:27 +00:00
|
|
|
|
:thumb-size="0"
|
|
|
|
|
:max="duration"
|
2022-06-08 16:42:03 +00:00
|
|
|
|
:value="currentTime"
|
|
|
|
|
@start="$emit('seeking')"
|
|
|
|
|
@end="$emit('seeking')"
|
2022-06-08 16:57:12 +00:00
|
|
|
|
@change="$emit('scrub', $event)"
|
2022-06-08 16:42:03 +00:00
|
|
|
|
@input="seeking ? seek($event) : null"
|
2022-05-28 05:16:27 +00:00
|
|
|
|
>
|
|
|
|
|
<template #thumb-label="{ value }">
|
|
|
|
|
<div style="transform: translateY(-50%)">
|
|
|
|
|
<canvas
|
|
|
|
|
ref="preview"
|
|
|
|
|
class="white"
|
2022-05-28 05:27:34 +00:00
|
|
|
|
:width="video.clientWidth / 3"
|
|
|
|
|
:height="video.clientHeight / 3"
|
2022-05-28 05:16:27 +00:00
|
|
|
|
style="border: 2px solid white"
|
|
|
|
|
:style="{
|
|
|
|
|
borderRadius: $store.state.tweaks.roundWatch
|
|
|
|
|
? `${$store.state.tweaks.roundTweak / 3}rem`
|
|
|
|
|
: '0',
|
|
|
|
|
}"
|
|
|
|
|
></canvas>
|
|
|
|
|
<div class="text-center pb-4" style="font-size: 0.8rem">
|
2022-08-10 20:25:25 +00:00
|
|
|
|
<b v-if="seeking">{{ $vuetube.humanTime(value) }}</b>
|
2022-05-28 05:16:27 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</v-slider>
|
|
|
|
|
</div>
|
2022-04-29 11:49:32 +00:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
2022-06-01 18:06:34 +00:00
|
|
|
|
props: {
|
|
|
|
|
video: {
|
|
|
|
|
type: Object,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
controls: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
fullscreen: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
sources: {
|
|
|
|
|
type: Array,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
currentTime: {
|
|
|
|
|
type: Number,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
2022-06-08 15:59:43 +00:00
|
|
|
|
duration: {
|
|
|
|
|
type: Number,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
2022-06-08 16:55:10 +00:00
|
|
|
|
seeking: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
2022-04-29 11:49:32 +00:00
|
|
|
|
},
|
2022-06-08 16:57:12 +00:00
|
|
|
|
emits: ["scrub", "seeking"],
|
2022-06-01 18:06:34 +00:00
|
|
|
|
data: () => ({
|
|
|
|
|
vidWrs: "",
|
|
|
|
|
}),
|
2022-04-29 11:49:32 +00:00
|
|
|
|
mounted() {
|
2022-06-01 18:35:14 +00:00
|
|
|
|
this.vidWrs = this.sources[1].url;
|
2022-05-21 02:01:39 +00:00
|
|
|
|
},
|
2022-05-28 05:16:27 +00:00
|
|
|
|
methods: {
|
2022-06-01 18:06:34 +00:00
|
|
|
|
seek(e) {
|
|
|
|
|
// console.log(`scrubbing ${e}`);
|
|
|
|
|
let vid = this.$refs.playerfake;
|
|
|
|
|
let canvas = this.$refs.preview;
|
|
|
|
|
this.$refs.playerfake.currentTime = e;
|
|
|
|
|
canvas
|
|
|
|
|
.getContext("2d")
|
|
|
|
|
.drawImage(
|
|
|
|
|
vid,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
this.video.clientWidth / 3,
|
|
|
|
|
this.video.clientHeight / 3
|
|
|
|
|
);
|
|
|
|
|
},
|
2022-07-27 22:32:12 +00:00
|
|
|
|
// TODO: better scrubbing preview start
|
2022-06-08 15:59:43 +00:00
|
|
|
|
// loadVideoFrames() {
|
|
|
|
|
// // Exit loop if desired number of frames have been extracted
|
|
|
|
|
// if (this.frames.length >= frameCount) {
|
|
|
|
|
// this.visibleFrame = 0;
|
|
|
|
|
|
|
|
|
|
// // Append all canvases to container div
|
|
|
|
|
// this.frames.forEach((frame) => {
|
|
|
|
|
// this.frameContainerElement.appendChild(frame);
|
|
|
|
|
// });
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // If extraction hasn’t started, set desired time for first frame
|
|
|
|
|
// if (this.frames.length === 0) {
|
|
|
|
|
// this.requestedTime = 0;
|
|
|
|
|
// } else {
|
|
|
|
|
// this.requestedTime = this.requestedTime + this.frameTimestep;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Send seek request to video player for the next frame.
|
|
|
|
|
// this.videoElement.currentTime = this.requestedTime;
|
|
|
|
|
// },
|
|
|
|
|
// extractFrame(videoWidth, videoHeight) {
|
|
|
|
|
// // Create DOM canvas object
|
|
|
|
|
// var canvas = document.createElement("canvas");
|
|
|
|
|
// canvas.className = "video-scrubber-frame";
|
|
|
|
|
// canvas.height = videoHeight;
|
|
|
|
|
// canvas.width = videoWidth;
|
|
|
|
|
|
|
|
|
|
// // Copy current frame to canvas
|
|
|
|
|
// var context = canvas.getContext("2d");
|
|
|
|
|
// context.drawImage(this.videoElement, 0, 0, videoWidth, videoHeight);
|
|
|
|
|
// this.frames.push(canvas);
|
|
|
|
|
|
|
|
|
|
// // Load the next frame
|
|
|
|
|
// loadVideoFrames();
|
|
|
|
|
// },
|
|
|
|
|
// async extractFramesFromVideo(videoUrl, fps = 25) {
|
|
|
|
|
// // fully download it first (no buffering):
|
|
|
|
|
// console.log(videoUrl);
|
|
|
|
|
// console.log(fps);
|
|
|
|
|
// let videoBlob = await fetch(videoUrl, {
|
|
|
|
|
// headers: { range: "bytes=0-567139" },
|
|
|
|
|
// }).then((r) => r.blob());
|
|
|
|
|
// console.log(videoBlob);
|
|
|
|
|
// let videoObjectUrl = URL.createObjectURL(videoBlob);
|
|
|
|
|
// let video = document.createElement("video");
|
|
|
|
|
|
|
|
|
|
// let seekResolve;
|
|
|
|
|
// video.addEventListener("seeked", async function () {
|
|
|
|
|
// if (seekResolve) seekResolve();
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// video.src = videoObjectUrl;
|
|
|
|
|
|
|
|
|
|
// // workaround chromium metadata bug (https://stackoverflow.com/q/38062864/993683)
|
|
|
|
|
// while (
|
|
|
|
|
// (video.duration === Infinity || isNaN(video.duration)) &&
|
|
|
|
|
// video.readyState < 2
|
|
|
|
|
// ) {
|
|
|
|
|
// await new Promise((r) => setTimeout(r, 1000));
|
|
|
|
|
// video.currentTime = 10000000 * Math.random();
|
|
|
|
|
// }
|
|
|
|
|
// let duration = video.duration;
|
|
|
|
|
|
|
|
|
|
// let canvas = document.createElement("canvas");
|
|
|
|
|
// let context = canvas.getContext("2d");
|
|
|
|
|
// let [w, h] = [video.videoWidth, video.videoHeight];
|
|
|
|
|
// canvas.width = w;
|
|
|
|
|
// canvas.height = h;
|
|
|
|
|
|
|
|
|
|
// let interval = 1;
|
|
|
|
|
// let currentTime = 0;
|
|
|
|
|
|
|
|
|
|
// while (currentTime < duration) {
|
|
|
|
|
// video.currentTime = currentTime;
|
|
|
|
|
// await new Promise((r) => (seekResolve = r));
|
|
|
|
|
|
|
|
|
|
// context.drawImage(video, 0, 0, w, h);
|
|
|
|
|
// let base64ImageData = canvas.toDataURL();
|
|
|
|
|
// console.log(base64ImageData);
|
|
|
|
|
// this.frames.push(base64ImageData);
|
|
|
|
|
|
|
|
|
|
// currentTime += interval;
|
|
|
|
|
// }
|
|
|
|
|
// console.log("%c frames", "color: #00ff00");
|
|
|
|
|
// console.log(this.frames);
|
|
|
|
|
// },
|
2022-05-28 22:28:41 +00:00
|
|
|
|
// TODO: scrubbing preview end
|
2022-05-28 05:16:27 +00:00
|
|
|
|
},
|
2022-05-21 02:01:39 +00:00
|
|
|
|
};
|
2022-04-29 11:49:32 +00:00
|
|
|
|
</script>
|