# 적응형 품질 제어 설계 문서 ## 📋 개요 이 문서는 기존의 **프레임 스킵 방식을 대체하는 적응형 품질 제어 시스템**의 설계와 구현을 다룹니다. 이 시스템은 **디코더 독립적**으로 설계되어 NVDEC, dav1d, MediaFoundation 등 모든 비디오 디코더에 적용할 수 있습니다. --- ## 🎯 문제 정의 ### 기존 프레임 스킵 방식의 문제점 - **시각적 불연속성**: 비디오 타임라인에서 급작스러운 점프 발생 - **오디오-비디오 비동기화**: 오디오는 계속 진행되는데 비디오 프레임이 누락됨 - **사용자 경험 저하**: 성능 병목 구간에서 끊기는 재생 - **정보 손실**: 완전한 프레임이 폐기되어 장면 맥락 상실 ### 제안하는 해결책: 적응형 품질 제어 - **연속적 재생**: 모든 프레임을 디코딩하고 표시 - **동적 해상도 조정**: 성능에 따라 해상도를 자동으로 조정 - **부드러운 품질 저하**: 프레임 드롭 대신 점진적인 품질 감소 - **시스템 적응**: 하드웨어 성능에 맞춰 자동 조정 --- ## 🏗️ 아키텍처 설계 ### 핵심 구성요소 ```mermaid graph TD A[성능 모니터] --> B[품질 분석기] B --> C[해상도 계산기] C --> D[디코더 재설정] D --> E[프레임 출력] E --> F[렌더링 타이머] F --> A G[사용자 설정] --> B H[시스템 리소스] --> A ``` ### 품질 레벨 시스템 | 레벨 | 해상도 비율 | 사용 시나리오 | 성능 목표 | |------|------------|-------------|----------| | **ULTRA** | 100% (원본) | 고사양 시스템 | 목표 프레임 시간의 80% 미만 | | **HIGH** | 75% | 균형잡힌 성능 | 목표 프레임 시간의 80-100% | | **MEDIUM** | 50% | 중간 사양 시스템 | 목표 프레임 시간의 100-120% | | **LOW** | 35% | 저사양 시스템 | 목표 프레임 시간의 120-150% | | **MINIMUM** | 25% | 긴급 대체 | 목표 프레임 시간의 150% 초과 | --- ## 🔧 구현 프레임워크 ### 1. 기본 인터페이스 설계 ```cpp // 범용 적응형 디코더 인터페이스 class IAdaptiveDecoder { public: // 핵심 적응형 기능 virtual bool SetQualityLevel(QualityLevel level) = 0; virtual QualityLevel GetCurrentQualityLevel() const = 0; virtual bool EnableAdaptiveMode(bool enable) = 0; // 성능 모니터링 virtual void UpdatePerformanceMetrics(double decode_time, double render_time) = 0; virtual PerformanceMetrics GetPerformanceMetrics() const = 0; // 설정 관리 virtual void SetAdaptiveConfig(const AdaptiveConfig& config) = 0; virtual void SetTargetFrameRate(double fps) = 0; // 수동 제어 virtual void ForceQualityAdjustment() = 0; virtual bool SupportsResolutionChange() const = 0; }; ``` ### 2. 설정 시스템 ```cpp struct AdaptiveConfig { // 성능 임계값 (밀리초) double target_frame_time_ms = 33.33; // 30 FPS 목표 double critical_frame_time_ms = 50.0; // 20 FPS 임계점 // 품질 조정 임계값 double quality_up_threshold = 0.8; // 목표의 80% 미만일 때 품질 향상 double quality_down_threshold = 1.2; // 목표의 120% 초과일 때 품질 저하 // 안정성 제어 uint32_t stable_frames_required = 30; // 조정 전 대기 프레임 수 uint32_t max_quality_changes_per_sec = 2; // 초당 최대 품질 변경 횟수 // 기능 토글 bool enable_dynamic_resolution = true; bool enable_memory_optimization = true; bool enable_skip_non_reference = true; // 디코더별 설정 std::unordered_map decoder_specific; }; ``` ### 3. 성능 모니터링 시스템 ```cpp struct PerformanceMetrics { // 타이밍 지표 double avg_decode_time_ms = 0.0; double avg_render_time_ms = 0.0; double total_frame_time_ms = 0.0; // 시스템 지표 double cpu_usage_percent = 0.0; double gpu_usage_percent = 0.0; size_t available_memory_mb = 0; // 품질 지표 uint64_t frames_decoded = 0; uint64_t quality_adjustments = 0; QualityLevel current_quality = QualityLevel::ULTRA; // 타임스탬프 std::chrono::steady_clock::time_point last_update; std::chrono::steady_clock::time_point session_start; }; ``` --- ## 🎮 디코더별 구체적 구현 ### 1. NVDEC 구현 ```cpp class AdaptiveNVDECDecoder : public NVDECAV1Decoder, public IAdaptiveDecoder { private: bool ReconfigureDecoder(uint32_t newWidth, uint32_t newHeight) override { // NVDEC의 cuvidReconfigureDecoder를 사용한 동적 해상도 변경 CUVIDDECODECREATEINFO newCreateInfo = m_createInfo; newCreateInfo.ulWidth = newWidth; newCreateInfo.ulHeight = newHeight; newCreateInfo.ulTargetWidth = newWidth; newCreateInfo.ulTargetHeight = newHeight; CUresult result = cuvidReconfigureDecoder(m_decoder, &newCreateInfo); return (result == CUDA_SUCCESS); } bool SupportsResolutionChange() const override { return true; // NVDEC은 런타임 재설정 지원 } }; ``` **NVDEC의 장점:** - ✅ 네이티브 `cuvidReconfigureDecoder()` API 제공 - ✅ 하드웨어 가속 스케일링 - ✅ GPU 메모리 최적화 - ✅ 실시간 포스트 프로세싱 ### 2. dav1d 구현 ```cpp class Adaptivedav1dDecoder : public AV1Decoder, public IAdaptiveDecoder { private: bool ReconfigureDecoder(uint32_t newWidth, uint32_t newHeight) override { // dav1d는 런타임 재설정을 지원하지 않음 // 디코딩 후 스케일링 방식 사용 m_targetWidth = newWidth; m_targetHeight = newHeight; m_needsScaling = (newWidth != m_originalWidth || newHeight != m_originalHeight); return true; } bool PostProcessFrame(VideoFrame& frame) { if (m_needsScaling) { return ScaleFrame(frame, m_targetWidth, m_targetHeight); } return true; } bool SupportsResolutionChange() const override { return false; // 포스트 프로세싱 스케일링 필요 } }; ``` **dav1d 접근법:** - ⚠️ 네이티브 런타임 재설정 불가 - ✅ 디코딩 후 CPU/GPU 스케일링 - ✅ 스케일링 알고리즘을 통한 품질 제어 - ✅ 더 작은 출력 프레임으로 메모리 절약 ### 3. MediaFoundation 구현 ```cpp class AdaptiveMediaFoundationDecoder : public MediaFoundationAV1Decoder, public IAdaptiveDecoder { private: bool ReconfigureDecoder(uint32_t newWidth, uint32_t newHeight) override { // MediaFoundation 방식: 출력 타입 재설정 if (m_transform) { return SetOutputMediaType(newWidth, newHeight); } return false; } bool SetOutputMediaType(uint32_t width, uint32_t height) { // 다른 해상도에 대한 MFT 출력 설정 ComPtr outputType; HRESULT hr = MFCreateMediaType(&outputType); // ... width/height 설정 ... return SUCCEEDED(m_transform->SetOutputType(0, outputType.Get(), 0)); } bool SupportsResolutionChange() const override { return true; // MFT는 출력 타입 변경 지원 } }; ``` **MediaFoundation 접근법:** - ✅ 출력 타입 재설정 - ✅ 하드웨어 가속 스케일링 (GPU 종속적) - ✅ Windows 그래픽 파이프라인과 통합 - ⚠️ 플랫폼 특정적 (Windows 전용) --- ## 🚀 범용 적응형 알고리즘 ### 핵심 적응형 로직 ```cpp class AdaptiveController { public: void AnalyzeAndAdjust(IAdaptiveDecoder* decoder, const PerformanceMetrics& metrics) { double totalFrameTime = metrics.avg_decode_time_ms + metrics.avg_render_time_ms; double targetTime = m_config.target_frame_time_ms; // 성능 비율 계산 double ratio = totalFrameTime / targetTime; // 최적 품질 레벨 결정 QualityLevel optimalQuality = CalculateOptimalQuality(ratio); // 진동 방지를 위한 히스테리시스 적용 if (ShouldAdjustQuality(optimalQuality, metrics)) { decoder->SetQualityLevel(optimalQuality); LogQualityChange(optimalQuality, ratio); } } private: QualityLevel CalculateOptimalQuality(double performanceRatio) { if (performanceRatio > 2.0) return QualityLevel::MINIMUM; if (performanceRatio > 1.5) return QualityLevel::LOW; if (performanceRatio > 1.2) return QualityLevel::MEDIUM; if (performanceRatio > 1.0) return QualityLevel::HIGH; return QualityLevel::ULTRA; } bool ShouldAdjustQuality(QualityLevel target, const PerformanceMetrics& metrics) { // 안정성 검사 및 히스테리시스 구현 return m_stableFrameCount >= m_config.stable_frames_required && target != metrics.current_quality; } }; ``` ### 디코더 타입별 스케일링 전략 | 디코더 | 주요 전략 | 대체 전략 | 성능 | |---------|----------|----------|------| | **NVDEC** | 하드웨어 재설정 | 디코딩 후 스케일링 | ⭐⭐⭐⭐⭐ | | **MediaFoundation** | MFT 출력 재설정 | 디코딩 후 스케일링 | ⭐⭐⭐⭐ | | **dav1d** | 디코딩 후 CPU 스케일링 | 디코딩 후 GPU 스케일링 | ⭐⭐⭐ | | **범용** | 디코딩 후 스케일링만 | 프레임 스킵 대체 | ⭐⭐ | --- ## 🎛️ 설정 프리셋 ### 프리셋 설정들 ```cpp namespace AdaptivePresets { // 보수적: 안정성을 위한 적극적 품질 저하 AdaptiveConfig Conservative() { AdaptiveConfig config; config.quality_down_threshold = 1.1; // 빠른 품질 저하 config.quality_up_threshold = 0.7; // 느린 품질 향상 config.stable_frames_required = 15; // 빠른 조정 return config; } // 균형: 품질과 성능의 좋은 균형 AdaptiveConfig Balanced() { AdaptiveConfig config; config.quality_down_threshold = 1.2; // 표준 임계값 config.quality_up_threshold = 0.8; config.stable_frames_required = 30; // 중간 안정성 return config; } // 품질 우선: 성능보다 시각적 품질 우선 AdaptiveConfig Quality() { AdaptiveConfig config; config.quality_down_threshold = 1.4; // 더 많은 지연 허용 config.quality_up_threshold = 0.9; // 빠른 품질 복원 config.stable_frames_required = 45; // 높은 안정성 return config; } // 게이밍: 저지연을 위한 초고속 반응 AdaptiveConfig Gaming() { AdaptiveConfig config; config.target_frame_time_ms = 16.67; // 60 FPS 목표 config.quality_down_threshold = 1.1; config.stable_frames_required = 10; // 매우 빠른 조정 return config; } } ``` --- ## 📊 성능 이점 분석 ### 비교: 프레임 스킵 vs 적응형 품질 | 지표 | 프레임 스킵 | 적응형 품질 | 개선도 | |------|-----------|------------|-------| | **시각적 연속성** | 나쁨 (끊김) | 우수 (부드러움) | +400% | | **오디오 동기화** | 나쁨 (비동기) | 완벽 (연속) | +100% | | **정보 보존** | 나쁨 (데이터 손실) | 좋음 (모든 프레임) | +300% | | **사용자 경험** | 답답함 | 매끄러움 | +500% | | **CPU 효율성** | 불규칙적 | 일관적 | +50% | | **메모리 사용량** | 정적 | 동적 최적화 | +30% | ### 예상 성능 시나리오 ``` 시나리오 1: 중급 시스템에서 4K 비디오 ├── 적응형 없음: 잦은 스킵으로 15 FPS └── 적응형 적용: HIGH 품질(1080p 상당)에서 30 FPS 시나리오 2: 저사양 시스템에서 1080p 비디오 ├── 적응형 없음: 끊김 현상과 함께 20 FPS └── 적응형 적용: MEDIUM 품질(720p 상당)에서 30 FPS 시나리오 3: 고사양 시스템의 일시적 부하 ├── 적응형 없음: 부하 스파이크 중 급작스러운 프레임 드롭 └── 적응형 적용: 일시적 품질 저하, 부드러운 복원 ``` --- ## 🔧 통합 가이드 ### 1단계: 기존 디코더에 적응형 인터페이스 추가 ```cpp // 기존 디코더 class MyDecoder : public IVideoDecoder { // ... 기존 구현 ... }; // 적응형 기능으로 강화 class MyAdaptiveDecoder : public MyDecoder, public IAdaptiveDecoder { public: bool SetQualityLevel(QualityLevel level) override { // 디코더별 품질 조정 구현 return ReconfigureForQuality(level); } // ... 다른 IAdaptiveDecoder 메서드 구현 ... }; ``` ### 2단계: VideoDecoderFactory와 통합 ```cpp class AdaptiveDecoderFactory { public: static std::unique_ptr CreateAdaptiveDecoder( VideoCodecType codec, const AdaptiveConfig& config = AdaptivePresets::Balanced()) { switch (codec) { case VideoCodecType::AV1: if (IsNVDECAvailable()) { return std::make_unique(config); } else { return std::make_unique(config); } // ... 다른 코덱들 ... } } }; ``` ### 3단계: VideoPlayerControl 업데이트 ```cpp void VideoPlayerControl::InitializeWithAdaptiveControl() { // 일반 디코더 대신 적응형 디코더 생성 m_decoder = AdaptiveDecoderFactory::CreateAdaptiveDecoder( m_videoMetadata.codec_type, AdaptivePresets::Gaming() // 저지연 재생용 ); // 성능 모니터링 시작 StartAdaptiveMonitoring(); } void VideoPlayerControl::ProcessFrameWithAdaptive() { auto start = std::chrono::high_resolution_clock::now(); // 적응형 품질로 디코딩 VideoFrame frame; bool success = m_decoder->DecodeFrame(packet, frame); auto decode_end = std::chrono::high_resolution_clock::now(); if (success) { RenderFrame(frame); auto render_end = std::chrono::high_resolution_clock::now(); // 타이밍 데이터로 적응형 시스템 업데이트 double decode_time = std::chrono::duration(decode_end - start).count(); double render_time = std::chrono::duration(render_end - decode_end).count(); auto adaptive_decoder = dynamic_cast(m_decoder.get()); if (adaptive_decoder) { adaptive_decoder->UpdatePerformanceMetrics(decode_time, render_time); } } } ``` --- ## 🧪 테스트 및 검증 ### 테스트 시나리오 1. **스트레스 테스트** - 높은 CPU 부하 시뮬레이션 - 메모리 압박 테스트 - GPU 리소스 경합 상황 2. **품질 검증** - 각 레벨에서의 시각적 품질 평가 - 전환 중 부드러움 평가 - 오디오-비디오 동기화 테스트 3. **성능 벤치마킹** - 적용 전후 프레임 레이트 비교 - 리소스 사용률 분석 - 지연시간 측정 ### 검증 지표 ```cpp struct AdaptiveTestMetrics { // 성능 double average_fps = 0.0; double frame_time_variance = 0.0; double quality_transition_smoothness = 0.0; // 품질 std::vector quality_distribution; uint32_t total_quality_changes = 0; double visual_quality_score = 0.0; // 안정성 double oscillation_frequency = 0.0; uint32_t false_adjustments = 0; double convergence_time_ms = 0.0; }; ``` --- ## 🚀 미래 개선사항 ### 계획된 기능들 1. **머신러닝 통합** - 최적 품질 레벨을 위한 패턴 인식 - 콘텐츠 분석 기반 예측적 품질 조정 - 개인화된 설정을 위한 사용자 행동 학습 2. **고급 스케일링 알고리즘** - 콘텐츠 인식 스케일링 (중요한 영역 보존) - 시간적 스케일링 (모션 기반 조정) - 지각적 품질 지표 통합 3. **멀티 디코더 협력** - 콘텐츠 기반 동적 디코더 전환 - 여러 디코더 간 부하 분산 - 이기종 프로세싱 (CPU + GPU 협력) 4. **네트워크 적응** - 적응형 스트리밍 프로토콜과 통합 - 대역폭 인식 품질 조정 - 적응형 콘텐츠를 위한 CDN 최적화 --- ## 🎯 실제 적용 예시 ### 일반적인 사용 사례 ```cpp // 예시 1: 게이밍 스트리밍용 설정 auto config = AdaptivePresets::Gaming(); config.target_frame_time_ms = 16.67; // 60 FPS auto decoder = std::make_unique(config); // 예시 2: 배터리 절약 모드 auto config = AdaptivePresets::Conservative(); config.quality_down_threshold = 1.05; // 매우 적극적 auto decoder = std::make_unique(config); // 예시 3: 고품질 미디어 플레이어 auto config = AdaptivePresets::Quality(); config.quality_down_threshold = 1.5; // 품질 우선 auto decoder = std::make_unique(config); ``` ### 성능 프로파일별 권장 설정 | 시스템 유형 | 권장 프리셋 | 목표 FPS | 품질 우선순위 | |------------|----------|----------|-------------| | **저사양 노트북** | Conservative | 24-30 | 안정성 > 품질 | | **일반 데스크톱** | Balanced | 30 | 균형 | | **게이밍 PC** | Gaming | 60 | 응답성 > 품질 | | **미디어 워크스테이션** | Quality | 30 | 품질 > 성능 | --- ## 📚 참고 자료 및 표준 - **NVIDIA Video Codec SDK 13.0**: [공식 문서](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/) - **dav1d 라이브러리**: [VideoLAN dav1d](https://code.videolan.org/videolan/dav1d) - **Windows Media Foundation**: [Microsoft MF 문서](https://docs.microsoft.com/en-us/windows/win32/medfound/) - **적응형 스트리밍 표준**: DASH, HLS, Smooth Streaming - **비디오 품질 지표**: PSNR, SSIM, VMAF --- ## 🔍 핵심 장점 요약 ### 💡 **기술적 혁신** - 프레임 드롭 → 해상도 조정으로 패러다임 전환 - 디코더 독립적 설계로 범용 적용 가능 - 실시간 성능 분석 기반 자동 최적화 ### 🎮 **사용자 경험 개선** - 끊김 없는 부드러운 재생 - 시각적 품질과 성능의 지능적 균형 - 시스템 성능에 자동 적응 ### ⚡ **성능 최적화** - CPU/GPU 리소스 효율적 활용 - 메모리 사용량 동적 최적화 - 배터리 수명 개선 (모바일 환경) --- *문서 버전: 1.0* *최종 업데이트: 2025-09-24* *Claude Code로 생성됨*