# Video To Md

> 영상 파일(mp4/avi/mov/mkv/webm 등)을 ffmpeg 프레임 추출과 화면 판독으로 분석해, 영상을 직접 볼 수 없는 사람이나 에이전트가 내용을 숙지할 수 있는 마크다운 문서로 정리한다. "영상 분석해줘", "녹화 내용 정리해줘", "이 동영상 뭐 하는 건지 설명해줘", "화면녹화 문서화해줘", "영상 내용 md로 만들어줘" 같은 요청에 반드시 사용한다. 프로젝트 폴더에 추가된 화면녹화·데모·시연·회의녹화·튜토리얼·강의 영상의 내용을 파악해야 하는 상황이면, 사용자가 "분석"이라는 단어를 쓰지 않았더라도 적용한다. 영상 파일 경로가 언급되고 그 내용을 알아야 답할 수 있는 모든 상황이 대상이다.

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

---


# 영상 → 숙지용 마크다운

> **Claude Code · codex · goose 공용.** 런타임별 변형본을 두지 않는다 — 이 스킬은 셸 명령(ffmpeg)과 이미지 판독만 쓰므로 세 런타임에서 절차가 동일하다. 원본은 `codex-personal-skills` 저장소의 `skills/video-to-md/`이며, 각 런타임 스킬 디렉터리로 복사해 쓴다. **스킬 실행 중에 자신이나 다른 스킬 사본을 수정하지 않는다.**

## 이 스킬이 푸는 문제

에이전트는 영상을 재생할 수 없다. 프레임 이미지로 변환해야 읽을 수 있는데, 프레임 판독은 비싸다(720p 한 장 ≈ 1.5k 토큰). 그래서 **아무 프레임이나 많이 뽑는 방식은 실패한다.** 비용은 폭발하는데 정작 중요한 순간은 놓친다.

핵심은 **구조를 먼저 파악하고 그 구조에 맞춰 표본을 뽑는 것**이다. 어디가 변화 구간이고 어디가 반복 구간인지 알면, 판독할 프레임 수를 몇 배로 줄이면서 내용은 더 정확하게 잡을 수 있다.

산출물의 독자는 **영상을 못 보는 다른 에이전트**다. "영상에 대한 감상"이 아니라 **영상을 대체할 수 있는 사실 기록**을 써야 한다. 화면에 뜬 숫자·필드명·버튼 이름을 그대로 옮기는 것이 요약보다 훨씬 가치 있다.

---

## 실행 전제 — 먼저 확인한다

이 스킬은 **셸에서 `ffmpeg`/`ffprobe`를 실행할 수 있어야** 동작한다. 프레임 추출이 전부 여기에 의존하기 때문이다.

```bash
command -v ffprobe ffmpeg || echo "MISSING"
```

- **둘 다 있음** → 아래 절차를 그대로 수행한다.
- **없는데 패키지 매니저를 쓸 수 있음** → 설치는 사용자 환경을 바꾸는 일이므로 **먼저 물어보고** 진행한다(macOS `brew install ffmpeg`, Debian/Ubuntu `apt install ffmpeg`, Windows `winget install Gyan.FFmpeg`).
- **셸 자체가 없는 환경**(파일 실행이 불가능한 채팅 전용 환경 등) → **이 스킬은 수행할 수 없다.** 추측으로 영상 내용을 지어내지 말고, "이 환경에서는 영상을 프레임으로 변환할 수 없어 분석이 불가능하다"고 명확히 말한다. 사용자가 프레임 이미지를 직접 올려준다면 4단계(판독)부터 §산출물 구조까지는 그대로 적용할 수 있다.

오디오 전사 도구(whisper 계열)는 **선택 사항**이다. 없으면 §1의 지침대로 "음성 미확보"로 처리한다.

---

## 절차

### 0. 열기 전에 접근 규칙부터 확인

프로젝트에 파일 열람 규칙이 있으면 **영상을 열기 전에** 먼저 확인한다. macOS에서 Finder 태그로 접근을 통제하는 프로젝트가 흔하다:

```bash
xattr -p com.apple.metadata:_kMDItemUserTags "<video>" 2>&1
mdls -name kMDItemUserTags "<video>"
```

