完善超分
This commit is contained in:
+162
-38
@@ -100,27 +100,30 @@ function PlayPageClient() {
|
|||||||
|
|
||||||
// Anime4K超分相关状态
|
// Anime4K超分相关状态
|
||||||
const [webGPUSupported, setWebGPUSupported] = useState<boolean>(false);
|
const [webGPUSupported, setWebGPUSupported] = useState<boolean>(false);
|
||||||
const [anime4kEnabled, setAnime4kEnabled] = useState<boolean>(() => {
|
const [anime4kEnabled, setAnime4kEnabled] = useState<boolean>(false);
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
const v = localStorage.getItem('enable_anime4k');
|
|
||||||
if (v !== null) return v === 'true';
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
const [anime4kMode, setAnime4kMode] = useState<string>(() => {
|
const [anime4kMode, setAnime4kMode] = useState<string>(() => {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
const v = localStorage.getItem('anime4k_mode');
|
const v = localStorage.getItem('anime4k_mode');
|
||||||
if (v !== null) return v;
|
if (v !== null) return v;
|
||||||
}
|
}
|
||||||
return 'fast';
|
return 'ModeA';
|
||||||
|
});
|
||||||
|
const [anime4kScale, setAnime4kScale] = useState<number>(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const v = localStorage.getItem('anime4k_scale');
|
||||||
|
if (v !== null) return parseFloat(v);
|
||||||
|
}
|
||||||
|
return 2.0;
|
||||||
});
|
});
|
||||||
const anime4kRef = useRef<any>(null);
|
const anime4kRef = useRef<any>(null);
|
||||||
const anime4kEnabledRef = useRef(anime4kEnabled);
|
const anime4kEnabledRef = useRef(anime4kEnabled);
|
||||||
const anime4kModeRef = useRef(anime4kMode);
|
const anime4kModeRef = useRef(anime4kMode);
|
||||||
|
const anime4kScaleRef = useRef(anime4kScale);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
anime4kEnabledRef.current = anime4kEnabled;
|
anime4kEnabledRef.current = anime4kEnabled;
|
||||||
anime4kModeRef.current = anime4kMode;
|
anime4kModeRef.current = anime4kMode;
|
||||||
}, [anime4kEnabled, anime4kMode]);
|
anime4kScaleRef.current = anime4kScale;
|
||||||
|
}, [anime4kEnabled, anime4kMode, anime4kScale]);
|
||||||
|
|
||||||
// 检测WebGPU支持
|
// 检测WebGPU支持
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -560,18 +563,59 @@ function PlayPageClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const video = artPlayerRef.current.video as HTMLVideoElement;
|
const video = artPlayerRef.current.video as HTMLVideoElement;
|
||||||
|
|
||||||
|
// 等待视频元数据加载完成
|
||||||
|
if (!video.videoWidth || !video.videoHeight) {
|
||||||
|
console.warn('视频尺寸未就绪,等待loadedmetadata事件');
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const handler = () => {
|
||||||
|
video.removeEventListener('loadedmetadata', handler);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
video.addEventListener('loadedmetadata', handler);
|
||||||
|
// 如果已经加载过了,立即resolve
|
||||||
|
if (video.videoWidth && video.videoHeight) {
|
||||||
|
video.removeEventListener('loadedmetadata', handler);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次检查视频尺寸
|
||||||
|
if (!video.videoWidth || !video.videoHeight) {
|
||||||
|
throw new Error('无法获取视频尺寸');
|
||||||
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const container = artPlayerRef.current.template.$video.parentElement;
|
const container = artPlayerRef.current.template.$video.parentElement;
|
||||||
|
|
||||||
// 设置canvas尺寸和样式
|
// 使用用户选择的超分倍数
|
||||||
canvas.width = video.videoWidth * 2; // 2倍超分
|
const scale = anime4kScaleRef.current;
|
||||||
canvas.height = video.videoHeight * 2;
|
canvas.width = video.videoWidth * scale;
|
||||||
|
canvas.height = video.videoHeight * scale;
|
||||||
canvas.style.position = 'absolute';
|
canvas.style.position = 'absolute';
|
||||||
canvas.style.top = '0';
|
canvas.style.top = '0';
|
||||||
canvas.style.left = '0';
|
canvas.style.left = '0';
|
||||||
canvas.style.width = '100%';
|
canvas.style.width = '100%';
|
||||||
canvas.style.height = '100%';
|
canvas.style.height = '100%';
|
||||||
canvas.style.objectFit = 'contain';
|
canvas.style.objectFit = 'contain';
|
||||||
|
canvas.style.cursor = 'pointer';
|
||||||
|
|
||||||
|
// 在canvas上监听点击事件,触发播放器的暂停/播放切换
|
||||||
|
const handleCanvasClick = (e: MouseEvent) => {
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.toggle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
canvas.addEventListener('click', handleCanvasClick);
|
||||||
|
|
||||||
|
// 在canvas上监听双击事件,触发全屏切换
|
||||||
|
const handleCanvasDblClick = (e: MouseEvent) => {
|
||||||
|
if (artPlayerRef.current) {
|
||||||
|
artPlayerRef.current.fullscreen = !artPlayerRef.current.fullscreen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
canvas.addEventListener('dblclick', handleCanvasDblClick);
|
||||||
|
|
||||||
// 隐藏原始video元素
|
// 隐藏原始video元素
|
||||||
video.style.display = 'none';
|
video.style.display = 'none';
|
||||||
@@ -581,15 +625,30 @@ function PlayPageClient() {
|
|||||||
|
|
||||||
// 动态导入对应的模式
|
// 动态导入对应的模式
|
||||||
let ModeClass: any;
|
let ModeClass: any;
|
||||||
if (anime4kModeRef.current === 'fast') {
|
const modeName = anime4kModeRef.current;
|
||||||
const { ModeA } = await import('anime4k-webgpu');
|
const modeModule = await import('anime4k-webgpu');
|
||||||
ModeClass = ModeA;
|
|
||||||
} else if (anime4kModeRef.current === 'balanced') {
|
switch (modeName) {
|
||||||
const { ModeB } = await import('anime4k-webgpu');
|
case 'ModeA':
|
||||||
ModeClass = ModeB;
|
ModeClass = modeModule.ModeA;
|
||||||
} else {
|
break;
|
||||||
const { ModeC } = await import('anime4k-webgpu');
|
case 'ModeB':
|
||||||
ModeClass = ModeC;
|
ModeClass = modeModule.ModeB;
|
||||||
|
break;
|
||||||
|
case 'ModeC':
|
||||||
|
ModeClass = modeModule.ModeC;
|
||||||
|
break;
|
||||||
|
case 'ModeAA':
|
||||||
|
ModeClass = modeModule.ModeAA;
|
||||||
|
break;
|
||||||
|
case 'ModeBB':
|
||||||
|
ModeClass = modeModule.ModeBB;
|
||||||
|
break;
|
||||||
|
case 'ModeCA':
|
||||||
|
ModeClass = modeModule.ModeCA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ModeClass = modeModule.ModeA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用anime4k-webgpu的render函数
|
// 使用anime4k-webgpu的render函数
|
||||||
@@ -614,11 +673,11 @@ function PlayPageClient() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const controller = await anime4kRender(renderConfig);
|
const controller = await anime4kRender(renderConfig);
|
||||||
anime4kRef.current = { controller, canvas };
|
anime4kRef.current = { controller, canvas, handleCanvasClick, handleCanvasDblClick };
|
||||||
|
|
||||||
console.log('Anime4K超分已启用,模式:', anime4kModeRef.current);
|
console.log('Anime4K超分已启用,模式:', anime4kModeRef.current, '倍数:', scale);
|
||||||
if (artPlayerRef.current) {
|
if (artPlayerRef.current) {
|
||||||
artPlayerRef.current.notice.show = `超分已启用 (${anime4kModeRef.current})`;
|
artPlayerRef.current.notice.show = `超分已启用 (${anime4kModeRef.current}, ${scale}x)`;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('初始化Anime4K失败:', err);
|
console.error('初始化Anime4K失败:', err);
|
||||||
@@ -639,6 +698,16 @@ function PlayPageClient() {
|
|||||||
// 停止渲染循环
|
// 停止渲染循环
|
||||||
anime4kRef.current.controller?.stop?.();
|
anime4kRef.current.controller?.stop?.();
|
||||||
|
|
||||||
|
// 移除canvas事件监听器
|
||||||
|
if (anime4kRef.current.canvas) {
|
||||||
|
if (anime4kRef.current.handleCanvasClick) {
|
||||||
|
anime4kRef.current.canvas.removeEventListener('click', anime4kRef.current.handleCanvasClick);
|
||||||
|
}
|
||||||
|
if (anime4kRef.current.handleCanvasDblClick) {
|
||||||
|
anime4kRef.current.canvas.removeEventListener('dblclick', anime4kRef.current.handleCanvasDblClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 移除canvas
|
// 移除canvas
|
||||||
if (anime4kRef.current.canvas && anime4kRef.current.canvas.parentNode) {
|
if (anime4kRef.current.canvas && anime4kRef.current.canvas.parentNode) {
|
||||||
anime4kRef.current.canvas.parentNode.removeChild(anime4kRef.current.canvas);
|
anime4kRef.current.canvas.parentNode.removeChild(anime4kRef.current.canvas);
|
||||||
@@ -688,6 +757,21 @@ function PlayPageClient() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更改Anime4K分辨率倍数
|
||||||
|
const changeAnime4KScale = async (scale: number) => {
|
||||||
|
try {
|
||||||
|
setAnime4kScale(scale);
|
||||||
|
localStorage.setItem('anime4k_scale', scale.toString());
|
||||||
|
|
||||||
|
if (anime4kEnabledRef.current) {
|
||||||
|
await cleanupAnime4K();
|
||||||
|
await initAnime4K();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('更改超分倍数失败:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function filterAdsFromM3U8(type: string, m3u8Content: string): string {
|
function filterAdsFromM3U8(type: string, m3u8Content: string): string {
|
||||||
if (!m3u8Content) return '';
|
if (!m3u8Content) return '';
|
||||||
|
|
||||||
@@ -1640,25 +1724,70 @@ function PlayPageClient() {
|
|||||||
html: '超分模式',
|
html: '超分模式',
|
||||||
selector: [
|
selector: [
|
||||||
{
|
{
|
||||||
html: '快速模式',
|
html: 'ModeA (快速)',
|
||||||
value: 'fast',
|
value: 'ModeA',
|
||||||
default: anime4kModeRef.current === 'fast',
|
default: anime4kModeRef.current === 'ModeA',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
html: '平衡模式',
|
html: 'ModeB (平衡)',
|
||||||
value: 'balanced',
|
value: 'ModeB',
|
||||||
default: anime4kModeRef.current === 'balanced',
|
default: anime4kModeRef.current === 'ModeB',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
html: '高质量模式',
|
html: 'ModeC (质量)',
|
||||||
value: 'high_quality',
|
value: 'ModeC',
|
||||||
default: anime4kModeRef.current === 'high_quality',
|
default: anime4kModeRef.current === 'ModeC',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: 'ModeAA (增强快速)',
|
||||||
|
value: 'ModeAA',
|
||||||
|
default: anime4kModeRef.current === 'ModeAA',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: 'ModeBB (增强平衡)',
|
||||||
|
value: 'ModeBB',
|
||||||
|
default: anime4kModeRef.current === 'ModeBB',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: 'ModeCA (最高质量)',
|
||||||
|
value: 'ModeCA',
|
||||||
|
default: anime4kModeRef.current === 'ModeCA',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
onSelect: async function (item: any) {
|
onSelect: async function (item: any) {
|
||||||
await changeAnime4KMode(item.value);
|
await changeAnime4KMode(item.value);
|
||||||
return item.html;
|
return item.html;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '超分倍数',
|
||||||
|
html: '超分倍数',
|
||||||
|
selector: [
|
||||||
|
{
|
||||||
|
html: '1.5x',
|
||||||
|
value: '1.5',
|
||||||
|
default: anime4kScaleRef.current === 1.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: '2.0x',
|
||||||
|
value: '2.0',
|
||||||
|
default: anime4kScaleRef.current === 2.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: '3.0x',
|
||||||
|
value: '3.0',
|
||||||
|
default: anime4kScaleRef.current === 3.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
html: '4.0x',
|
||||||
|
value: '4.0',
|
||||||
|
default: anime4kScaleRef.current === 4.0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onSelect: async function (item: any) {
|
||||||
|
await changeAnime4KScale(parseFloat(item.value));
|
||||||
|
return item.html;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
] : []),
|
] : []),
|
||||||
{
|
{
|
||||||
@@ -1752,11 +1881,6 @@ function PlayPageClient() {
|
|||||||
if (artPlayerRef.current && !artPlayerRef.current.paused) {
|
if (artPlayerRef.current && !artPlayerRef.current.paused) {
|
||||||
requestWakeLock();
|
requestWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果启用了Anime4K,初始化超分
|
|
||||||
if (anime4kEnabledRef.current) {
|
|
||||||
await initAnime4K();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听播放状态变化,控制 Wake Lock
|
// 监听播放状态变化,控制 Wake Lock
|
||||||
|
|||||||
Reference in New Issue
Block a user