# 등록 기반 팩토리 패턴 (Registration-Based Factory Pattern) 설계 ## 📋 **현재 문제점 분석** ### **기존 VideoDecoderFactory의 문제** ```cpp // 현재 VideoDecoderFactory.h - 모든 디코더 헤더를 직접 포함 #include "AV1Decoder.h" #include "MediaFoundationAV1Decoder.h" #include "NVDECAV1Decoder.h" // CUDA/NVDEC 헤더 충돌 가능 #include "AMFAV1Decoder.h" // AMF 헤더 충돌 가능 #include "VPLAV1Decoder.h" // VPL 헤더 충돌 가능 class VideoDecoderFactory { // 새로운 디코더 추가시마다 코드 수정 필요 case DecoderType::NVDEC: return std::make_unique(); case DecoderType::AMF: return std::make_unique(); case DecoderType::VPL: return std::make_unique(); }; ``` ### **핵심 문제들** 1. **개방-폐쇄 원칙 위반**: 새 디코더 추가시 팩토리 클래스 수정 필요 2. **헤더 의존성 충돌**: 서로 다른 SDK 헤더들이 같은 심볼 정의로 충돌 3. **컴파일 시간 증가**: 모든 디코더 헤더가 팩토리에 포함됨 4. **빌드 환경 의존성**: 특정 SDK가 없으면 전체 빌드 실패 ## 🎯 **등록 기반 팩토리 패턴 솔루션** ### **핵심 아이디어** - **등록자(Registrar)**: 각 디코더가 자신을 팩토리에 등록 - **팩토리(Factory)**: 등록된 생성자 함수들을 통해 객체 생성 - **자동 등록**: 디코더 구현 파일에서 자동으로 등록 수행 - **헤더 분리**: 팩토리는 구체 디코더 헤더를 포함하지 않음 ## 🏗️ **단순화된 아키텍처 설계** ### **핵심 원칙** - **복잡한 DecoderRegistry 제거** → VideoDecoderFactory 내부 배열 사용 - **템플릿 클래스 제거** → 간단한 함수 포인터 등록 - **매크로 최소화** → 가독성 있는 등록 함수 사용 ### **1. 단순화된 등록 시스템** ```cpp // VideoDecoderFactory.h - 구체 디코더 헤더 포함 없음! #include "IVideoDecoder.h" #include #include #include namespace VavCore { // 디코더 등록 정보 구조체 struct DecoderRegistration { std::string name; std::string description; int priority; // 0=최고 우선순위 std::function isAvailable; // 가용성 체크 std::function()> creator; // 생성 함수 }; enum class DecoderType { AUTO, // 가장 적합한 디코더 자동 선택 (우선순위 기반) NVDEC, // NVIDIA NVDEC 하드웨어 디코더 강제 사용 VPL, // Intel VPL 하드웨어 디코더 강제 사용 AMF, // AMD AMF 하드웨어 디코더 강제 사용 DAV1D, // dav1d 소프트웨어 디코더 강제 사용 MEDIA_FOUNDATION // Media Foundation 디코더 강제 사용 }; class VideoDecoderFactory { public: // 디코더 생성 static std::unique_ptr CreateDecoder(VideoCodecType codec_type, DecoderType type = DecoderType::AUTO); static std::unique_ptr CreateDecoder(const std::string& decoder_name); // 사용 가능한 디코더 목록 static std::vector GetAvailableDecoders(VideoCodecType codec_type); // 디코더 등록 (각 디코더 cpp에서 호출) static void RegisterAV1Decoder(const DecoderRegistration& registration); static void RegisterVP9Decoder(const DecoderRegistration& registration); // 팩토리 초기화 static void InitializeFactory(); private: // 코덱별 등록된 디코더 배열 static std::vector s_av1_decoders; static std::vector s_vp9_decoders; // 헬퍼 함수 static std::vector& GetDecoderList(VideoCodecType codec_type); static bool IsHardwareDecoder(const std::string& decoder_name); static bool IsSoftwareDecoder(const std::string& decoder_name); }; } // namespace VavCore ``` ### **2. VideoDecoderFactory 구현** ```cpp // VideoDecoderFactory.cpp - 헤더 포함 없음! #include "pch.h" #include "VideoDecoderFactory.h" #include #include namespace VavCore { // 정적 멤버 초기화 std::vector VideoDecoderFactory::s_av1_decoders; std::vector VideoDecoderFactory::s_vp9_decoders; std::unique_ptr VideoDecoderFactory::CreateDecoder(VideoCodecType codec_type, DecoderType type) { auto& decoders = GetDecoderList(codec_type); // 가용성 필터링 std::vector available; for (const auto& decoder : decoders) { if (decoder.isAvailable()) { available.push_back(decoder); } } if (available.empty()) { return nullptr; } // 우선순위 정렬 std::sort(available.begin(), available.end(), [](const auto& a, const auto& b) { return a.priority < b.priority; }); switch (type) { case DecoderType::AUTO: return available[0].creator(); case DecoderType::NVDEC: for (const auto& decoder : available) { if (decoder.name == "nvdec") { return decoder.creator(); } } break; case DecoderType::VPL: for (const auto& decoder : available) { if (decoder.name == "vpl") { return decoder.creator(); } } break; case DecoderType::AMF: for (const auto& decoder : available) { if (decoder.name == "amf") { return decoder.creator(); } } break; case DecoderType::DAV1D: for (const auto& decoder : available) { if (decoder.name == "dav1d") { return decoder.creator(); } } break; case DecoderType::MEDIA_FOUNDATION: for (const auto& decoder : available) { if (decoder.name == "media_foundation") { return decoder.creator(); } } break; } return nullptr; } void VideoDecoderFactory::RegisterAV1Decoder(const DecoderRegistration& registration) { s_av1_decoders.push_back(registration); // 우선순위 순으로 정렬 std::sort(s_av1_decoders.begin(), s_av1_decoders.end(), [](const auto& a, const auto& b) { return a.priority < b.priority; }); std::cout << "[VideoDecoderFactory] Registered AV1 decoder: " << registration.name << " (priority: " << registration.priority << ")" << std::endl; } } // namespace VavCore ``` ### **3. 단순화된 디코더별 자동 등록** #### **AV1Decoder.cpp (dav1d 소프트웨어 디코더)** ```cpp #include "pch.h" #include "AV1Decoder.h" #include "VideoDecoderFactory.h" // AV1Decoder 구현... namespace VavCore { // 자동 등록 함수 void RegisterAV1Decoders() { VideoDecoderFactory::RegisterAV1Decoder({ "dav1d", // 이름 "Software AV1 decoder using dav1d library", // 설명 50, // 우선순위 (중간) []() { return true; }, // 가용성 체크 (항상 사용 가능) []() { return std::make_unique(); } // 생성 함수 }); } // 정적 초기화를 통한 자동 등록 static bool s_av1_registered = (RegisterAV1Decoders(), true); } // namespace VavCore ``` #### **NVDECAV1Decoder.cpp (NVDEC 하드웨어 디코더)** ```cpp #include "pch.h" #include "NVDECAV1Decoder.h" #include "VideoDecoderFactory.h" // NVDECAV1Decoder 구현... namespace VavCore { // 자동 등록 함수 void RegisterNVDECDecoders() { VideoDecoderFactory::RegisterAV1Decoder({ "nvdec", // 이름 "Hardware AV1 decoder using NVIDIA NVDEC", // 설명 10, // 우선순위 (높음) []() { // 가용성 체크 return NVDECAV1Decoder::CheckNVDECAvailability(); }, []() { return std::make_unique(); } // 생성 함수 }); } // 정적 초기화를 통한 자동 등록 static bool s_nvdec_registered = (RegisterNVDECDecoders(), true); } // namespace VavCore ``` #### **VPLAV1Decoder.cpp (Intel VPL 하드웨어 디코더)** ```cpp #include "pch.h" #include "VPLAV1Decoder.h" #include "VideoDecoderFactory.h" // VPLAV1Decoder 구현... namespace VavCore { // 자동 등록 함수 void RegisterVPLDecoders() { VideoDecoderFactory::RegisterAV1Decoder({ "vpl", // 이름 "Hardware AV1 decoder using Intel VPL", // 설명 20, // 우선순위 (높음) []() { // 가용성 체크 return VPLAV1Decoder::CheckVPLSystemAvailability(); }, []() { return std::make_unique(); } // 생성 함수 }); } // 정적 초기화를 통한 자동 등록 static bool s_vpl_registered = (RegisterVPLDecoders(), true); } // namespace VavCore ``` #### **AMFAV1Decoder.cpp (AMD AMF 하드웨어 디코더)** ```cpp #include "pch.h" #include "AMFAV1Decoder.h" #include "VideoDecoderFactory.h" // AMFAV1Decoder 구현... namespace VavCore { // 자동 등록 함수 void RegisterAMFDecoders() { VideoDecoderFactory::RegisterAV1Decoder({ "amf", // 이름 "Hardware AV1 decoder using AMD AMF", // 설명 15, // 우선순위 (높음) []() { // 가용성 체크 return AMFAV1Decoder::IsAMFAvailable(); }, []() { return std::make_unique(); } // 생성 함수 }); } // 정적 초기화를 통한 자동 등록 static bool s_amf_registered = (RegisterAMFDecoders(), true); } // namespace VavCore ``` ## 🔄 **단순화된 사용 예시** ### **기본 사용법** ```cpp // 1. 자동 선택 (가장 적합한 디코더, 우선순위 기반) auto decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AUTO); // 2. NVIDIA NVDEC 하드웨어 디코더 강제 사용 auto nvdecDecoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::NVDEC); // 3. Intel VPL 하드웨어 디코더 강제 사용 auto vplDecoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::VPL); // 4. AMD AMF 하드웨어 디코더 강제 사용 auto amfDecoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::AMF); // 5. dav1d 소프트웨어 디코더 강제 사용 auto dav1dDecoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::DAV1D); // 6. Media Foundation 디코더 강제 사용 auto mfDecoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, DecoderType::MEDIA_FOUNDATION); // 7. 사용 가능한 디코더 목록 조회 auto available = VideoDecoderFactory::GetAvailableDecoders(VideoCodecType::AV1); for (const auto& name : available) { std::cout << "Available AV1 decoder: " << name << std::endl; } ``` ### **WebM 파일 처리 예시** ```cpp // WebM 코덱 ID에서 자동 디코더 생성 std::string codecId = "V_AV01"; // WebM의 AV1 코덱 ID VideoCodecType codecType = VideoDecoderFactory::DetectCodecTypeFromId(codecId); auto decoder = VideoDecoderFactory::CreateDecoder(codecType, DecoderType::AUTO); if (decoder) { std::cout << "Created decoder for: " << codecId << std::endl; } else { std::cout << "No suitable decoder found for: " << codecId << std::endl; } ``` ## 🚀 **단순화된 설계의 장점** ### **1. 개방-폐쇄 원칙 준수** - ✅ **개방**: 새로운 디코더 추가 용이 (각자의 cpp 파일에서 등록) - ✅ **폐쇄**: VideoDecoderFactory 헤더/구현 수정 불필요 ### **2. 헤더 의존성 완전 분리** - ✅ **충돌 제거**: VideoDecoderFactory가 구체 디코더 헤더를 포함하지 않음 - ✅ **빌드 시간 단축**: 불필요한 헤더 컴파일 제거 - ✅ **선택적 빌드**: 특정 SDK 없어도 나머지 디코더는 정상 빌드 ### **3. 구현 단순성** - ✅ **복잡한 DecoderRegistry 제거**: 간단한 std::vector 사용 - ✅ **템플릿/매크로 최소화**: 가독성 높은 함수 기반 등록 - ✅ **디버깅 용이**: 복잡한 싱글톤/템플릿 없이 직관적인 구조 ### **4. 성능 최적화** - ✅ **우선순위 기반 선택**: 시스템 환경에 따른 최적 디코더 자동 선택 - ✅ **가용성 기반 필터링**: 사용 불가능한 디코더 자동 제외 - ✅ **정적 초기화 활용**: 런타임 오버헤드 최소화 ### **5. 유지보수성 향상** - ✅ **관심사 분리**: 각 디코더가 자신의 등록 로직만 관리 - ✅ **코드 가독성**: 복잡한 등록 시스템 없이 명확한 구조 - ✅ **확장성**: 새로운 코덱 타입 추가 시에도 동일 패턴 적용 가능 ## 📋 **단순화된 구현 계획** ### **Phase 1: 단순화된 VideoDecoderFactory 구현** 1. 기존 복잡한 VideoDecoderFactory.h/.cpp 교체 2. `DecoderRegistration` 구조체 기반 등록 시스템 구현 3. 정적 std::vector를 사용한 디코더 저장소 구현 ### **Phase 2: 디코더별 등록 변환** 1. `AV1Decoder.cpp`에 단순화된 등록 로직 추가 2. `NVDECAV1Decoder.cpp`에 등록 로직 추가 3. `VPLAV1Decoder.cpp`에 등록 로직 추가 4. `AMFAV1Decoder.cpp`에 등록 로직 추가 (AMF SDK 사용 가능 시) ### **Phase 3: 빌드 및 테스트** 1. VavCore 라이브러리 빌드 테스트 2. 헤더 의존성 제거 확인 3. 디코더 자동 등록 및 우선순위 동작 검증 ### **Phase 4: 기존 코드와 통합** 1. WebMFileReader에서 새로운 팩토리 사용 확인 2. VideoPlayerControl에서 디코더 생성 로직 업데이트 3. 전체 애플리케이션 통합 테스트 ## 🎯 **단순화된 설계의 결론** **함수 포인터 기반 등록 패턴**을 통해: - ✅ **PIMPL 패턴의 복잡성 없이** 헤더 의존성 문제 완전 해결 - ✅ **개방-폐쇄 원칙 준수**로 확장 가능한 아키텍처 구현 - ✅ **복잡한 싱글톤/템플릿 제거**로 코드 가독성 향상 - ✅ **정적 초기화 활용**으로 성능 최적화 - ✅ **직관적인 등록 시스템**으로 디버깅 및 유지보수 용이 **기존 복잡한 등록 시스템 대비 장점:** - DecoderRegistry 싱글톤 제거 → 간단한 정적 배열 사용 - DecoderRegistrar 템플릿 제거 → 명확한 함수 기반 등록 - 복잡한 매크로 제거 → 가독성 높은 구조체 초기화 방식 - 범용적인 문자열 기반 API 제거 → 타입 안전한 enum 기반 접근법 이 단순화된 설계는 Vav2Player의 디코더 생태계를 더욱 **유연하고 유지보수하기 쉽게** 만들어, 미래의 새로운 디코더 추가나 SDK 변경에도 robust하게 대응할 수 있습니다.