`AGENTS.md` / `CLAUDE.md`에 규칙이 있으면 그것을 따른다. 판별이 실패하면 열지 말고 그 사실을 기록한다. 이미 열어버린 뒤에 확인하면 규칙 위반이므로 순서가 중요하다.

### 1. 메타데이터 — 특히 오디오 유무

```bash
ffprobe -v error -show_format -show_streams "<video>"
```

확인할 것: 재생시간, 해상도, fps, **오디오 스트림 존재 여부**.

오디오 유무는 이후 전략을 완전히 바꾸므로 가장 먼저 확정한다.

- **오디오 없음** → 화면 텍스트가 유일한 정보원이다. 프레임 판독에 전부 투자한다.
- **오디오 있음** → 말이 핵심 정보일 가능성이 높다. 전사를 먼저 시도한다:
  ```bash
  ffmpeg -i "<video>" -vn -ac 1 -ar 16000 audio.wav
  # whisper / mlx_whisper / faster-whisper 등 설치된 도구로 전사
  ```
  전사 도구가 없으면 **없다고 명시하고** 프레임만으로 분석한 뒤, 문서의 "미확인" 항목에 "음성 내용 미확보"를 남긴다. 음성을 못 들었으면서 들은 것처럼 쓰지 않는다.

### 2. 구조 파악 — 장면 전환 지도

```bash
ffmpeg -hide_banner -i "<video>" -vf "select='gt(scene,0.06)',showinfo" \
  -vsync vfr -f null - 2>&1 | grep -o 'pts_time:[0-9.]*'
```

이 출력이 알려주는 것:

- **전환이 몰린 구간** = 화면·주제가 바뀌는 곳. 반드시 판독한다.
- **전환이 없는 긴 구간** = 정적 화면 또는 같은 작업의 반복. 표본 몇 장이면 충분하다. 이 구간의 길이 자체가 중요한 발견인 경우가 많다(예: 4분 영상 중 2분이 단순 반복 입력 = 업무 비효율의 정량 근거).

임계값은 0.06이 화면녹화에 무난하다. 실사 영상은 0.3~0.4로 올린다.

### 3. 프레임 추출 — 파일명에 타임스탬프를 넣는다

번들 스크립트를 쓰면 위 1~3단계가 한 번에 끝난다. **이 SKILL.md와 같은 디렉터리의 `scripts/vidframes.sh`** 를 실행한다:

```bash
# 설치 위치에 의존하지 않고 스킬 디렉터리를 찾는다 (Claude Code / codex / goose 공통)
for d in ~/.claude/skills ~/.codex/skills ~/.config/goose/skills \
         ./.agents/skills ./.claude/skills ./.goose/skills; do
  [ -f "$d/video-to-md/scripts/vidframes.sh" ] && SK="$d/video-to-md" && break
done
bash "${SK:?스크립트 없음 — 아래 -ss 루프를 직접 쓴다}/scripts/vidframes.sh" "<video>" <outdir> [interval]
```

스크립트를 못 찾으면 아래 3단계의 `-ss` 루프를 직접 쓴다. 스크립트는 편의 도구일 뿐이고, **절차 자체는 ffmpeg 명령만으로 완결된다.**

직접 할 경우 **반드시 `-ss`로 시각을 지정해 파일명에 시각을 박는다**:

```bash
for t in $(seq 2 5 262); do
  ffmpeg -v error -ss $t -i "<video>" -frames:v 1 -q:v 2 "<outdir>/$(printf %03d $t)s.jpg" -y
done
```

`fps=1/5` 필터나 `mpdecimate` 중복제거는 편해 보이지만 **출력 파일명이 시각과 대응하지 않는다.** 타임라인을 쓸 수 없게 되어 결국 다시 뽑게 된다. 판독한 내용을 시각에 묶으려면 처음부터 `-ss` 루프로 간다.

**간격 선정** (판독 비용과 직결):

| 영상 길이 | 기본 간격 | 대략 프레임 수 |
|---|---|---|
| ~3분 | 3초 | ~65 |
| 3~7분 | 5초 | 40~80 |
| 7~15분 | 10초 | 40~90 |
| 15~30분 | 20초 | 45~90 |
| 30~60분 | 40초 | 45~90 |
| 60분+ | 60초 + 장면전환 보강 | 60~ |

