Files
dronevideoplayer/PROGRESS.md
minsung 2aae3d1c0d feat: StationOverlay 렌더링 최적화 및 스무딩 적용 close #1
- 텍스트(측점/POI) 전 프레임 사전 계산 Map (requestIdleCallback 백그라운드)
- 드론 데이터 이동 평균 스무딩 (smoothFrame ±N프레임)
- 30fps→60fps 프레임 간 선형 보간 (performance.now() 기반)
- EMA(지수이동평균) 표시 위치 스무딩 (α=0.01 기본값)
- 글씨 2배 크기, bold, strokeText 테두리, 배경 박스 제거
- 카메라 파라미터 패널에 smooth/EMA α 슬라이더 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:11:39 +09:00

12 KiB
Raw Blame History

PROGRESS.md — abcvideo 진행 상태

이 파일은 각 단계의 진행 상태를 기록합니다. 에이전트는 작업 시작/완료 시 반드시 이 파일을 업데이트합니다.


현재 상태 요약

  • 마지막 완료 단계: 검증 (VERIFICATION)
  • 현재 진행 단계: 전체 완료 + 검증 완료
  • 블로커: FFmpeg 미설치 (HLS/프레임 기능은 FFmpeg 설치 후 동작)
  • 검증 결과: VERIFICATION.md 참조 (모든 항목 통과, V3-3 RAF 버그 1건 수정 완료)

단계별 진행 기록

단계 1: 프로젝트 구조 세팅

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • 루트 package.json (npm workspaces)
    • shared/src/types.ts (공유 타입)
    • server/ 스캐폴드 + tsx dev 환경
    • client/ Vite + React 18 + TypeScript + Tailwind
    • storage/ 디렉토리 구조
    • npm install 성공 (514 packages)
    • server TypeScript 컴파일 에러 없음
    • GET /api/health 응답 확인
  • 미완료/이슈:
    • better-sqlite3 ^12.8.0으로 업그레이드 (Node 24 prebuilt binary 문제)
  • 다음 단계 참고:
    • server/package.json에 better-sqlite3 ^12.8.0 사용 중
    • client Vite dev는 아직 미확인 (브라우저 확인 필요)
    • server/src/app.ts는 최소 스캐폴드 — 단계 2에서 확장

단계 2: 백엔드 서버

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • server/src/config.ts — 환경변수 기반 설정
    • server/src/services/ffmpeg.ts — FFprobe/FFmpeg spawn 래퍼 (probeVideo, runFFmpeg, getVideoFps 등)
    • server/src/services/streaming.ts — Range Request 스트리밍 (10MB 청크, 1MB highWaterMark)
    • server/src/services/storage.ts — better-sqlite3 초기화, Annotation CRUD, 임시파일 정리
    • server/src/middleware/security.ts — pathTraversalGuard, validateMimeType, securityHeaders
    • server/src/routes/stream.ts — GET /api/stream/:videoId
    • server/src/routes/hls.ts — POST /convert, GET /status, GET /progress(SSE), GET /index.m3u8, GET /:segment
    • server/src/routes/frame.ts — GET /api/frame/:videoId?time=|frame=
    • server/src/routes/upload.ts — 청크 업로드 (init/chunk/complete/status), @tus/server 대신 자체 구현
    • server/src/routes/meta.ts — GET /api/videos, GET /api/meta/:videoId, DELETE /api/videos/:videoId
    • server/src/routes/annotations.ts — CRUD + export(vtt/srt/json/csv)
    • server/src/app.ts — 전체 통합, 헬스체크, 에러 핸들러
    • server/.env — 환경변수 파일
    • server/tsconfig.json — rootDirs 수정 (shared 타입 접근 허용)
    • GET /api/health, /api/videos, /api/annotations/:videoId 정상 응답 확인
  • 미완료/이슈:
    • @tus/server 2.3.0이 ESM-only("type":"module")라 CommonJS 서버와 호환 불가 → 자체 청크 업로드 구현으로 대체
    • FFmpeg 시스템 PATH 미등록 상태 → HLS 변환/프레임 추출은 FFmpeg 설치 후 동작
  • 다음 단계 참고:
    • 청크 업로드 클라이언트는 POST /api/upload/init → POST /api/upload/chunk (X-Upload-Id, X-Chunk-Index 헤더, application/octet-stream body) → POST /api/upload/complete 순서 사용
    • HLS 변환 완료 후 /api/hls/:videoId/index.m3u8 로 플레이리스트 접근
    • 서버는 포트 3001에서 실행 중

