312 lines
9.9 KiB
Markdown
312 lines
9.9 KiB
Markdown
# 🔥 MAJOR REFACTORING GUIDE - 기술 부채 제거 및 코드 간소화
|
|
|
|
**⚠️ CRITICAL: 이 문서는 현재 진행 중인 대규모 리팩토링의 핵심 가이드입니다.**
|
|
**AI 토큰 절약 및 작업 연속성을 위해 반드시 읽고 따라야 합니다.**
|
|
|
|
---
|
|
|
|
## 🎯 **리팩토링 목표**
|
|
|
|
### **근본 문제 인식**
|
|
현재 codebase는 **"방어적 코딩"**으로 증상만 치료하고 있습니다:
|
|
- ResourceBarrier NULL 포인터 → NULL 체크 추가 (❌ 증상 치료)
|
|
- GPU 리소스 생성 실패 → 더 많은 fallback 로직 (❌ 복잡도 증가)
|
|
- 초기화 순서 문제 → 더 많은 상태 체크 (❌ 기술 부채 증가)
|
|
|
|
### **해결 철학: "삭제 후 올바른 재설계" (Delete & Redesign Properly)**
|
|
> **"잘못된 고성능 구현" < "올바른 설계 기반 구현"**
|
|
|
|
**현재 파이프라인 문제점:**
|
|
- **과도한 추상화**: 3단계 복잡한 파이프라인으로 성능 저하
|
|
- **잘못된 리소스 관리**: NULL placeholder로 인한 크래시 다발
|
|
- **역효과적 멀티스레드**: 오버헤드 > 실제 성능 향상
|
|
- **디버깅 불가능**: 복잡한 상태 머신으로 문제 추적 불가
|
|
|
|
**목표:**
|
|
1. **즉시 목표**: 안정적인 CPU 기반 재생 (6800 → 800 라인)
|
|
2. **최종 목표**: 올바른 GPU 파이프라인 재설계 (단순하지만 효율적)
|
|
|
|
---
|
|
|
|
## 📋 **단계별 실행 계획**
|
|
|
|
### **🎯 전체 로드맵**
|
|
|
|
#### **1단계: 잘못된 파이프라인 제거** (현재 진행 중)
|
|
- 복잡한 멀티스레드 파이프라인 삭제
|
|
- 안정적인 CPU 기반 재생 확보
|
|
|
|
#### **2단계: 올바른 GPU 파이프라인 재설계** (향후)
|
|
```cpp
|
|
// 새로운 단순 설계
|
|
CPU Thread: VideoPacket → AV1Decode → YUV Frame
|
|
↓ (Zero-copy handoff)
|
|
GPU Thread: YUV Frame → D3D12 Upload → YUV→RGB Shader → Screen
|
|
```
|
|
|
|
#### **3단계: 점진적 최적화** (최종)
|
|
- 이중 버퍼링으로 CPU-GPU 병렬화
|
|
- 프로파일링 기반 성능 튜닝
|
|
|
|
---
|
|
|
|
### **🗑️ Phase 1: 잘못된 파이프라인 완전 제거**
|
|
|
|
#### **1.1 제거 대상 파일들 (즉시 삭제)**
|
|
```bash
|
|
# Pipeline 디렉토리 전체 제거
|
|
rm -rf src/Pipeline/ThreadedDecoder.*
|
|
rm -rf src/Pipeline/OverlappedProcessor.*
|
|
rm -rf src/Pipeline/DependencyScheduler.*
|
|
|
|
# 복잡한 GPU 관리 제거
|
|
rm -rf src/Rendering/CommandListPool.*
|
|
rm -rf src/Rendering/DirectTextureAllocator.*
|
|
|
|
# 사용하지 않는 유틸리티 제거
|
|
rm -rf src/Common/PacketPool.*
|
|
rm -rf src/Common/FramePool.*
|
|
```
|
|
|
|
#### **1.2 VideoPlayerControl.xaml.h 단순화**
|
|
```cpp
|
|
// 제거할 복잡한 멤버들
|
|
❌ std::unique_ptr<::Vav2Player::ThreadedDecoder> m_threadedDecoder;
|
|
❌ std::unique_ptr<::Vav2Player::OverlappedProcessor> m_overlappedProcessor;
|
|
❌ std::shared_ptr<::Vav2Player::DependencyScheduler> m_dependencyScheduler;
|
|
❌ std::shared_ptr<::Vav2Player::FrameDependencyScheduler> m_frameScheduler;
|
|
❌ bool m_useMultiThreadedDecoding = true;
|
|
❌ bool m_useOverlappedPipeline = true;
|
|
❌ bool m_useDependencyScheduling = true;
|
|
|
|
// 유지할 핵심 멤버들
|
|
✅ std::unique_ptr<WebMFileReader> m_fileReader;
|
|
✅ std::unique_ptr<IVideoDecoder> m_decoder;
|
|
✅ std::unique_ptr<D3D12VideoRenderer> m_d3d12Renderer; // 선택적
|
|
```
|
|
|
|
#### **1.3 제거할 복잡한 메서드들**
|
|
```cpp
|
|
// VideoPlayerControl.xaml.cpp에서 완전 삭제
|
|
❌ void InitializeThreadedDecoder();
|
|
❌ void ShutdownThreadedDecoder();
|
|
❌ void InitializeOverlappedProcessor();
|
|
❌ void ShutdownOverlappedProcessor();
|
|
❌ void InitializeDependencyScheduler();
|
|
❌ void ShutdownDependencyScheduler();
|
|
❌ void ProcessSingleFrameThreaded();
|
|
❌ void ProcessSingleFrameOverlapped();
|
|
❌ void ProcessSingleFrameScheduled();
|
|
❌ bool SubmitPacketForDecoding();
|
|
❌ bool SubmitPacketForOverlappedProcessing();
|
|
❌ bool SubmitFrameForScheduledProcessing();
|
|
```
|
|
|
|
### **🔧 Phase 2: 단순 처리 경로로 통합**
|
|
|
|
#### **2.1 ProcessSingleFrame() 대폭 단순화**
|
|
```cpp
|
|
// BEFORE: 1000+ 라인의 복잡한 분기 처리
|
|
void ProcessSingleFrame() {
|
|
if (m_useDependencyScheduling && m_frameScheduler) {
|
|
ProcessSingleFrameScheduled();
|
|
} else if (m_useOverlappedPipeline && m_overlappedProcessor) {
|
|
ProcessSingleFrameOverlapped();
|
|
} else if (m_useMultiThreadedDecoding && m_threadedDecoder) {
|
|
ProcessSingleFrameThreaded();
|
|
} else {
|
|
ProcessSingleFrameLegacy();
|
|
}
|
|
}
|
|
|
|
// AFTER: 10라인의 단순 선형 처리
|
|
void ProcessSingleFrame() {
|
|
VideoPacket packet;
|
|
if (!m_fileReader->ReadNextPacket(packet)) return;
|
|
|
|
VideoFrame frame;
|
|
if (!m_decoder->DecodeFrame(packet, frame)) return;
|
|
|
|
RenderFrameToScreen(frame); // 단일 렌더링 경로
|
|
}
|
|
```
|
|
|
|
#### **2.2 RenderFrameToScreen() 단순화**
|
|
```cpp
|
|
void RenderFrameToScreen(const VideoFrame& frame) {
|
|
// GPU 렌더링 시도 (선택적)
|
|
if (m_useHardwareRendering && m_d3d12Renderer && m_d3d12Renderer->IsInitialized()) {
|
|
if (m_d3d12Renderer->TryRenderFrame(frame)) {
|
|
return; // 성공하면 완료
|
|
}
|
|
}
|
|
|
|
// CPU 렌더링 (항상 동작하는 fallback)
|
|
RenderFrameSoftware(frame);
|
|
}
|
|
```
|
|
|
|
### **🧹 Phase 3: 프로젝트 파일 정리**
|
|
|
|
#### **3.1 Vav2Player.vcxproj 정리**
|
|
```xml
|
|
<!-- 제거할 파일 참조들 -->
|
|
❌ <ClCompile Include="src\Pipeline\ThreadedDecoder.cpp" />
|
|
❌ <ClCompile Include="src\Pipeline\OverlappedProcessor.cpp" />
|
|
❌ <ClCompile Include="src\Pipeline\DependencyScheduler.cpp" />
|
|
❌ <ClCompile Include="src\Rendering\CommandListPool.cpp" />
|
|
❌ <ClCompile Include="src\Common\PacketPool.cpp" />
|
|
❌ <ClCompile Include="src\Common\FramePool.cpp" />
|
|
|
|
<!-- 유지할 핵심 파일들 -->
|
|
✅ <ClCompile Include="src\FileIO\WebMFileReader.cpp" />
|
|
✅ <ClCompile Include="src\Decoder\AV1Decoder.cpp" />
|
|
✅ <ClCompile Include="src\Decoder\MediaFoundationAV1Decoder.cpp" />
|
|
✅ <ClCompile Include="src\Rendering\D3D12VideoRenderer.cpp" />
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 **단계별 아키텍처 목표**
|
|
|
|
### **Phase 1 완료 후: 단순 안정화 아키텍처**
|
|
```
|
|
VideoPlayerControl
|
|
├── WebMFileReader (파일 파싱)
|
|
├── IVideoDecoder (AV1 디코딩)
|
|
└── SoftwareRenderer (CPU 렌더링, 100% 안정)
|
|
```
|
|
|
|
### **Phase 2 목표: 올바른 GPU 파이프라인**
|
|
```
|
|
VideoPlayerControl
|
|
├── WebMFileReader (파일 파싱)
|
|
├── IVideoDecoder (AV1 디코딩)
|
|
├── GPUTextureUploader (효율적 GPU 업로드)
|
|
├── YUVToRGBConverter (GPU 셰이더)
|
|
└── D3D12Presenter (화면 출력)
|
|
```
|
|
|
|
### **단계별 데이터 플로우**
|
|
```
|
|
Phase 1: WebM → Packet → Frame → CPU Render → Screen
|
|
Phase 2: WebM → Packet → Frame → GPU Pipeline → Screen
|
|
↓
|
|
(Zero-copy, 단순 병렬)
|
|
```
|
|
|
|
### **코드 크기 목표**
|
|
| 컴포넌트 | 현재 | 목표 | 감소율 |
|
|
|----------|------|------|--------|
|
|
| VideoPlayerControl.xaml.cpp | 2500줄 | 400줄 | -84% |
|
|
| Pipeline/* | 3000줄 | 0줄 | -100% |
|
|
| Rendering/* | 1500줄 | 800줄 | -47% |
|
|
| **전체** | **7000줄** | **1200줄** | **-83%** |
|
|
|
|
---
|
|
|
|
## ⚠️ **중요한 설계 원칙**
|
|
|
|
### **1. 단순성 우선 (Simplicity First)**
|
|
- **복잡한 최적화 < 단순한 동작**
|
|
- **멀티스레드 < 단일스레드 + 빠른 디코더**
|
|
- **GPU 파이프라인 < CPU 렌더링 + 선택적 GPU**
|
|
|
|
### **2. 확실성 우선 (Reliability First)**
|
|
- **100% 동작하는 기본 기능 > 50% 동작하는 고급 기능**
|
|
- **NULL 체크보다 NULL 생성 방지**
|
|
- **방어 코딩보다 원인 제거**
|
|
|
|
### **3. 유지보수성 우선 (Maintainability First)**
|
|
- **선형 처리 경로 > 복잡한 상태 머신**
|
|
- **명확한 에러 처리 > 복잡한 fallback**
|
|
- **적은 코드 > 많은 기능**
|
|
|
|
---
|
|
|
|
## 🚨 **작업 중 주의사항**
|
|
|
|
### **절대 하지 말 것**
|
|
❌ **방어 코딩 추가**: NULL 체크, try-catch 남발
|
|
❌ **기능 추가**: 새로운 파이프라인이나 최적화
|
|
❌ **점진적 수정**: 기존 복잡한 코드를 조금씩 고치기
|
|
|
|
### **반드시 할 것**
|
|
✅ **코드 삭제**: 의심스러우면 삭제
|
|
✅ **단순화**: 복잡한 분기를 선형 처리로
|
|
✅ **테스트**: 각 단계마다 기본 동작 확인
|
|
|
|
---
|
|
|
|
## 📝 **진행 상황 체크리스트**
|
|
|
|
### **Phase 1: 파이프라인 제거**
|
|
- [ ] ThreadedDecoder.* 삭제
|
|
- [ ] OverlappedProcessor.* 삭제
|
|
- [ ] DependencyScheduler.* 삭제
|
|
- [ ] CommandListPool.* 삭제
|
|
- [ ] VideoPlayerControl.xaml.h 멤버 정리
|
|
- [ ] VideoPlayerControl.xaml.cpp 메서드 정리
|
|
|
|
### **Phase 2: 로직 단순화**
|
|
- [ ] ProcessSingleFrame() 단순화 (1000줄→10줄)
|
|
- [ ] RenderFrameToScreen() 단순화
|
|
- [ ] LoadVideo() 초기화 로직 단순화
|
|
- [ ] 에러 처리 단순화
|
|
|
|
### **Phase 3: 프로젝트 정리**
|
|
- [ ] .vcxproj 파일 정리
|
|
- [ ] 빌드 테스트
|
|
- [ ] 기본 동작 테스트 (비디오 재생)
|
|
- [ ] 코드 라인 수 측정
|
|
|
|
---
|
|
|
|
## 🔄 **중간 중단 시 재시작 가이드**
|
|
|
|
### **상황 파악 질문**
|
|
1. "현재 어느 Phase까지 완료되었나?"
|
|
2. "빌드가 성공하는가?"
|
|
3. "기본 비디오 재생이 동작하는가?"
|
|
|
|
### **빠른 재시작 명령어**
|
|
```bash
|
|
# 1. 현재 상태 확인
|
|
find src/ -name "*.cpp" | grep -E "(Threaded|Overlapped|Dependency)" | wc -l
|
|
|
|
# 2. 빌드 테스트
|
|
cd "D:/Project/video-av1/vav2/Vav2Player/Vav2Player"
|
|
MSBuild Vav2Player.vcxproj //p:Configuration=Debug //p:Platform=x64 //v:minimal
|
|
|
|
# 3. 헤드리스 테스트
|
|
cd "x64/Debug/Headless"
|
|
./Vav2PlayerHeadless.exe "D:/Project/video-av1/sample/simple_test.webm"
|
|
```
|
|
|
|
### **우선순위 복구 순서**
|
|
1. **빌드 수정** (컴파일 에러 해결)
|
|
2. **기본 동작 복구** (ProcessSingleFrame 단순화)
|
|
3. **불필요한 코드 삭제** (Phase 1 계속)
|
|
|
|
---
|
|
|
|
## 💡 **성공 지표**
|
|
|
|
### **정량적 지표**
|
|
- 전체 코드 라인 수: < 1500줄
|
|
- 빌드 시간: < 30초
|
|
- 메모리 사용량: < 100MB
|
|
- 비디오 재생 성공률: 100%
|
|
|
|
### **정성적 지표**
|
|
- 코드 이해하기 쉬움
|
|
- 디버깅 시간 단축
|
|
- 새 기능 추가 용이성
|
|
- 크래시 발생률 0%
|
|
|
|
---
|
|
|
|
**⚡ 핵심 메시지: "삭제가 최고의 디버깅이다"**
|
|
|
|
*문서 작성일: 2025-09-21*
|
|
*최종 업데이트: 진행 중* |