목표는 **40~90장**이다. 이보다 적으면 조작 단계를 통째로 놓치고, 많으면 비용만 늘고 정확도는 안 오른다. 번들 스크립트가 이 표대로 자동 선택한다.

균등 간격으로 뼈대를 잡고, 2단계에서 찾은 전환 시점 근처만 추가로 뽑아 보강한다.

### 4. 순서대로 판독

프레임을 **시간 순으로** 읽는다. 뒤에서 앞으로 가거나 건너뛰면 인과관계를 놓친다.

각 프레임에서 뽑을 것:
- 화면 이름 / 탭 / 창 제목
- 필드명과 **입력된 값** (값이 핵심이다)
- 버튼·메뉴·드롭다운 선택지
- 상태바, 번호, 날짜, 사용자명
- 직전 프레임 대비 **무엇이 바뀌었는지**

**뽑은 프레임은 전부 읽는다.** 토큰을 아끼려고 "앞뒤가 비슷해 보이니 건너뛰자"고 하면, 건너뛴 그 한 장에 결정적 장면이 들어 있는 경우가 많다. 실제 사례: 5초 간격으로 뽑아놓고 172초와 182초만 읽고 177초를 건너뛰었는데, 그 한 장에 "단가를 수기로 입력 중"인 화면이 있었다. 건너뛴 탓에 "단가는 자동 반영된다"는 **틀린 서술**이 문서에 들어갔다. 간격을 넓게 잡을지언정, 뽑은 것은 읽는다. 부득이 건너뛰면 어느 구간을 안 봤는지 기록한다.

글씨가 작아 안 읽히면 잘라서 확대한다. 이건 자주 필요하다:

```bash
ffmpeg -v error -ss <t> -i "<video>" -frames:v 1 \
  -vf "crop=<w>:<h>:<x>:<y>,scale=<w*3>:<h*3>:flags=lanczos" -q:v 2 zoom.jpg -y
```

작은 숫자, 상태바, 메뉴 목록, 화면 안에 떠 있는 사진/캡처는 거의 항상 확대해야 읽힌다. 흐릿하다고 넘기지 말고 확대해서 확인한다 — 거기에 문서의 핵심 데이터가 있는 경우가 많다.

### 4.5 공백 추적 루프 — 설명되지 않는 변화를 쫓는다

순서대로 읽다 보면 **앞 프레임과 뒤 프레임 사이에 뭔가 일어났는데 그게 뭔지 모르겠는** 지점이 생긴다. 8행이던 표가 7행이 되어 있다, 비어 있던 단가 열이 채워져 있다, 값이 바뀌었는데 바꾸는 장면이 없다.

그 구간만 다시 뽑아서 본다. 균등 샘플링이 구조적으로 놓치는 것을 메우는 방법은 이것뿐이다.

**이건 한 번 훑고 끝나는 단계가 아니라 루프다.** 새로 뽑은 프레임이 또 다른 공백을 만들면 그것도 후보에 넣는다. 실제로 한 단계 더 들어가야 결론이 뒤집히는 경우가 있다:

```
172s·182s 판독 → "단가가 어떻게 채워졌지?" → 177s 추출
     → 1행만 편집 중 → "나머지 6행은?"      → 179.5s 추출
     → 1~6행 완료·7행 편집 중 → "행별 수기 입력" 확정
```

177초에서 멈췄다면 "1행부터 채우기 시작"까지만 알고, 전파 버튼을 썼을 가능성이 남는다. 179.5초가 있어야 확정된다.

#### 무엇이 트리거인가

**"읽은 내용에 설명 안 되는 차이가 있는 구간"이다. "장면전환이 몰린 구간"이 아니다.**

이 둘은 자주 어긋난다. 실측 사례 하나를 그대로 적어둔다 — 4분 22초 화면녹화에서 이 루프로 정정한 사실 3건은 **전부 장면전환이 0개인 구간에서 나왔고**, 반대로 전환이 몰린 구간(초당 3~4회 검출)을 이분해서 얻은 새 사실은 **0건**이었다.

이유는 구조적이다:

- 전환 검출이 잡는 건 탭 전환·창 열림처럼 **화면이 통째로 바뀌고 몇 초씩 지속되는** 변화다. 그건 **균등 샘플링이 이미 잡는다.** 거기에 프레임을 더 쓰는 건 대체로 중복이다.
- 정작 놓치는 건 그리드 한 열이 채워지거나 행 하나가 사라지는 변화다. **픽셀 변화가 작아 전환 검출에 안 걸리고**, 표본 간격 사이에 끝난다. 전환 밀도를 트리거로 쓰면 이런 건 영원히 못 잡는다.

그래서 장면전환 목록은 3단계에서 **구조를 파악하는 용도**로만 쓰고, 이 루프의 트리거로는 쓰지 않는다.

#### 루프 운영

1. 판독하면서 **설명 안 되는 변화**를 목록에 쌓는다. 각 항목에 "이게 풀리면 문서의 어떤 서술이 바뀌는가"를 함께 적는다.
2. 그 영향이 큰 것부터 구간을 이분한다:
   ```bash
   ffmpeg -v error -ss <중간시각> -i "<video>" -frames:v 1 -q:v 2 gap.jpg -y
   ```
3. 새로 읽은 프레임이 만든 공백도 같은 기준으로 목록에 넣는다.
4. 예산이 남아 있고 목록에 "문서를 바꿀 수 있는" 항목이 남아 있으면 2로 돌아간다.

#### 언제 멈추는가

화면녹화는 무한히 잘게 쪼갤 수 있다. 깊이 제한만으로는 부족하고, **두 가지 기준을 함께** 쓴다.

**① 문서 영향 판정 — 이게 주 기준이다.** "이 공백을 풀면 내가 쓸 문장이 달라지는가?"

- 달라진다 → 쫓는다. 특히 **단정해서 쓸 값이 걸린 공백은 반드시** 쫓는다. "이 값은 자동 계산되었다"고 쓰려면 그 사이에 사용자가 버튼을 눌렀는지 확인해야 한다. 확인 없이 쓰면 **문서가 틀리고**, 독자는 영상을 못 보므로 검증할 방법이 없다.
- 안 달라진다 → 버린다. 마우스 이동 경로, 0.3초 떴다 사라진 툴팁, 이미 확립된 패턴의 반복(행별 입력이 확인된 뒤 "3행은 언제 채워졌나")은 쫓지 않는다.

**② 총 예산 — 발산 방지용이다.** 추가 판독은 **1차 표본의 20% 이내**로 잡는다(53장이면 10장 남짓). 깊이가 아니라 총량으로 거는 이유는, 한 공백이 깊게 들어가야 풀리는 경우와 여러 공백이 얕게 풀리는 경우 중 어느 쪽이 나을지 미리 알 수 없기 때문이다.

**못 푼 것은 반드시 남긴다.** 예산이 끝나거나 이분해도 안 잡히면 "미확인"에 **좁혀진 구간과 함께** 적는다 — "27.0~27.4초 사이에 발생, 그 안은 확인 불가". 어디까지 좁혔는지가 정보이고, 예산이 모자랐다는 사실도 정보다. 조용히 지우면 독자는 그 공백의 존재조차 모른다.

### 5. 교차 검증

**이게 이 스킬에서 가장 중요한 단계다.** 판독한 숫자들 사이의 관계를 실제로 계산해 맞는지 확인한다.

- 합계가 항목 합과 맞는가
- 단가 × 수량 = 금액인가
- A 화면의 값이 B 화면의 같은 항목과 일치하는가
- 화면 밖 자료(첨부 이미지, 다른 탭)의 값과 입력값이 일치하는가

효과가 두 가지다. 첫째, **오독을 잡는다**(저해상도에서 8/B, 0/O, 1/l은 자주 헷갈린다). 둘째, **불일치 자체가 발견이 된다.** 예를 들어 원본 자료의 수량과 실제 입력값이 다르면, 그 영상은 실제 업무 처리가 아니라 시연일 가능성이 크다 — 이런 판단은 문서 신뢰도를 크게 좌우하므로 반드시 명시한다.

### 6. 문서 작성

영상 파일과 **같은 이름의 `.md`** 를 같은 폴더에 만든다 (`ERP사용예시1.avi` → `ERP사용예시1.md`). 사용자가 다른 경로를 지정하면 그걸 따른다.

---

## 산출물 구조