단계 3: 기본 플레이어

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • client/src/types/player.ts — VideoSource, PlayerState 타입
    • client/src/store/playerStore.ts — Zustand 플레이어 상태 스토어
    • client/src/store/annotationStore.ts — 주석 Zustand 스토어
    • client/src/hooks/useVideoPlayer.ts — Video.js 8 초기화, loadLocalFile, loadServerStream, switchToHls
    • client/src/components/player/VideoPlayer.tsx — forwardRef + VideoPlayerHandle API
    • client/src/components/player/HlsConversionStatus.tsx — SSE 진행률 바
    • client/src/components/sidebar/VideoList.tsx — 서버 영상 목록
    • client/src/App.tsx — 전체 레이아웃 통합
    • npm install: video.js@^8.23.0, @videojs/http-streaming, hls.js@^1.6.15, interactjs@^1.10.27, subsrt-ts@^2.0.3
    • TypeScript 에러 없음, 빌드 성공 (dist 1.47MB)
  • 미완료/이슈:
    • interact.js 패키지명 오류 → interactjs (하이픈 없음) 으로 설치
    • 빌드 경고: chunk > 500kB (video.js 특성상 정상, 운영환경 분할 불필요)
  • 다음 단계 참고:
    • VideoPlayer는 forwardRef 사용 — App에서 playerRef.current?.loadServerStream() 호출
    • hls.js backBufferLength: 30 설정 완료
    • MemoOverlay는 interactjs 사용 (import from 'interactjs')

단계 4: 프레임 추출

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • client/src/utils/frameCapture.ts — 단일 Canvas 재사용, captureFrame, downloadDataUrl
    • client/src/components/player/FrameCaptureButton.tsx — Shift+S 캡처 버튼
    • VideoPlayer에 캡처 통합 (getVideoElement → captureFrame → downloadDataUrl)
  • 미완료/이슈: 서버 FFmpeg 정확 추출(로컬 파일 정확 추출 시)은 미구현 — Canvas 즉시 미리보기만 구현
  • 다음 단계 참고: (없음)

단계 5: 단위 이동

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • client/src/hooks/useFrameStep.ts — requestVideoFrameCallback FPS 감지, stepForward/stepBackward
    • client/src/hooks/useKeyboard.ts — CLAUDE.md 키보드 단축키 전체 구현
    • 프레임/초/장면 단위 이동 완성 (Space/←/→/J/L/,/./[/]/F/M/+/-/Shift+S/Shift+M/0-9)
  • 미완료/이슈: (없음)
  • 다음 단계 참고: (없음)

단계 6: 텍스트 오버레이

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • client/src/hooks/useAnnotations.ts — 주석 CRUD API 연동
    • client/src/components/overlay/MemoOverlay.tsx — interactjs 드래그, x%/y% 좌표
    • client/src/components/sidebar/AnnotationPanel.tsx — 자막/메모 탭, 내보내기(VTT/SRT/JSON/CSV)
    • client/src/components/AddAnnotationModal.tsx — 주석 추가 모달
    • client/src/utils/timecode.ts — secondsToTimecode, timecodeToSeconds, frameToSeconds, secondsToFrame
  • 미완료/이슈:
    • WebVTT track 요소를 통한 자막형 렌더링은 미구현 (주석 저장/표시는 완성, track 연동은 단계 7)
  • 다음 단계 참고:
    • 자막형 WebVTT track 연동은 단계 7 UI/UX 통합 시 추가 가능
    • 내보내기는 /api/annotations/:videoId/export?format=vtt|srt|json|csv 백엔드 API 사용

