mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-27 01:21:20 -08:00
feat: remove unused style file and integrate TensorFlow body segmentation for danmuku mask functionality
This commit is contained in:
1 parent
d9bdc9bdeb
commit
ef56482911
5 files changed
+78463
-40
No files matched your search
@@ -20,5 +20,12 @@
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
]
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@mediapipe/selfie_segmentation": "^0.1.1675465747",
|
||||
"@tensorflow-models/body-segmentation": "^1.0.2",
|
||||
"@tensorflow/tfjs-backend-webgl": "^4.21.0",
|
||||
"@tensorflow/tfjs-converter": "^4.21.0",
|
||||
"@tensorflow/tfjs-core": "^4.21.0"
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,125 @@
|
||||
import style from 'bundle-text:./style.less';
|
||||
import * as tf from '@tensorflow/tfjs-core';
|
||||
import '@tensorflow/tfjs-backend-webgl';
|
||||
import * as bodySegmentation from '@tensorflow-models/body-segmentation';
|
||||
|
||||
export default function artplayerPluginDanmukuMask(option) {
|
||||
export default function artplayerPluginDanmukuMask(option = {}) {
|
||||
return (art) => {
|
||||
const {
|
||||
template: { $player, $video, $danmuku },
|
||||
} = art;
|
||||
|
||||
let segmenter = null;
|
||||
let canvas = null;
|
||||
let ctx = null;
|
||||
let animationFrameId = null;
|
||||
|
||||
async function initSegmenter() {
|
||||
await tf.setBackend('webgl');
|
||||
const model = bodySegmentation.SupportedModels.MediaPipeSelfieSegmentation;
|
||||
|
||||
const segmenterConfig = {
|
||||
runtime: 'mediapipe', // or 'tfjs'
|
||||
solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation',
|
||||
modelType: 'general',
|
||||
};
|
||||
|
||||
segmenter = await bodySegmentation.createSegmenter(model, segmenterConfig);
|
||||
}
|
||||
|
||||
function createCanvas() {
|
||||
canvas = document.createElement('canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.top = '0';
|
||||
canvas.style.left = '0';
|
||||
canvas.style.width = '100%';
|
||||
canvas.style.height = '100%';
|
||||
canvas.style.pointerEvents = 'none';
|
||||
$player.appendChild(canvas);
|
||||
}
|
||||
|
||||
async function segmentBody() {
|
||||
if ($video.paused || $video.ended) {
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
canvas.width = $video.videoWidth;
|
||||
canvas.height = $video.videoHeight;
|
||||
|
||||
const segmentation = await segmenter.segmentPeople($video);
|
||||
|
||||
if (!segmentation) {
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
return;
|
||||
}
|
||||
|
||||
const foregroundColor = { r: 0, g: 0, b: 0, a: 0 };
|
||||
const backgroundColor = { r: 0, g: 0, b: 0, a: 255 };
|
||||
const drawContour = false;
|
||||
const foregroundThreshold = 0.6;
|
||||
|
||||
const mask = await bodySegmentation.toBinaryMask(
|
||||
segmentation,
|
||||
foregroundColor,
|
||||
backgroundColor,
|
||||
drawContour,
|
||||
foregroundThreshold,
|
||||
);
|
||||
|
||||
const opacity = 1;
|
||||
const maskBlurAmount = 3;
|
||||
await bodySegmentation.drawMask(canvas, $video, mask, opacity, maskBlurAmount);
|
||||
|
||||
$danmuku.style.webkitMaskImage = `url(${canvas.toDataURL()})`;
|
||||
$danmuku.style.maskImage = `url(${canvas.toDataURL()})`;
|
||||
} catch (error) {
|
||||
console.error('Error in segmentBody:', error);
|
||||
}
|
||||
|
||||
animationFrameId = requestAnimationFrame(segmentBody);
|
||||
}
|
||||
|
||||
async function startSegmentation() {
|
||||
if (!segmenter) {
|
||||
await initSegmenter();
|
||||
}
|
||||
|
||||
if (!canvas) {
|
||||
createCanvas();
|
||||
}
|
||||
|
||||
// Wait for the video element to be ready
|
||||
await new Promise((resolve) => {
|
||||
if ($video.readyState >= 2) {
|
||||
resolve();
|
||||
} else {
|
||||
$video.onloadeddata = resolve;
|
||||
}
|
||||
});
|
||||
|
||||
segmentBody();
|
||||
}
|
||||
|
||||
function stopSegmentation() {
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
animationFrameId = null;
|
||||
}
|
||||
}
|
||||
|
||||
art.on('ready', startSegmentation);
|
||||
art.on('destroy', stopSegmentation);
|
||||
|
||||
return {
|
||||
name: 'artplayerPluginDanmukuMask',
|
||||
start: startSegmentation,
|
||||
stop: stopSegmentation,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
const id = 'artplayer-plugin-danmuku-mask';
|
||||
const $style = document.getElementById(id);
|
||||
if ($style) {
|
||||
$style.textContent = style;
|
||||
} else {
|
||||
const $style = document.createElement('style');
|
||||
$style.id = id;
|
||||
$style.textContent = style;
|
||||
document.head.appendChild($style);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayerPluginDanmukuMask'] = artplayerPluginDanmukuMask;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
.artplayer-plugin-danmuku-mask {
|
||||
//
|
||||
}
|
||||
Reference in new issue
Block a user