기존 것보다 나쁘지는 않아야 한다 · v1.0.0.2
기존 녹화·녹음 프로그램을 옆에 놓고 이 프로그램에 없는 기능을 하나씩 센다. 열두 가지를 넣고, 그 과정에서 느린 PC 에서만 생기는 결함 하나를 더 잡는다. 기존 프로그램보다 못하지 않은 상태가 이 판의 목표다.
2026. 09. 10
목적
기존 녹화·녹음 프로그램에는 있는데 이 프로그램에는 없는 기능을 세어 채운다. 기존 프로그램보다 못하지 않은 상태를 이 판의 목표로 한다.
계획
- 기존 녹화·녹음 프로그램 셋의 기본 기능을 표로 늘어놓고 빠진 것 표시
- 넣을 것 열둘과 넣지 않을 것 셋을 이유와 함께 정함
- 창 녹화·캡처 제외·미니 막대·초 읽기·자동 정지·클릭 강조·스크린샷·하드웨어 인코더·디스크·파일 크기·최근 목록·비트레이트·프리셋 구현
- enginetest [7] 과 realtest 를 새 기능에 맞게 확장
- wine 에서 Windows Python 시험과 exe 실기
체크리스트 8/10
| 항목 | 상태 | 비고 |
|---|---|---|
| 기능 비교표(18항목) | 완료 | |
| 창 녹화: EnumWindows 목록, 프레임마다 창 위치 따라가기 | 완료 | |
| 자기 창·미니 막대 캡처 제외(SetWindowDisplayAffinity) | 완료 | |
| 미니 제어 막대, 초 읽기, 자동 정지 | 완료 | |
| 클릭 강조, 스크린샷 Ctrl+Alt+S | 완료 | |
| 하드웨어 인코더 자동 탐지(뒤 스레드), 디스크 여유, 파일 크기, 최근 목록, 비트레이트, 프리셋 | 완료 | |
| 결함 수정: 느린 PC 에서 일시정지 직후 프레임 7장 더 들어감 | 완료 | |
| enginetest 7묶음·realtest 클라우드와 wine 전부 통과, exe 실기 | 완료 | |
| 실제 Windows 에서 창 목록·캡처 제외·클릭 강조·하드웨어 인코더 확인 | 미완 | wine 은 반쪽만 보여 줌 |
| 녹화 중 그리기(펜), 웹캠 | 미완 | 다음 판 |
1. 기준
이 판의 기준은 기존 프로그램보다 못하지 않은 것이다. 기존 녹화 프로그램 둘(A 는 유료, B 는 무료 방송용)과 기존 녹음 프로그램 하나의 기본 기능을 표로 늘어놓고, 빠진 것을 하나씩 채웠다. 넣지 않은 것은 이유를 적었다.
| 기능 | 기존 녹화 프로그램 A (유료) |
기존 녹화 프로그램 B (무료) |
기존 녹음 프로그램 A (무료) |
v1.0.0.1 | v1.0.0.2 |
|---|---|---|---|---|---|
| 특정 창 녹화(따라가기) | O | O | – | X | O EnumWindows + 매 프레임 창 위치 |
| 자기 창이 영상에 안 찍힘 | O | O | – | X(트레이로 숨김) | O SetWindowDisplayAffinity |
| 녹화 중 작은 제어 막대 | O | △(독) | – | X | O 미니 막대, 끌어서 이동 |
| 시작 전 초 읽기 | O | X | X | X | O 0·3·5초 |
| 정해진 시간 뒤 자동 정지 | O | X | X | X | O 10~120분 |
| 마우스 클릭 효과 | O | X | – | X | O 노란 고리 |
| 스크린샷 | O | O | – | X | O Ctrl+Alt+S, 같은 이름 규칙 |
| 하드웨어 인코더 | O | O | – | X | O NVENC·QSV·AMF 자동 탐지 |
| 디스크 여유 확인 | O | O | – | X | O 500MB 미만이면 시작 거부 |
| 녹화 중 파일 크기 표시 | O | O | – | X | O |
| 최근 결과 목록 유지 | O | – | O | X(끄면 사라짐) | O 설정에 20개 |
| 소리 비트레이트 | O | O | O | X(160k 고정) | O 96~256k |
| 영역 크기 프리셋 | O | X | – | X | O HD·FHD·480 |
| 버전표시(marker) 파일로 저장 | X | X | △(앱 안) | O | O |
| 화면 녹화 | O | O | X | O | O |
| 음성 녹음 | X | X | O | O | O |
| 웹캠 덧붙이기 | O | O | – | X | X 카메라가 없어 시험할 수 없음 |
| 방송·장면 전환 | X | O | – | X | X 목적 밖 |
| 녹화 중 그리기(펜) | O | X | – | X | X 다음 판 |
2. 창 녹화
원천 선택에 모니터와 영역 다음으로 창을 추가하였다. Windows 의 EnumWindows 로 제목이 있고 보이는 최상위 창을 모으고, DwmGetWindowAttribute(EXTENDED_FRAME_BOUNDS) 로 그림자를 뺀 실제 사각형을 얻는다. 시작할 때 창 크기를 출력 크기로 고정하고, 프레임마다 창의 지금 위치를 다시 물어 그 자리를 찍는다. 인코더는 크기가 바뀌면 안 되므로 창이 작아지면 주변이 함께 찍히고 커지면 왼쪽 위부터 고정 크기만 찍힌다. 창이 화면 밖으로 나가면 사각형을 안으로 밀고, 최소화되거나 닫히면 예외를 내서 VideoWriter 가 직전 프레임을 다시 쓴다.
class FollowSource:
def _place(self):
r = self.provider() # 지금 창 사각형. 없으면 None
if r is None: raise RuntimeError("창이 보이지 않는다")
left = max(b.left, min(r.left, b.left + b.width - self.rect.width)) # 화면 안으로
...