검증 (VERIFICATION)

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • VERIFICATION.md 작성 및 전 항목 검증 실행
    • V1 정적 검증: server/client tsc 에러 없음, 빌드 성공
    • V2 서버 API: 헬스체크/영상목록/업로드/주석 CRUD/내보내기/보안 모두 통과
    • V3 코드 품질: 10/10 통과 (MemoOverlay RAF 버그 발견 및 수정)
    • V4 파일 구조: 19개 필수 파일 전부 존재 확인
  • 수정 사항:
    • VideoPlayerHandlegetVideoElement() 추가 (VideoPlayer.tsx)
    • App.tsx RAF 루프 추가 → MemoOverlay currentTime 60fps 업데이트

기능 확장: 카메라 파라미터 보정 패널 (2026-03-26)

  • 상태: 완료
  • 완료 항목:
    • client/src/utils/geoProjection.ts — CameraParams 인터페이스 추가, projectPoint 시그니처 변경
      • yawOffset(number) → params(CameraParams) 로 통합
      • Roll 회전 수학 추가 (Rodrigues, fwd 축 기준): right_r = right0·cosR up0·sinR
      • 주점 오프셋(cx0, cy0) 핀홀 투영에 적용
      • 초점 배율(focalScale) 적용: f_eff = focalLen × focalScale
      • pxRaw/pyRaw 필드 추가 (클램프 전 원본값, FOV 이탈 감지용)
      • DEFAULT_CAMERA_PARAMS export
    • client/src/components/overlay/StationOverlay.tsx — 파라미터 패널 UI 전면 개편
      • ParamRow 컴포넌트: 슬라이더 + 직접 수치 입력(Enter/blur 커밋) 양방향 동기화
      • 자세 보정 섹션: Yaw(-180~+180°), Pitch(-45~+45°), Roll(-45~+45°)
      • 내부표정 섹션: f×(0.33.0배율), cx₀(-0.5+0.5), cy₀(-0.5~+0.5)
      • 현재 유효값 실시간 표시: yaw_eff, pitch_eff, f_eff(mm), hFOV(°)
      • 측점 Canvas 마커 구현: 다이아몬드 ◆ + 측점명 레이블 + 거리(m)
      • FOV 이탈 측점 → 가장자리 방향 화살표(drawEdgeArrow)
      • POI 마커: + 심볼 + 레이블
      • 지면 가이드선: 측점 → 화면 하단 점선
      • 나침반 HUD: hFOV를 focalScale 반영하여 동적 계산
      • 초기화 버튼, 드론 경로 체크박스
    • 빌드 성공: tsc + vite build 에러 없음 (2026-03-26)
  • 발견 사항:
    • SRT gb_roll=0.0 (전 프레임 고정) → Roll 보정은 이 영상에서 효과 없으나 다른 영상 대비 구조 완성
    • 자기 편각(-8°) 보정이 yawOffset 슬라이더의 주된 용도
    • focalScale로 실효 FOV를 조정할 수 있어 정밀 보정 가능
  • 미완료/이슈:
    • GCP 클릭 기반 자동 Resection 미구현 (yaw/pitch 자동 계산)
    • 파라미터 설정값 영속 저장(localStorage) 미구현

