영상에서 ‘그 순간’만 뽑아내기 — FFmpeg Frame Extractor 개발기

영상에서 사진 한 장 뽑으려고, 편집 프로그램을 켜본 적 있나요?

썸네일로 쓸 장면, 자료에 넣을 한 컷, 딥러닝 학습용 이미지 — 영상 속 특정 순간의 프레임이 필요한 때가 의외로 많습니다. 그런데 그때마다 무거운 영상 편집기를 켜고, 타임라인을 헤매고, 내보내기 설정을 만지는 건 너무 번거롭습니다.

FFmpeg Frame Extractor는 딱 그 문제만 해결합니다. 영상을 열고 → 프레임 단위로 넘기며 → 원하는 장면에 마크를 찍고 → 한 번에 고화질 PNG로 저장. 그게 전부입니다.

  • 개발 형태: 1인 개발
  • 기술 스택: Python · PyQt6 · OpenCV · ffmpeg
  • 형태: Windows 데스크톱 앱 (PyInstaller 단일 실행)

메인 화면 — 탐색과 마크 패널

화면 이미지는 실제 코드(PyQt6) 레이아웃을 그대로 재현한 UI 미리보기입니다.

이런 분께 유용합니다

  • 영상에서 썸네일·자료용 한 컷을 자주 뽑는 분
  • 딥러닝/비전 학습용 프레임을 골라 저장해야 하는 분
  • 편집 프로그램은 부담스럽고, 가볍고 정확한 도구가 필요한 분
  • 특정 장면을 화질 손실 없이 이미지로 남기고 싶은 분

주요 기능

🎞️ 프레임 단위 정밀 탐색

  • mp4·avi·mov·mkv·wmv·flv·webm 등 주요 포맷 지원
  • ◀◀ ◀ ▶ ▶▶ 버튼으로 ±1 / ±10 프레임 이동
  • 해상도·fps·길이 등 영상 정보 표시
  • HH:MM:SS.mmm 타임스탬프 + 현재 프레임 번호 실시간 표시

기술 구현 — OpenCV VideoCapture 래퍼(VideoReader)로 임의 프레임에 접근하고, 슬라이더에 50ms 디바운스를 걸어 빠르게 드래그해도 끊김을 줄였습니다.

⭐ 마크 & 썸네일 관리

  • 「마크 추가 ★」로 현재 프레임을 썸네일로 보관
  • 썸네일 클릭 → 해당 프레임으로 즉시 이동
  • 썸네일 더블클릭 → 마크 삭제, 「전체 삭제」도 지원
  • 프레임 번호 기준 자동 정렬, 중복 마크 방지

기술 구현 — 마크별 RGB 썸네일을 메모리에 보관해 재추출 없이 미리보기를 제공하고, 저장 버튼이 「N장 저장하기」로 실시간 갱신됩니다.

🖼️ 고화질 PNG 일괄 추출

  • 마크한 모든 프레임을 PNG로 한 번에 저장
  • 출력 폴더 선택(기본값: 영상 파일과 같은 폴더)
  • {영상명}_frame_0375.png 형식의 자동 파일명
  • 완료 후 결과 폴더 자동 열기

기술 구현 — 추출은 ffmpeg -ss 시킹 + -frames:v 1 -q:v 1 옵션으로 최고 화질을 보장합니다.

⚡ 멈추지 않는 UI

  • 여러 장 추출 시 진행률 다이얼로그 + 취소 지원
  • 추출 작업이 메인 화면을 멈추게 하지 않음

기술 구현QThread로 ffmpeg 작업을 분리하고 시그널로 진행률을 전달합니다. Windows cp949 환경에서도 ffmpeg 로그를 UTF-8로 안전하게 처리합니다.

추출 진행률 다이얼로그

동작 흐름

  1. 영상 열기 — 파일 선택 시 OpenCV가 메타데이터를 읽고 첫 프레임을 미리보기
  2. 프레임 탐색 — 슬라이더·점프 버튼으로 원하는 순간까지 프레임 단위 이동
  3. 마크 찍기 — 마음에 드는 프레임을 썸네일로 모아 목록 구성
  4. 일괄 저장 — ffmpeg이 백그라운드에서 고화질 PNG로 한 번에 추출

시작 화면 — 영상 열기 전

설계 포인트 — “미리보기는 빠르게, 추출은 정확하게”

OpenCV는 임의 프레임 접근이 빨라 탐색·미리보기에 적합하지만, 코덱에 따라 색·정밀도가 미묘하게 달라질 수 있습니다. 그래서 최종 추출은 ffmpeg에 맡겨 원본 화질을 그대로 보존했습니다. 핵심은 프레임 번호를 ffmpeg이 이해하는 타임스탬프로 정확히 변환하는 것입니다.

# app/utils/time_format.py — 프레임 번호 → ffmpeg 타임스탬프
def frame_to_timestamp(frame_index, fps):
    total_seconds = frame_index / fps
    h = int(total_seconds // 3600)
    m = int((total_seconds % 3600) // 60)
    s = total_seconds % 60
    return f"{h:02d}:{m:02d}:{s:06.3f}"   # 예) 00:00:12.512

이 변환값을 ffmpeg -ss에 넘기고 한 장을 무손실에 가깝게 뽑아냅니다. 추출·변환 로직은 pytest로 검증합니다(test_extractor, test_time_format, test_video_reader).

다운로드 및 설치

Windows용 실행 파일을 준비했습니다. 무설치(압축 해제 후 바로 실행) 버전입니다. 아래 순서대로 진행하세요.

1. ffmpeg 먼저 설치 (필수)

이 앱은 실제 프레임 추출을 ffmpeg에 맡깁니다. ffmpeg이 시스템에 없으면 실행 시 안내 메시지가 뜨고 종료됩니다.

  • ffmpeg 공식 다운로드: https://ffmpeg.org/download.html
  • 압축을 푼 뒤 ffmpeg.exe가 들어 있는 bin 폴더를 시스템 환경변수 PATH에 추가
  • 확인: 명령 프롬프트에서 ffmpeg -version 입력 시 버전 정보가 나오면 정상

2. 앱 다운로드 & 실행

처음 실행 시 Windows SmartScreen 경고가 뜨면 [추가 정보] → [실행] 을 누르세요. (개인이 빌드한 미서명 앱이라 표시되는 정상적인 경고입니다.)

3. 사용법

  1. 파일 열기 — 프레임을 뽑을 영상을 선택합니다.
  2. 슬라이더와 ◀◀ ◀ ▶ ▶▶ 버튼으로 원하는 프레임까지 탐색합니다.
  3. 마크 추가 ★ — 저장하고 싶은 프레임을 썸네일로 모읍니다. (썸네일 클릭=이동, 더블클릭=삭제)
  4. 필요하면 출력 폴더를 바꿉니다. (기본값: 영상과 같은 폴더)
  5. N장 저장하기 — 마크한 프레임이 고화질 PNG로 저장되고, 저장된 폴더가 자동으로 열립니다.

기술 스택

구분 기술
UI PyQt6, QThread, QSlider/QGridLayout
Core OpenCV, ffmpeg(subprocess), NumPy
Build / Test PyInstaller, pytest, Python 3

무거운 편집기 대신, 영상에서 그 순간만 가볍고 정확하게. FFmpeg Frame Extractor였습니다.

  • 개발: 배성원 (ggoomter@gmail.com)

댓글 남기기