Merge branch 'master' of ssh://gitea.bowongai.com:222/bowong/mxivideo
This commit is contained in:
commit
d27ec4d634
|
|
@ -0,0 +1,211 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
测试视频文件加载的脚本
|
||||
检查视频文件的存在性、可访问性和格式
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
project_root = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from python_core.services.media_manager import MediaManager
|
||||
from python_core.config import settings
|
||||
|
||||
def check_video_files():
|
||||
"""检查视频文件的存在和可访问性"""
|
||||
print("🎬 检查视频文件...")
|
||||
|
||||
# 获取所有视频片段
|
||||
media_manager = MediaManager()
|
||||
segments = media_manager.get_all_segments()
|
||||
|
||||
if not segments:
|
||||
print("❌ 没有找到任何视频片段")
|
||||
return
|
||||
|
||||
print(f"📊 找到 {len(segments)} 个视频片段")
|
||||
|
||||
# 检查每个视频文件
|
||||
for i, segment in enumerate(segments[:10]): # 只检查前10个
|
||||
file_path = segment.get('file_path', '')
|
||||
filename = segment.get('filename', 'Unknown')
|
||||
|
||||
print(f"\n{i+1}. {filename}")
|
||||
print(f" 路径: {file_path}")
|
||||
|
||||
if not file_path:
|
||||
print(" ❌ 文件路径为空")
|
||||
continue
|
||||
|
||||
# 检查文件是否存在
|
||||
path_obj = Path(file_path)
|
||||
if path_obj.exists():
|
||||
print(" ✅ 文件存在")
|
||||
|
||||
# 检查文件大小
|
||||
size = path_obj.stat().st_size
|
||||
print(f" 📏 文件大小: {size:,} 字节 ({size/1024/1024:.2f} MB)")
|
||||
|
||||
# 检查文件权限
|
||||
readable = os.access(file_path, os.R_OK)
|
||||
print(f" 🔓 可读权限: {'是' if readable else '否'}")
|
||||
|
||||
# 检查文件扩展名
|
||||
extension = path_obj.suffix.lower()
|
||||
supported_formats = ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v']
|
||||
is_supported = extension in supported_formats
|
||||
print(f" 🎞️ 文件格式: {extension} ({'支持' if is_supported else '不支持'})")
|
||||
|
||||
else:
|
||||
print(" ❌ 文件不存在")
|
||||
|
||||
# 检查父目录是否存在
|
||||
parent_dir = path_obj.parent
|
||||
if parent_dir.exists():
|
||||
print(f" 📁 父目录存在: {parent_dir}")
|
||||
# 列出父目录中的文件
|
||||
try:
|
||||
files = list(parent_dir.glob("*"))
|
||||
print(f" 📋 父目录包含 {len(files)} 个文件")
|
||||
if files:
|
||||
print(" 📄 文件列表:")
|
||||
for f in files[:5]: # 只显示前5个
|
||||
print(f" - {f.name}")
|
||||
except Exception as e:
|
||||
print(f" ❌ 无法读取父目录: {e}")
|
||||
else:
|
||||
print(f" ❌ 父目录不存在: {parent_dir}")
|
||||
|
||||
def check_storage_directories():
|
||||
"""检查存储目录结构"""
|
||||
print("\n📁 检查存储目录结构...")
|
||||
|
||||
# 检查主要目录
|
||||
directories = [
|
||||
settings.temp_dir,
|
||||
settings.temp_dir / "cache",
|
||||
settings.temp_dir / "video_segments",
|
||||
settings.temp_dir / "original_videos",
|
||||
settings.temp_dir / "thumbnails"
|
||||
]
|
||||
|
||||
for directory in directories:
|
||||
print(f"\n📂 {directory}")
|
||||
if directory.exists():
|
||||
print(" ✅ 目录存在")
|
||||
|
||||
# 统计文件数量
|
||||
try:
|
||||
files = list(directory.glob("*"))
|
||||
video_files = [f for f in files if f.suffix.lower() in ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v']]
|
||||
|
||||
print(f" 📊 总文件数: {len(files)}")
|
||||
print(f" 🎬 视频文件数: {len(video_files)}")
|
||||
|
||||
if video_files:
|
||||
print(" 🎞️ 视频文件示例:")
|
||||
for vf in video_files[:3]:
|
||||
size = vf.stat().st_size
|
||||
print(f" - {vf.name} ({size/1024/1024:.2f} MB)")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ 无法读取目录内容: {e}")
|
||||
else:
|
||||
print(" ❌ 目录不存在")
|
||||
|
||||
def test_video_info_extraction():
|
||||
"""测试视频信息提取"""
|
||||
print("\n🔍 测试视频信息提取...")
|
||||
|
||||
media_manager = MediaManager()
|
||||
segments = media_manager.get_all_segments()
|
||||
|
||||
if not segments:
|
||||
print("❌ 没有视频片段可测试")
|
||||
return
|
||||
|
||||
# 测试第一个存在的视频文件
|
||||
for segment in segments[:5]:
|
||||
file_path = segment.get('file_path', '')
|
||||
if file_path and Path(file_path).exists():
|
||||
print(f"\n🎬 测试文件: {segment.get('filename', 'Unknown')}")
|
||||
print(f" 路径: {file_path}")
|
||||
|
||||
try:
|
||||
# 尝试获取视频信息
|
||||
video_info = media_manager._get_video_info(file_path)
|
||||
print(f" ✅ 视频信息提取成功:")
|
||||
print(f" 时长: {video_info.get('duration', 'N/A')} 秒")
|
||||
print(f" 分辨率: {video_info.get('width', 'N/A')}x{video_info.get('height', 'N/A')}")
|
||||
print(f" 帧率: {video_info.get('fps', 'N/A')} fps")
|
||||
print(f" 编码: {video_info.get('codec', 'N/A')}")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ 视频信息提取失败: {e}")
|
||||
continue
|
||||
else:
|
||||
print("❌ 没有找到可用的视频文件进行测试")
|
||||
|
||||
def suggest_fixes():
|
||||
"""建议修复方案"""
|
||||
print("\n🔧 修复建议:")
|
||||
|
||||
print("\n1. 如果视频文件不存在:")
|
||||
print(" - 检查导入过程是否正确完成")
|
||||
print(" - 确认文件没有被意外删除")
|
||||
print(" - 重新导入视频素材")
|
||||
|
||||
print("\n2. 如果文件存在但无法播放:")
|
||||
print(" - 检查文件格式是否支持")
|
||||
print(" - 验证文件是否损坏")
|
||||
print(" - 尝试使用其他播放器测试文件")
|
||||
|
||||
print("\n3. 如果路径问题:")
|
||||
print(" - 检查路径中是否包含特殊字符")
|
||||
print(" - 确认路径分隔符正确(Windows vs Unix)")
|
||||
print(" - 验证文件权限设置")
|
||||
|
||||
print("\n4. 浏览器播放问题:")
|
||||
print(" - 检查Tauri配置中的asset protocol设置")
|
||||
print(" - 验证CSP策略是否允许视频播放")
|
||||
print(" - 尝试不同的视频加载方法")
|
||||
|
||||
print("\n5. 调试步骤:")
|
||||
print(" - 启用浏览器开发者工具")
|
||||
print(" - 查看网络请求和错误信息")
|
||||
print(" - 检查控制台日志")
|
||||
print(" - 测试convertFileSrc和data URL方法")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🎬 视频加载问题诊断")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
# 1. 检查视频文件
|
||||
check_video_files()
|
||||
|
||||
# 2. 检查存储目录
|
||||
check_storage_directories()
|
||||
|
||||
# 3. 测试视频信息提取
|
||||
test_video_info_extraction()
|
||||
|
||||
# 4. 提供修复建议
|
||||
suggest_fixes()
|
||||
|
||||
print("\n✅ 诊断完成!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 诊断过程中出现错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -41,28 +41,11 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
return
|
||||
}
|
||||
|
||||
// 文件存在,转换为安全URL
|
||||
const src = convertFileSrc(videoPath)
|
||||
console.log('Video path conversion:', {
|
||||
originalPath: videoPath,
|
||||
convertedSrc: src,
|
||||
fileExists: exists,
|
||||
pathType: videoPath.includes('\\') ? 'Windows' : 'Unix',
|
||||
pathLength: videoPath.length
|
||||
})
|
||||
|
||||
// 获取文件详细信息
|
||||
try {
|
||||
const fileInfo = await invoke('get_file_info', { filePath: videoPath })
|
||||
console.log('File info:', fileInfo)
|
||||
} catch (infoError) {
|
||||
console.warn('Could not get file info:', infoError)
|
||||
}
|
||||
|
||||
setFileExists(true)
|
||||
setErrorMessage('')
|
||||
setVideoSrc(src)
|
||||
setLoadingMethod('convertFileSrc')
|
||||
|
||||
// 尝试多种方法加载视频
|
||||
await tryLoadVideo(videoPath)
|
||||
} catch (error) {
|
||||
console.error('Error checking file:', error)
|
||||
setFileExists(false)
|
||||
|
|
@ -74,21 +57,96 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
checkFileAndSetSrc()
|
||||
}, [isOpen, videoPath])
|
||||
|
||||
// 备用加载方法:使用data URL
|
||||
const tryDataUrlMethod = async () => {
|
||||
if (!videoPath) return
|
||||
// 尝试多种方法加载视频
|
||||
const tryLoadVideo = async (path: string) => {
|
||||
const methods = [
|
||||
{
|
||||
name: 'convertFileSrc',
|
||||
load: () => {
|
||||
const src = convertFileSrc(path)
|
||||
console.log('Trying convertFileSrc:', { originalPath: path, convertedSrc: src })
|
||||
return src
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'dataUrl',
|
||||
load: async () => {
|
||||
console.log('Trying data URL method for:', path)
|
||||
const dataUrl = await invoke<string>('read_video_as_data_url', { filePath: path })
|
||||
console.log('Data URL method successful, length:', dataUrl.length)
|
||||
return dataUrl
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
try {
|
||||
console.log('Trying data URL method for:', videoPath)
|
||||
const dataUrl = await invoke<string>('read_video_as_data_url', { filePath: videoPath })
|
||||
console.log('Data URL method successful, length:', dataUrl.length)
|
||||
setVideoSrc(dataUrl)
|
||||
setLoadingMethod('dataUrl')
|
||||
setErrorMessage('')
|
||||
} catch (error) {
|
||||
console.error('Data URL method failed:', error)
|
||||
setErrorMessage(`所有加载方法都失败了: ${error}`)
|
||||
for (const method of methods) {
|
||||
try {
|
||||
console.log(`Attempting video load with method: ${method.name}`)
|
||||
const src = await method.load()
|
||||
|
||||
// 测试视频源是否可用
|
||||
const testResult = await testVideoSource(src, method.name)
|
||||
if (testResult) {
|
||||
setVideoSrc(src)
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Method ${method.name} failed:`, error)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 所有方法都失败了
|
||||
setErrorMessage('无法加载视频:所有加载方法都失败了')
|
||||
}
|
||||
|
||||
// 测试视频源是否可用
|
||||
const testVideoSource = (src: string, methodName: string): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
const testVideo = document.createElement('video')
|
||||
|
||||
const cleanup = () => {
|
||||
testVideo.removeEventListener('canplay', onCanPlay)
|
||||
testVideo.removeEventListener('error', onError)
|
||||
testVideo.removeEventListener('loadstart', onLoadStart)
|
||||
}
|
||||
|
||||
const onCanPlay = () => {
|
||||
console.log(`${methodName} method successful - video can play`)
|
||||
cleanup()
|
||||
resolve(true)
|
||||
}
|
||||
|
||||
const onError = (e: any) => {
|
||||
console.log(`${methodName} method failed - video error:`, {
|
||||
error: e,
|
||||
networkState: testVideo.networkState,
|
||||
readyState: testVideo.readyState
|
||||
})
|
||||
cleanup()
|
||||
resolve(false)
|
||||
}
|
||||
|
||||
const onLoadStart = () => {
|
||||
console.log(`${methodName} method - load started`)
|
||||
}
|
||||
|
||||
testVideo.addEventListener('canplay', onCanPlay)
|
||||
testVideo.addEventListener('error', onError)
|
||||
testVideo.addEventListener('loadstart', onLoadStart)
|
||||
|
||||
// 设置超时
|
||||
setTimeout(() => {
|
||||
if (testVideo.readyState < 2) { // HAVE_CURRENT_DATA
|
||||
console.log(`${methodName} method timeout`)
|
||||
cleanup()
|
||||
resolve(false)
|
||||
}
|
||||
}, 5000)
|
||||
|
||||
testVideo.src = src
|
||||
testVideo.load()
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -239,13 +297,13 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
readyState: e.currentTarget.readyState,
|
||||
currentMethod: loadingMethod
|
||||
})
|
||||
|
||||
// 如果当前使用的是convertFileSrc方法,尝试备用的data URL方法
|
||||
if (loadingMethod === 'convertFileSrc') {
|
||||
console.log('convertFileSrc failed, trying data URL method...')
|
||||
await tryDataUrlMethod()
|
||||
} else {
|
||||
setErrorMessage('视频加载失败,请检查文件格式和路径')
|
||||
// 如果当前视频源失败,尝试重新加载
|
||||
if (videoPath) {
|
||||
console.log('Video error detected, attempting reload...')
|
||||
tryLoadVideo(videoPath).catch(err => {
|
||||
console.error('Reload failed:', err)
|
||||
setErrorMessage('视频加载失败:文件可能损坏或格式不支持')
|
||||
})
|
||||
}
|
||||
}}
|
||||
onLoadStart={() => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue