# Extract Video

> 提取视频文件的基本信息、音频轨道、关键帧截图，或将其转换为可分析的格式。 当用户提供视频路径并需要了解内容、提取字幕、获取关键帧时使用。

- Skill: `gagaa-hue/extract-video` (Agent Skill)
- Install (CLI): `npx skillmds@latest add gagaa-hue/extract-video`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gagaa-hue/extract-video/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: gagaa-hue (https://skillmd.com/u/gagaa-hue)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/gagaa-hue/extract-video

---


# extract-video Skill

## 触发条件

用户输入 `/extract-video <路径>` 时，本 skill 生效。

## 执行流程

### Step 1: 自动检测 FFmpeg 路径

在 Windows 系统上，按以下优先级自动检测 FFmpeg：

1. **Winget 安装路径**（默认）：
   ```
   %LOCALAPPDATA%\Microsoft\WinGet\Packages\Gyan.FFmpeg_*
   ```

2. **Chocolatey 安装路径**：
   ```
   C:\ProgramData\chocolatey\bin\ffmpeg.exe
   ```

3. **官方安装程序路径**：
   ```
   C:\Program Files\FFmpeg\bin\ffmpeg.exe
   C:\ffmpeg\bin\ffmpeg.exe
   ```

4. **系统 PATH**：直接调用 `ffmpeg` / `ffprobe`

检测逻辑（Bash）：
```bash
# 尝试找到 ffmpeg
FFMPEG_PATH=""
PROBE_PATHS=(
  "$LOCALAPPDATA/Microsoft/WinGet/Packages/Gyan.FFmpeg_*/ffmpeg-*/bin/ffmpeg.exe"
  "/c/ProgramData/chocolatey/bin/ffmpeg.exe"
  "/c/Program Files/FFmpeg/bin/ffmpeg.exe"
  "/c/ffmpeg/bin/ffmpeg.exe"
)

for path in "${PROBE_PATHS[@]}"; do
  found=$(ls $path 2>/dev/null | head -1)
  if [ -n "$found" ]; then
    FFMPEG_PATH="$found"
    FFPROBE_PATH="${found/ffmpeg/ffprobe}"
    break
  fi
done

# 如果都没找到，尝试系统 PATH
if [ -z "$FFMPEG_PATH" ]; then
  if command -v ffmpeg &> /dev/null; then
    FFMPEG_PATH="ffmpeg"
    FFPROBE_PATH="ffprobe"
  fi
fi

if [ -z "$FFMPEG_PATH" ]; then
  echo "❌ FFmpeg 未找到。请安装："
  echo "   winget install Gyan.FFmpeg"
  echo "   或: choco install ffmpeg"
  exit 1
fi
```

### Step 2: 验证文件

确认路径存在且为视频文件：
```bash
if [ ! -f "$VIDEO_PATH" ]; then
  echo "❌ 文件不存在: $VIDEO_PATH"
  exit 1
fi
```

### Step 3: 根据操作类型执行

#### info（默认）
运行：
```bash
"$FFPROBE_PATH" -v quiet -print_format json -show_streams -show_format "$VIDEO_PATH"
```
将 JSON 结果整理为易读的摘要（分辨率、时长、帧率、编码器、音频轨道数等）。

#### frames
运行：
```bash
# 创建输出目录
OUTPUT_DIR="${TEMP:-/tmp}/extract-video-frames-$(date +%s)"
mkdir -p "$OUTPUT_DIR"

# 按时间间隔提取（每2秒一帧，480px宽度）
"$FFMPEG_PATH" -i "$VIDEO_PATH" -vf "fps=1/2,scale=480:-1" -q:v 2 "$OUTPUT_DIR/frame_%04d.jpg"

# 或按场景变化提取（需要更多计算）
# "$FFMPEG_PATH" -i "$VIDEO_PATH" -vf "select='gt(scene,0.3)',showinfo" -vsync vfr -q:v 2 -f image2 "$OUTPUT_DIR/scene_%04d.jpg"
```

生成完成后，列出提取的帧文件路径，供后续分析使用。

#### audio
运行：
```bash
OUTPUT_AUDIO="${VIDEO_PATH%.*}.mp3"
"$FFMPEG_PATH" -i "$VIDEO_PATH" -vn -acodec libmp3lame -q:a 2 "$OUTPUT_AUDIO"
```
输出音频文件路径。

#### subtitle
- 先尝试提取内嵌字幕流：
  ```bash
  "$FFMPEG_PATH" -i "$VIDEO_PATH" -map 0:s:0 "${VIDEO_PATH%.*}.srt" 2>/dev/null
  ```
- 若无内嵌字幕，提取音频后使用 Whisper 进行转写（如果 Whisper 可用）。
- 将字幕/转写文本内容返回给用户。

---

## 完整执行脚本模板

```bash
#!/bin/bash
VIDEO_PATH="$1"
ACTION="${2:-info}"

# 自动检测 FFmpeg
find_ffmpeg() {
  local paths=(
    "$LOCALAPPDATA/Microsoft/WinGet/Packages/Gyan.FFmpeg_*/ffmpeg-*/bin/ffmpeg.exe"
    "/c/ProgramData/chocolatey/bin/ffmpeg.exe"
    "/c/Program Files/FFmpeg/bin/ffmpeg.exe"
    "/c/ffmpeg/bin/ffmpeg.exe"
  )

  for pattern in "${paths[@]}"; do
    local found=$(ls $pattern 2>/dev/null | head -1)
    if [ -n "$found" ] && [ -f "$found" ]; then
      echo "$found"
      return 0
    fi
  done

  # 尝试 PATH
  if command -v ffmpeg &> /dev/null; then
    echo "ffmpeg"
    return 0
  fi

  return 1
}

FFMPEG=$(find_ffmpeg)
if [ -z "$FFMPEG" ]; then
  echo "❌ FFmpeg 未找到"
  echo "请安装: winget install Gyan.FFmpeg"
  exit 1
fi

FFPROBE="${FFMPEG/ffmpeg/ffprobe}"

# 验证文件
if [ ! -f "$VIDEO_PATH" ]; then
  echo "❌ 文件不存在: $VIDEO_PATH"
  exit 1
fi

# 执行操作
case "$ACTION" in
  info)
    "$FFPROBE" -v quiet -print_format json -show_streams -show_format "$VIDEO_PATH" | \
    python3 -c "
import sys, json
d = json.load(sys.stdin)
fmt = d.get('format', {})
streams = d.get('streams', [])
video = next((s for s in streams if s.get('codec_type') == 'video'), {})
audio = next((s for s in streams if s.get('codec_type') == 'audio'), {})

print('📹 视频信息')
print('=' * 40)
print(f'时长: {float(fmt.get(\"duration\", 0)):.2f} 秒')
print(f'大小: {int(fmt.get(\"size\", 0)) / 1024 / 1024:.2f} MB')
print(f'码率: {int(fmt.get(\"bit_rate\", 0)) / 1000:.0f} kbps')
print(f'格式: {fmt.get(\"format_name\", \"unknown\")}')
if video:
  print(f'分辨率: {video.get(\"width\", \"?\")}x{video.get(\"height\", \"?\")}')
  print(f'帧率: {eval(video.get(\"r_frame_rate\", \"0/1\")):.2f} fps')
  print(f'编码: {video.get(\"codec_name\", \"unknown\")}')
if audio:
  print(f'音频: {audio.get(\"codec_name\", \"unknown\")}, {audio.get(\"sample_rate\", \"?\")} Hz')
"
    ;;

  frames)
    OUTPUT_DIR="${TEMP:-/tmp}/extract-video-frames-$(date +%s)"
    mkdir -p "$OUTPUT_DIR"
    echo "🎬 正在提取关键帧..."
    "$FFMPEG" -i "$VIDEO_PATH" -vf "fps=1/2,scale=480:-1" -q:v 2 "$OUTPUT_DIR/frame_%04d.jpg" 2>/dev/null
    echo "✅ 已提取到: $OUTPUT_DIR"
    ls -la "$OUTPUT_DIR"
    ;;

  audio)
    OUTPUT="${VIDEO_PATH%.*}.mp3"
    echo "🎵 正在提取音频..."
    "$FFMPEG" -i "$VIDEO_PATH" -vn -acodec libmp3lame -q:a 2 "$OUTPUT" 2>/dev/null
    echo "✅ 已保存: $OUTPUT"
    ;;

  subtitle)
    OUTPUT="${VIDEO_PATH%.*}.srt"
    if "$FFMPEG" -i "$VIDEO_PATH" -map 0:s:0 "$OUTPUT" 2>/dev/null; then
      echo "✅ 字幕已提取: $OUTPUT"
    else
      echo "⚠️ 未找到内嵌字幕，尝试音频转写需要 Whisper"
    fi
    ;;

  *)
    echo "未知操作: $ACTION"
    echo "可用: info, frames, audio, subtitle"
    exit 1
    ;;
esac
```

---

## 输出要求

- 始终使用中文回复用户。
- 对于 `info` 操作，输出结构化的视频参数摘要。
- 对于 `frames/audio/subtitle` 操作，明确告知输出文件的路径，并总结内容。
- 如果过程中遇到依赖缺失，清晰告知用户需要安装什么，并提供安装命令。