아래는 뼈대다. 영상 유형에 맞게 가감하되, **굵게 표시한 것은 빼지 않는다** — 독자가 영상을 못 보는 상황에서 이것들이 없으면 문서를 신뢰할 수 없다.

```markdown
# <파일명> — 영상 내용 분석

> 이 문서는 영상을 직접 볼 수 없는 에이전트가 <파일명>의 내용을 숙지하기 위한 대체 자료다.

## 1. 파일 메타          ← **오디오 유무를 반드시 포함**
## 2. 한 줄 요약          ← **전체를 한 문장으로**
## 3. 등장 요소           ← 시스템/조직/인물/화면 등 고유명사
## 4. 타임라인            ← **시각 + 화면 + 무슨 일이 일어났는지**
## 5. 화면(장면)별 상세    ← 필드 구조, 선택지, 실제 값
## 6. 데이터              ← 표로 옮긴 수치. 검증식도 함께
## 7. 흐름 / 프로세스      ← 단계 간 인과관계
## 8. 도메인 지식          ← 이 영상을 이해하는 데 필요한 배경
## 9. 시사점              ← 관찰된 사실에 근거한 것만
## 10. 확인 상태 구분      ← **확인된 사실 / 추정 / 미확인**
```

### 유형별 강조점

- **업무 시스템 화면녹화**: 5·6·7번이 핵심. 필드명·선택지·자동계산 동작·번호 체계를 그대로 옮긴다. 사용자가 어디서 시간을 많이 쓰는지(2단계의 정적 구간)를 정량으로 기록한다.
- **회의·발표 녹화**: 오디오 전사가 본체. 프레임은 슬라이드·화면공유 캡처용 보조.
- **튜토리얼·데모**: 4·7번 중심. 재현 가능한 단계 순서로 쓴다.
- **실사 영상**: 3·4번 중심. 장면 전환 임계값을 높여 표본을 잡는다.

---

## 판독 정확도 원칙

문서의 가치는 **정확도**에서 나온다. 영상을 못 보는 독자는 이 문서를 검증할 방법이 없으므로, 틀린 단정은 요약이 부실한 것보다 훨씬 해롭다.

**확인된 사실 / 추정 / 미확인을 반드시 분리한다.**

- **확인된 사실**: 화면에서 직접 읽었고, 가능하면 교차 검증까지 통과한 것
- **추정**: 근거는 있으나 화면이 단정하지 않은 것. 근거를 함께 적는다
- **미확인**: 영상에 없거나, 잘렸거나, 판독 실패한 것. **비워두지 말고 없다고 적는다**

특히 이런 것들은 미확인으로 명시한다: 오디오 미전사, 잘린 이미지의 나머지 부분, 클릭했지만 결과만 보이고 과정이 안 보인 팝업, 표본 간격 사이에 지나간 조작.

추측으로 빈칸을 메우지 않는다. "아마 저장했을 것"은 쓰지 않고 "저장 버튼 클릭 직전 프레임과 저장 후 프레임만 확인됨"이라고 쓴다.

---

## 흔한 실패

- **프레임을 너무 많이 뽑는다** — 구조 파악 없이 1초 간격으로 뽑으면 비용만 나가고 정확도는 안 오른다. 2단계를 건너뛰지 않는다.
- **파일명에 시각이 없다** — 타임라인을 못 쓴다. `-ss` 루프로 간다.
- **작은 글씨를 넘긴다** — 상태바·번호·메뉴에 핵심 정보가 있다. 확대해서 읽는다.
- **화면 안의 화면을 무시한다** — 채팅창에 붙은 사진, 열려 있는 다른 앱, 미리보기 창이 영상의 입력 출처인 경우가 많다.
- **요약만 쓰고 값을 안 옮긴다** — 독자에게 필요한 건 "수주를 등록했다"가 아니라 "수주번호 SOZ20260700195, 7행, 합계 10,665,268원"이다.
- **접근 규칙 확인을 나중에 한다** — 여는 순간 이미 늦다. 0단계를 먼저 한다.
- **표본 사이에서 일어난 일을 추론으로 메운다** — "값이 채워졌으니 자동 계산됐겠지"가 가장 흔한 오류다. 4.5단계로 실제로 확인하거나, 확인 못 했다고 적는다.