3. 자기 창을 영상에서 빼기와 미니 막대
1판은 녹화가 시작되면 창을 트레이로 숨겼다. 그러면 정지하려고 트레이를 찾아야 한다. 이번에는 SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE) 를 건다. Windows 10 2004 부터 있는 기능으로, 창은 모니터에는 보이지만 어떤 화면 캡처에도 찍히지 않는다. 주 창과 미니 막대 둘 다 이것을 건다. 미니 막대는 시간·파일 크기·일시정지·버전표시·정지·창 보기가 든 작은 막대다. 끌어서 옮길 수 있고 늘 위에 있다.

4. 나머지
- 초 읽기. 시작을 누르면 화면 가운데 큰 숫자가 3·2·1 로 줄고 그 뒤에 시작한다. Esc 로 취소한다. 녹화 전에 창을 정리할 시간을 두기 위한 것이다.
- 자동 정지. 10·30·60·120분 가운데 고른다. 회의 시간이 정해져 있을 때 정지를 잊어도 그 시간에 멈춘다.
- 클릭 강조.
GetAsyncKeyState(VK_LBUTTON)이 눌려 있는 프레임에 커서 끝에 노란 고리(반지름 18, 두께 5)를 알파 합성한다. - 스크린샷. Ctrl+Alt+S 를 누르면 지금 고른 원천을 PNG 한 장으로 저장한다. 녹화 중이 아니어도 되고, 이름 규칙은 같다.
- 하드웨어 인코더.
-encoders목록에 있어도 드라이버가 없으면 못 돈다. 64×64 두 프레임을 실제로 넣어 보고 되는 것을 쓴다. NVENC 는-rc vbr -cq, QSV 는-global_quality, AMF 는-rc cqp. 창이 뜨자마자 뒤에서 확인한다(아래 6절). - 디스크·파일 크기. 저장 폴더 여유가 500MB 미만이면 시작을 거부하고, 2GB 미만이면 노란색으로 표시한다. 녹화 중 임시 파일 크기를 1초마다 표시한다.
- 최근 결과·비트레이트·프리셋. 최근 목록을 설정에 20개까지 저장한다. 소리 비트레이트는 96~256 kbps 에서 고른다. 영역 프리셋은 고른 모니터 가운데에 그 크기를 잡는다.

5. 느린 PC 에서 일시정지 직후 프레임이 더 들어가던 결함
wine 에서 realtest 를 돌리니 일시정지 중에 프레임이 늘지 않는지 보는 항목이 7장 차이로 실패했다. wine 의 화면 캡처는 한 장에 100ms 넘게 걸린다. 캡처 스레드는 늦은 만큼 같은 프레임을 다시 보내 박자를 맞추는데(1판 4-2), 그 채우기 고리가 일시정지 신호를 안 봤다. 일시정지를 누른 뒤에도 밀린 박자를 최대 fps 장까지 채우고 나서야 멈췄다. 빠른 PC 에서는 밀린 박자가 0~1 이라 드러나지 않는다.
for _ in range(fill):
if self._pause_ev.is_set() or self._stop_ev.is_set():
break # 채우다가도 일시정지면 그만
pipe.write(frame); tick += 1
같은 자리에서 하나를 더 정했다. 밀린 박자가 3초(fps × 3)를 넘으면 그 PC 는 이 설정을 못 따라가는 것이다. 무한히 채우면 파일만 커지고 실시간과도 어긋난다. 넘친 만큼은 버리고 시계를 다시 맞추되, ticks_lost 에 세어 두었다가 끝날 때 상태줄에 「PC 가 못 따라가 N초를 놓쳤다. 초당 프레임이나 출력 크기를 낮추면 좋다」고 알린다.
6. 첫 시작이 5초 멈추던 것
하드웨어 인코더 확인은 ffmpeg 를 세 번 띄운다. 처음엔 시작 단추 안에서 했더니 wine 에서 단추가 5초 멈췄고, 초 읽기가 그 뒤에야 시작됐다. 실제 PC 에서도 1~3초는 멈춘다. 창이 뜨자마자 뒤 스레드에서 확인하게 옮기고, 시작 때 아직 안 끝났으면 1초만 기다리고 CPU 인코더로 간다. 다음 시작부터는 결과가 있다.
7. 시험
enginetest [1]~[6] 이전 판 그대로 + [7] 클릭 고리 · 인코더 인수 · 하드웨어 탐지 · 창 따라가기(옮김·화면 밖·사라짐) · 파일 크기 · 96k
클라우드 Linux 전부 통과 / Windows Python(wine) 전부 통과
realtest 스크린샷 → 3초 초 읽기 → 시작 → 미니 막대 → 표식 → 미니 막대로 일시정지·재개 → 자동 정지(1.5초로 앞당김)
→ 결과 검증 → 창 따라가기 3위치 클라우드 전부 통과 / wine 전부 통과
exe wine 에서 스크린샷 단추 → 초 읽기 → 녹화 → 정지. PNG 와 3.03초 MP4

8. 남은 일
- 실제 Windows 에서 창 목록, 캡처 제외, 클릭 강조, 하드웨어 인코더가 잡히는지 확인한다. wine 에서는 넷 다 일부만 동작한다(창 목록 없음, 캡처 제외 무시, 인코더 없음).
- 녹화 중 그리기(펜)와 웹캠은 다음 판에서 다룬다.