2026-05-18-19-41-29 修复样例视频浏览器显示

This commit is contained in:
2026-05-18 19:43:25 +08:00
parent 72d0e9a168
commit f89ce5f5f6
7 changed files with 133 additions and 1 deletions

View File

@@ -77,7 +77,14 @@ function renderPreview(file) {
imagePreview.hidden = true; imagePreview.hidden = true;
openSourceButton.hidden = false; openSourceButton.hidden = false;
if (file.type.startsWith("video/")) { if (file.type.startsWith("video/")) {
videoPreview.preload = "metadata";
videoPreview.onloadedmetadata = () => {
if (Number.isFinite(videoPreview.duration) && videoPreview.duration > 0.2) {
videoPreview.currentTime = 0.1;
}
};
videoPreview.src = currentObjectUrl; videoPreview.src = currentObjectUrl;
videoPreview.load();
videoPreview.hidden = false; videoPreview.hidden = false;
openSourceButton.textContent = "放大查看"; openSourceButton.textContent = "放大查看";
sourcePaneTitle.textContent = "查看原始视频"; sourcePaneTitle.textContent = "查看原始视频";
@@ -280,7 +287,14 @@ openSourceButton.addEventListener("click", () => {
sourceVideo.hidden = true; sourceVideo.hidden = true;
sourceImage.hidden = true; sourceImage.hidden = true;
if (selectedFile.type.startsWith("video/")) { if (selectedFile.type.startsWith("video/")) {
sourceVideo.preload = "metadata";
sourceVideo.onloadedmetadata = () => {
if (Number.isFinite(sourceVideo.duration) && sourceVideo.duration > 0.2) {
sourceVideo.currentTime = 0.1;
}
};
sourceVideo.src = currentObjectUrl; sourceVideo.src = currentObjectUrl;
sourceVideo.load();
sourceVideo.hidden = false; sourceVideo.hidden = false;
} else { } else {
sourceImage.src = currentObjectUrl; sourceImage.src = currentObjectUrl;

View File

@@ -1,6 +1,8 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path from pathlib import Path
import shutil
import subprocess
import cv2 import cv2
import numpy as np import numpy as np
@@ -44,15 +46,45 @@ def make_frame(index: int, width: int = 640, height: int = 420) -> np.ndarray:
def main() -> None: def main() -> None:
SAMPLE_DIR.mkdir(parents=True, exist_ok=True) SAMPLE_DIR.mkdir(parents=True, exist_ok=True)
video_path = SAMPLE_DIR / "synthetic_guidewire.mp4" video_path = SAMPLE_DIR / "synthetic_guidewire.mp4"
raw_video_path = SAMPLE_DIR / "synthetic_guidewire.raw.mp4"
image_path = SAMPLE_DIR / "synthetic_guidewire.png" image_path = SAMPLE_DIR / "synthetic_guidewire.png"
width, height = 640, 420 width, height = 640, 420
writer = cv2.VideoWriter(str(video_path), cv2.VideoWriter_fourcc(*"mp4v"), 12.0, (width, height)) writer = cv2.VideoWriter(str(raw_video_path), cv2.VideoWriter_fourcc(*"mp4v"), 12.0, (width, height))
for index in range(72): for index in range(72):
frame = make_frame(index, width, height) frame = make_frame(index, width, height)
if index == 12: if index == 12:
cv2.imwrite(str(image_path), frame) cv2.imwrite(str(image_path), frame)
writer.write(frame) writer.write(frame)
writer.release() writer.release()
ffmpeg = shutil.which("ffmpeg")
if ffmpeg:
subprocess.run(
[
ffmpeg,
"-y",
"-i",
str(raw_video_path),
"-c:v",
"libx264",
"-pix_fmt",
"yuv420p",
"-movflags",
"+faststart",
"-preset",
"veryfast",
"-crf",
"20",
str(video_path),
],
check=True,
capture_output=True,
text=True,
)
raw_video_path.unlink(missing_ok=True)
else:
raw_video_path.replace(video_path)
print(video_path) print(video_path)
print(image_path) print(image_path)

View File

@@ -0,0 +1,24 @@
# 实现方案
开始时间2026-05-18-19-41-29
## 修改内容
1. `scripts/generate_sample.py`
- 先用 OpenCV 生成临时 `mp4v` 视频。
- 如果系统存在 `ffmpeg`,自动转码为 `libx264``yuv420p``faststart` 的浏览器友好 MP4。
- 如果没有 `ffmpeg`,退回保留 OpenCV 输出,保证脚本仍可运行。
2. `frontend/app.js`
- 视频预览设置 `preload = "metadata"`
- 设置 `src` 后调用 `load()`
- `loadedmetadata` 后尝试跳到 `0.1s`,帮助浏览器绘制首个可见帧。
- 原始视频弹窗也复用相同逻辑。
3. 重新生成样例
- 执行 `bash scripts/generate_sample.sh`
- 使用 `ffprobe` 确认编码为 H.264。
## 说明
这次问题不是用户操作错误,而是样例视频编码格式与浏览器播放兼容性不够稳。

View File

@@ -0,0 +1,27 @@
# 测试方案
开始时间2026-05-18-19-41-29
## 测试项
- `bash scripts/generate_sample.sh`
- `ffprobe` 检查 `storage/samples/synthetic_guidewire.mp4` 编码。
- `pytest -q`
- `curl -s http://127.0.0.1:8001/api/health`
- `curl -s http://127.0.0.1:8001/api/samples`
- 使用样例视频调用 `/api/segment`,确认后端仍可读取视频。
## 验收标准
- 样例视频编码为 H.264 或至少返回 `codec_tag_string=avc1`
- 点击“加载样例”后左侧原始视频面板能显示视频画面。
- 分割接口仍可处理样例视频。
## 执行结果
- `bash scripts/generate_sample.sh`:通过,重新生成样例视频和样例图像。
- `ffprobe storage/samples/synthetic_guidewire.mp4`:通过,返回 `codec_name=h264``codec_tag_string=avc1``pix_fmt=yuv420p`
- `pytest -q`通过4 个测试全部通过。
- `/api/samples`:通过,返回新的样例视频大小 `638484` 字节。
- `/api/segment` 使用新样例视频:通过,返回 `job_id=da013f73c636` 和 3 帧分割结果。
- `git diff --check`:通过,无空白格式错误。

View File

@@ -93,3 +93,15 @@ B. 产生问题原因:上一版将原始媒体查看入口作为辅助操作
C. 解决问题方案:将右侧工作区拆成左右两个 `workspace-pane`:左侧固定展示原始视频/图像,右侧展示分割进度、摘要和结果帧;保留“放大查看”作为左侧面板内的辅助操作。 C. 解决问题方案:将右侧工作区拆成左右两个 `workspace-pane`:左侧固定展示原始视频/图像,右侧展示分割进度、摘要和结果帧;保留“放大查看”作为左侧面板内的辅助操作。
D. 后续如何避免问题:医学影像交互页面应优先考虑“原始输入”和“算法输出”并列对照,而不是把原始输入藏在结果区域的附属操作中。 D. 后续如何避免问题:医学影像交互页面应优先考虑“原始输入”和“算法输出”并列对照,而不是把原始输入藏在结果区域的附属操作中。
## 2026-05-18-19-41-29 样例视频浏览器不显示画面
### 1. 样例视频控件显示但画面不渲染
A. 具体问题:用户点击“加载样例”后,左侧“查看原始视频”出现视频控件,但看不到原始视频画面。
B. 产生问题原因:内置样例视频由 OpenCV 直接写出,编码为 `mpeg4/mp4v`Chrome 对这种 MP4 兼容性不如 H.264 稳定,可能只显示控件不显示画面。
C. 解决问题方案:修改样例生成脚本,生成后用 `ffmpeg` 转码为 `libx264``yuv420p``faststart` MP4前端视频加载后调用 `load()` 并在 metadata 加载后轻微 seek 到 `0.1s`
D. 后续如何避免问题:面向网页播放的样例视频统一转为 H.264/yuv420p并用 Chrome 实际播放或截图验证,而不是只验证 OpenCV 能读取。

View File

@@ -0,0 +1,23 @@
# 需求分析
开始时间2026-05-18-19-41-29
## 用户反馈
用户点击“加载样例”后,左侧“查看原始视频”面板出现视频控件,但没有显示原始视频画面。
## 问题判断
通过 `ffprobe` 检查当前样例视频:
- `codec_name=mpeg4`
- `codec_tag_string=mp4v`
Chrome 对 OpenCV 直接写出的 `mp4v` MP4 兼容性不稳定,可能出现视频控件可见但首帧/画面不渲染的情况。
## 本轮目标
- 将内置样例视频改为浏览器兼容性更好的 H.264/yuv420p。
- 重新生成 `storage/samples/synthetic_guidewire.mp4`
- 前端加载视频后主动触发 `load()` 并轻微 seek帮助浏览器显示首帧。
- 验证样例视频编码和系统功能。