18 KiB
18 KiB
적응형 품질 제어 설계 문서
📋 개요
이 문서는 기존의 프레임 스킵 방식을 대체하는 적응형 품질 제어 시스템의 설계와 구현을 다룹니다. 이 시스템은 디코더 독립적으로 설계되어 NVDEC, dav1d, MediaFoundation 등 모든 비디오 디코더에 적용할 수 있습니다.
🎯 문제 정의
기존 프레임 스킵 방식의 문제점
- 시각적 불연속성: 비디오 타임라인에서 급작스러운 점프 발생
- 오디오-비디오 비동기화: 오디오는 계속 진행되는데 비디오 프레임이 누락됨
- 사용자 경험 저하: 성능 병목 구간에서 끊기는 재생
- 정보 손실: 완전한 프레임이 폐기되어 장면 맥락 상실
제안하는 해결책: 적응형 품질 제어
- 연속적 재생: 모든 프레임을 디코딩하고 표시
- 동적 해상도 조정: 성능에 따라 해상도를 자동으로 조정
- 부드러운 품질 저하: 프레임 드롭 대신 점진적인 품질 감소
- 시스템 적응: 하드웨어 성능에 맞춰 자동 조정
🏗️ 아키텍처 설계
핵심 구성요소
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. 기본 인터페이스 설계
// 범용 적응형 디코더 인터페이스
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. 설정 시스템
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<std::string, std::any> decoder_specific;
};
3. 성능 모니터링 시스템
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 구현
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 구현
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 구현
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<IMFMediaType> 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 전용)
🚀 범용 적응형 알고리즘
핵심 적응형 로직
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 스케일링 | ⭐⭐⭐ |
| 범용 | 디코딩 후 스케일링만 | 프레임 스킵 대체 | ⭐⭐ |
🎛️ 설정 프리셋
프리셋 설정들
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단계: 기존 디코더에 적응형 인터페이스 추가
// 기존 디코더
class MyDecoder : public IVideoDecoder {
// ... 기존 구현 ...
};
// 적응형 기능으로 강화
class MyAdaptiveDecoder : public MyDecoder, public IAdaptiveDecoder {
public:
bool SetQualityLevel(QualityLevel level) override {
// 디코더별 품질 조정 구현
return ReconfigureForQuality(level);
}
// ... 다른 IAdaptiveDecoder 메서드 구현 ...
};
2단계: VideoDecoderFactory와 통합
class AdaptiveDecoderFactory {
public:
static std::unique_ptr<IVideoDecoder> CreateAdaptiveDecoder(
VideoCodecType codec,
const AdaptiveConfig& config = AdaptivePresets::Balanced()) {
switch (codec) {
case VideoCodecType::AV1:
if (IsNVDECAvailable()) {
return std::make_unique<AdaptiveNVDECDecoder>(config);
} else {
return std::make_unique<Adaptivedav1dDecoder>(config);
}
// ... 다른 코덱들 ...
}
}
};
3단계: VideoPlayerControl 업데이트
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<double, std::milli>(decode_end - start).count();
double render_time = std::chrono::duration<double, std::milli>(render_end - decode_end).count();
auto adaptive_decoder = dynamic_cast<IAdaptiveDecoder*>(m_decoder.get());
if (adaptive_decoder) {
adaptive_decoder->UpdatePerformanceMetrics(decode_time, render_time);
}
}
}
🧪 테스트 및 검증
테스트 시나리오
-
스트레스 테스트
- 높은 CPU 부하 시뮬레이션
- 메모리 압박 테스트
- GPU 리소스 경합 상황
-
품질 검증
- 각 레벨에서의 시각적 품질 평가
- 전환 중 부드러움 평가
- 오디오-비디오 동기화 테스트
-
성능 벤치마킹
- 적용 전후 프레임 레이트 비교
- 리소스 사용률 분석
- 지연시간 측정
검증 지표
struct AdaptiveTestMetrics {
// 성능
double average_fps = 0.0;
double frame_time_variance = 0.0;
double quality_transition_smoothness = 0.0;
// 품질
std::vector<QualityLevel> 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;
};
🚀 미래 개선사항
계획된 기능들
-
머신러닝 통합
- 최적 품질 레벨을 위한 패턴 인식
- 콘텐츠 분석 기반 예측적 품질 조정
- 개인화된 설정을 위한 사용자 행동 학습
-
고급 스케일링 알고리즘
- 콘텐츠 인식 스케일링 (중요한 영역 보존)
- 시간적 스케일링 (모션 기반 조정)
- 지각적 품질 지표 통합
-
멀티 디코더 협력
- 콘텐츠 기반 동적 디코더 전환
- 여러 디코더 간 부하 분산
- 이기종 프로세싱 (CPU + GPU 협력)
-
네트워크 적응
- 적응형 스트리밍 프로토콜과 통합
- 대역폭 인식 품질 조정
- 적응형 콘텐츠를 위한 CDN 최적화
🎯 실제 적용 예시
일반적인 사용 사례
// 예시 1: 게이밍 스트리밍용 설정
auto config = AdaptivePresets::Gaming();
config.target_frame_time_ms = 16.67; // 60 FPS
auto decoder = std::make_unique<AdaptiveNVDECDecoder>(config);
// 예시 2: 배터리 절약 모드
auto config = AdaptivePresets::Conservative();
config.quality_down_threshold = 1.05; // 매우 적극적
auto decoder = std::make_unique<Adaptivedav1dDecoder>(config);
// 예시 3: 고품질 미디어 플레이어
auto config = AdaptivePresets::Quality();
config.quality_down_threshold = 1.5; // 품질 우선
auto decoder = std::make_unique<AdaptiveMediaFoundationDecoder>(config);
성능 프로파일별 권장 설정
| 시스템 유형 | 권장 프리셋 | 목표 FPS | 품질 우선순위 |
|---|---|---|---|
| 저사양 노트북 | Conservative | 24-30 | 안정성 > 품질 |
| 일반 데스크톱 | Balanced | 30 | 균형 |
| 게이밍 PC | Gaming | 60 | 응답성 > 품질 |
| 미디어 워크스테이션 | Quality | 30 | 품질 > 성능 |
📚 참고 자료 및 표준
- NVIDIA Video Codec SDK 13.0: 공식 문서
- dav1d 라이브러리: VideoLAN dav1d
- Windows Media Foundation: Microsoft MF 문서
- 적응형 스트리밍 표준: DASH, HLS, Smooth Streaming
- 비디오 품질 지표: PSNR, SSIM, VMAF
🔍 핵심 장점 요약
💡 기술적 혁신
- 프레임 드롭 → 해상도 조정으로 패러다임 전환
- 디코더 독립적 설계로 범용 적용 가능
- 실시간 성능 분석 기반 자동 최적화
🎮 사용자 경험 개선
- 끊김 없는 부드러운 재생
- 시각적 품질과 성능의 지능적 균형
- 시스템 성능에 자동 적응
⚡ 성능 최적화
- CPU/GPU 리소스 효율적 활용
- 메모리 사용량 동적 최적화
- 배터리 수명 개선 (모바일 환경)
문서 버전: 1.0 최종 업데이트: 2025-09-24 Claude Code로 생성됨