mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-20 04:01:20 -08:00
refactor: Update loadedTime and playing getters in Artplayer
This commit is contained in:
1 parent
8613164368
commit
0a7d3ca5aa
3 files changed
+272
-176
No files matched your search
@@ -1,76 +1,103 @@
|
||||
import { MP4Clip } from '@webav/av-cliper';
|
||||
|
||||
export default function artplayerProxyWebAV(option) {
|
||||
export default function artplayerProxyWebAV() {
|
||||
return (art) => {
|
||||
const { option, constructor } = art;
|
||||
const { createElement, def } = constructor.utils;
|
||||
|
||||
const canvas = createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const audioCtx = new AudioContext();
|
||||
let audioCtx;
|
||||
let gainNode;
|
||||
|
||||
let clip = null;
|
||||
let timer = null;
|
||||
let audioSource = null;
|
||||
|
||||
let playing = false;
|
||||
let duration = 0;
|
||||
let videoWidth = 0;
|
||||
let videoHeight = 0;
|
||||
let currentTime = 0;
|
||||
let loadedTime = 0;
|
||||
let volume = 1;
|
||||
let autoplay = false;
|
||||
let playbackRate = 1;
|
||||
let paused = true;
|
||||
let ended = false;
|
||||
let readyState = 0;
|
||||
let muted = false;
|
||||
const state = {
|
||||
playing: false,
|
||||
duration: 0,
|
||||
videoWidth: 0,
|
||||
videoHeight: 0,
|
||||
currentTime: 0,
|
||||
loadedTime: 0,
|
||||
volume: 1,
|
||||
autoplay: false,
|
||||
playbackRate: 1,
|
||||
paused: true,
|
||||
ended: false,
|
||||
readyState: 0,
|
||||
muted: false,
|
||||
};
|
||||
|
||||
function reset() {
|
||||
playing = false;
|
||||
duration = 0;
|
||||
videoWidth = 0;
|
||||
videoHeight = 0;
|
||||
currentTime = 0;
|
||||
loadedTime = 0;
|
||||
volume = 1;
|
||||
autoplay = false;
|
||||
playbackRate = 1;
|
||||
paused = true;
|
||||
ended = false;
|
||||
readyState = 0;
|
||||
muted = false;
|
||||
Object.assign(state, {
|
||||
playing: false,
|
||||
duration: 0,
|
||||
videoWidth: 0,
|
||||
videoHeight: 0,
|
||||
currentTime: 0,
|
||||
loadedTime: 0,
|
||||
volume: 1,
|
||||
autoplay: false,
|
||||
playbackRate: 1,
|
||||
paused: true,
|
||||
ended: false,
|
||||
readyState: 0,
|
||||
muted: false,
|
||||
});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
clearInterval(timer);
|
||||
audioSource?.stop();
|
||||
if (audioSource) {
|
||||
audioSource.stop();
|
||||
audioSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
function play() {
|
||||
let curTime = currentTime * 1e6;
|
||||
function updateVolume() {
|
||||
if (gainNode) {
|
||||
const effectiveVolume = state.muted ? 0 : state.volume;
|
||||
gainNode.gain.setValueAtTime(effectiveVolume, audioCtx.currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
async function play() {
|
||||
if (!audioCtx) {
|
||||
audioCtx = new AudioContext();
|
||||
gainNode = audioCtx.createGain();
|
||||
gainNode.connect(audioCtx.destination);
|
||||
}
|
||||
|
||||
let curTime = state.currentTime * 1e6;
|
||||
let startAt = 0;
|
||||
let first = true;
|
||||
|
||||
stop();
|
||||
|
||||
timer = setInterval(async () => {
|
||||
const { state, video, audio } = await clip.tick(Math.round(curTime));
|
||||
updateVolume();
|
||||
|
||||
curTime += (1000 / 30) * 1000;
|
||||
currentTime = curTime / 1e6;
|
||||
timer = setInterval(async () => {
|
||||
const { state: clipState, video, audio } = await clip.tick(Math.round(curTime));
|
||||
|
||||
curTime += (1000 / 30) * 1000 * state.playbackRate;
|
||||
state.currentTime = curTime / 1e6;
|
||||
|
||||
art.emit('video:timeupdate', { type: 'timeupdate' });
|
||||
|
||||
if (state === 'done') {
|
||||
clearInterval(timer);
|
||||
if (clipState === 'done') {
|
||||
stop();
|
||||
state.ended = true;
|
||||
state.playing = false;
|
||||
state.paused = true;
|
||||
art.emit('video:ended', { type: 'ended' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (video != null && state === 'success') {
|
||||
ctx.clearRect(0, 0, videoWidth, videoHeight);
|
||||
ctx.drawImage(video, 0, 0, videoWidth, videoHeight);
|
||||
if (video && clipState === 'success') {
|
||||
ctx.clearRect(0, 0, state.videoWidth, state.videoHeight);
|
||||
ctx.drawImage(video, 0, 0, state.videoWidth, state.videoHeight);
|
||||
video.close();
|
||||
}
|
||||
|
||||
@@ -79,23 +106,30 @@ export default function artplayerProxyWebAV(option) {
|
||||
return;
|
||||
}
|
||||
|
||||
const len = audio[0]?.length ?? 0;
|
||||
if (len === 0) return;
|
||||
const buf = audioCtx.createBuffer(2, len, 48000);
|
||||
buf.copyToChannel(audio[0], 0);
|
||||
buf.copyToChannel(audio[1], 1);
|
||||
audioSource = audioCtx.createBufferSource();
|
||||
audioSource.buffer = buf;
|
||||
audioSource.connect(audioCtx.destination);
|
||||
startAt = Math.max(audioCtx.currentTime, startAt);
|
||||
audioSource.start(startAt);
|
||||
startAt += buf.duration;
|
||||
if (audio?.[0]?.length) {
|
||||
const buf = audioCtx.createBuffer(2, audio[0].length, 48000);
|
||||
buf.copyToChannel(audio[0], 0);
|
||||
buf.copyToChannel(audio[1], 1);
|
||||
audioSource = audioCtx.createBufferSource();
|
||||
audioSource.buffer = buf;
|
||||
audioSource.connect(gainNode);
|
||||
audioSource.playbackRate.setValueAtTime(state.playbackRate, audioCtx.currentTime);
|
||||
startAt = Math.max(audioCtx.currentTime, startAt);
|
||||
audioSource.start(startAt);
|
||||
startAt += buf.duration / state.playbackRate;
|
||||
}
|
||||
}, 1000 / 30);
|
||||
|
||||
state.playing = true;
|
||||
state.paused = false;
|
||||
}
|
||||
|
||||
async function preview(time) {
|
||||
const { video } = await clip.tick(time * 1e6);
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
if (video) {
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
video.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
@@ -109,13 +143,12 @@ export default function artplayerProxyWebAV(option) {
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.resolve();
|
||||
art.emit('video:loadstart', { type: 'loadstart' });
|
||||
const response = await fetch(option.url);
|
||||
|
||||
if (!response.body) {
|
||||
const error = new Error('No response body');
|
||||
art.emit('video:error', error);
|
||||
throw error;
|
||||
throw new Error('No response body');
|
||||
}
|
||||
|
||||
clip = new MP4Clip(response.body);
|
||||
@@ -126,14 +159,16 @@ export default function artplayerProxyWebAV(option) {
|
||||
|
||||
const info = await clip.ready;
|
||||
|
||||
readyState = 4;
|
||||
duration = Math.round(info.duration / 1e6);
|
||||
videoWidth = info.width;
|
||||
videoHeight = info.height;
|
||||
Object.assign(state, {
|
||||
readyState: 4,
|
||||
duration: Math.round(info.duration / 1e6),
|
||||
videoWidth: info.width,
|
||||
videoHeight: info.height,
|
||||
});
|
||||
|
||||
canvas.width = videoWidth;
|
||||
canvas.height = videoHeight;
|
||||
preview(0.1);
|
||||
canvas.width = state.videoWidth;
|
||||
canvas.height = state.videoHeight;
|
||||
await preview(0.1);
|
||||
|
||||
art.emit('video:loadedmetadata', { type: 'loadedmetadata' });
|
||||
art.emit('video:durationchange', { type: 'durationchange' });
|
||||
@@ -147,41 +182,51 @@ export default function artplayerProxyWebAV(option) {
|
||||
});
|
||||
|
||||
def(canvas, 'loadedTime', {
|
||||
get: () => loadedTime,
|
||||
get: () => state.loadedTime,
|
||||
});
|
||||
|
||||
def(canvas, 'duration', {
|
||||
get: () => duration,
|
||||
get: () => state.duration,
|
||||
});
|
||||
|
||||
def(canvas, 'videoWidth', {
|
||||
get: () => videoWidth,
|
||||
get: () => state.videoWidth,
|
||||
});
|
||||
|
||||
def(canvas, 'videoHeight', {
|
||||
get: () => videoHeight,
|
||||
get: () => state.videoHeight,
|
||||
});
|
||||
|
||||
def(canvas, 'volume', {
|
||||
get: () => volume,
|
||||
get: () => state.volume,
|
||||
set: (val) => {
|
||||
volume = val;
|
||||
state.volume = Math.max(0, Math.min(1, val));
|
||||
updateVolume();
|
||||
art.emit('video:volumechange', { type: 'volumechange' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'currentTime', {
|
||||
get: () => currentTime,
|
||||
get: () => state.currentTime,
|
||||
set: (val) => {
|
||||
currentTime = val;
|
||||
preview(val);
|
||||
const newTime = Math.max(0, Math.min(val, state.duration));
|
||||
state.currentTime = newTime;
|
||||
preview(newTime);
|
||||
if (state.playing) {
|
||||
stop();
|
||||
play();
|
||||
}
|
||||
art.emit('video:timeupdate', { type: 'timeupdate' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'autoplay', {
|
||||
get: () => autoplay,
|
||||
get: () => state.autoplay,
|
||||
set: (val) => {
|
||||
autoplay = val;
|
||||
state.autoplay = val;
|
||||
if (val && state.readyState >= 4) {
|
||||
canvas.play();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -189,47 +234,54 @@ export default function artplayerProxyWebAV(option) {
|
||||
get: () => option.url,
|
||||
set: (val) => {
|
||||
option.url = val;
|
||||
init();
|
||||
init().then(() => {
|
||||
if (state.autoplay) {
|
||||
canvas.play();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'playbackRate', {
|
||||
get: () => playbackRate,
|
||||
get: () => state.playbackRate,
|
||||
set: (val) => {
|
||||
playbackRate = val;
|
||||
state.playbackRate = Math.max(0.25, Math.min(2, val));
|
||||
if (audioSource) {
|
||||
audioSource.playbackRate.setValueAtTime(state.playbackRate, audioCtx.currentTime);
|
||||
}
|
||||
art.emit('video:ratechange', { type: 'ratechange' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'playing', {
|
||||
get: () => playing,
|
||||
get: () => state.playing,
|
||||
});
|
||||
|
||||
def(canvas, 'paused', {
|
||||
get: () => paused,
|
||||
get: () => state.paused,
|
||||
});
|
||||
|
||||
def(canvas, 'ended', {
|
||||
get: () => ended,
|
||||
get: () => state.ended,
|
||||
});
|
||||
|
||||
def(canvas, 'readyState', {
|
||||
get: () => readyState,
|
||||
get: () => state.readyState,
|
||||
});
|
||||
|
||||
def(canvas, 'muted', {
|
||||
get: () => muted,
|
||||
get: () => state.muted,
|
||||
set: (val) => {
|
||||
muted = val;
|
||||
state.muted = val;
|
||||
updateVolume();
|
||||
art.emit('video:volumechange', { type: 'volumechange' });
|
||||
},
|
||||
});
|
||||
|
||||
// Define methods
|
||||
def(canvas, 'play', {
|
||||
value: async () => {
|
||||
play();
|
||||
playing = true;
|
||||
paused = false;
|
||||
await play();
|
||||
art.emit('video:play', { type: 'play' });
|
||||
art.emit('video:playing', { type: 'playing' });
|
||||
},
|
||||
@@ -238,8 +290,8 @@ export default function artplayerProxyWebAV(option) {
|
||||
def(canvas, 'pause', {
|
||||
value: () => {
|
||||
stop();
|
||||
playing = false;
|
||||
paused = true;
|
||||
state.playing = false;
|
||||
state.paused = true;
|
||||
art.emit('video:pause', { type: 'pause' });
|
||||
},
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user