기능 확장: 지리정보 오버레이 + 측점 검증 (2026-03-25)

  • 상태: 완료
  • 완료 항목:
    • server/src/services/geoMatch.ts — 블렌더 방식 월드 ENU 좌표계 구현
      • geoToEnu(): 위경도 → ENU(m), 기준점 위도로 cos(lat) 고정 (전 프레임 일관성)
      • projectEnu(): 상대 ENU 벡터 + 카메라 회전 → 핀홀 투영
      • project3D(): geoToEnu + projectEnu 래퍼, origin 파라미터 지원
      • findFramesForPoi / findPoisForFrame — frames[0]를 월드 원점으로 전달
      • getDroneFrames() 신규 export
    • server/src/routes/geo.ts — yawOffset 쿼리 파라미터, GET /api/geo/frames 엔드포인트
    • client/src/utils/geoProjection.ts — 서버와 동일한 블렌더 방식 ENU 투영, ref 파라미터 추가
    • client/src/components/overlay/StationOverlay.tsx — yaw 보정 슬라이더(-180~+180°), 드론 경로 오버레이, pathFrames[0] 원점 전달
    • client/src/components/geo/StationVerify.tsx — 측점 목록 + 클릭 검증 패널 (신규)
    • client/src/App.tsx — 우측 패널에 "측점" 탭 추가
    • server/client 빌드 모두 에러 없음 확인
  • 발견 사항:
    • cos(lat) 보정을 각 프레임 위도가 아닌 기준점(frame 0) 위도로 고정해야 전 구간 일관성 보장
    • CSV yaw/pitch/roll = 짐벌(카메라) 방향 (pitch=-29.8°는 짐벌 고정 틸트, roll=0은 짐벌 보정)
    • frame 1791 기준 158K300: px=70.1% (사용자 관측 ~73%와 일치)
  • 미완료/이슈:
    • Z값(표고) 미적용 — 측점 z값이 ~0m이라 수직 오차 존재, 실제 표고 데이터 확보 후 보정 필요
    • GCP 캘리브레이션 UI 미구현 (클릭으로 yaw/pitch 오프셋 자동 계산)

지리정보 오버레이 — Python advanced_tuner_v2 포팅 (2026-03-30)

  • 상태: 완료
  • 완료 항목:
    • geoProjection.ts 재구현: R_b2w=Rz(-yaw)*Rx(pitch)*Ry(roll), R_w2c=R_align@R_b2w.T (Python 동치)
    • pitch/roll 절대값 → 오프셋 방식 (Python spn_pitch/roll 기본값 0과 동일)
    • sensorH 기본값 20.25mm (=36×9/16, 16:9 영상 기준, 기존 24mm 수직 스케일 오류 수정)
    • CameraParams에 offX/offY/offZ 추가 (Python off_x/y/z 동치)
    • geoMatch.ts: center.csv 224점 로더 추가 (getCenterlinePoints)
    • GET /api/geo/centerline 엔드포인트 추가
    • StationOverlay: center.csv 중심선 빨간 선분 시각화 (Python 방식), Catmull-Rom next6 스플라인 제거
    • 파라미터 패널: 위치 보정(offX/Y/Z), 센서 크기(senW/H) 슬라이더 추가
    • DEFAULT_CAMERA_PARAMS = Python 기본값 (모든 오프셋 0, focal=24, sensor=36)
  • 다음 단계 참고:
    • off_x/y/z 슬라이더로 GPS 위치 오차 보정 필요
    • swap_xy 옵션 미구현 (Python에는 있음, 필요시 추가)

단계 7: UI/UX 통합

  • 상태: 완료 (2026-03-24)
  • 완료 항목:
    • client/src/components/ErrorBoundary.tsx — React 에러 바운더리 (오류 발생 시 복구 UI)
    • client/src/components/HelpOverlay.tsx — 키보드 단축키 도움말 오버레이
    • client/src/main.tsx — ErrorBoundary로 App 래핑
    • client/src/hooks/useKeyboard.ts — ? 키 (Shift+Slash) → onToggleHelp 콜백 추가
    • client/src/components/player/VideoPlayer.tsx — onToggleHelp prop 수신 및 useKeyboard에 전달
    • client/src/App.tsx — showHelp 상태 + HelpOverlay 렌더링 통합
    • README.md — 프로젝트 설치/실행/단축키/환경변수 문서 작성
    • TypeScript 타입 에러 없음, 프로덕션 빌드 성공 (1,480 kB / gzip 453 kB)
  • 미완료/이슈:
    • 빌드 경고: chunk > 500kB (video.js 특성상 정상)
  • 다음 단계 참고: 전체 7단계 완료