Implement adaptive dav1d decoder
This commit is contained in:
@@ -178,8 +178,8 @@ namespace winrt::Vav2Player::implementation
|
||||
videoPlayer.ShowControls(true);
|
||||
videoPlayer.AutoPlay(false);
|
||||
|
||||
// Set default decoder to Software (AV1Decoder)
|
||||
videoPlayer.DecoderType(Vav2Player::VideoDecoderType::Software);
|
||||
// Set default decoder to Auto (AdaptiveAV1Decoder priority)
|
||||
videoPlayer.DecoderType(Vav2Player::VideoDecoderType::Auto);
|
||||
|
||||
// Add border for visual separation
|
||||
auto border = winrt::Microsoft::UI::Xaml::Controls::Border();
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
<ClInclude Include="src\Decoder\IVideoDecoder.h" />
|
||||
<ClInclude Include="src\Decoder\VideoDecoderFactory.h" />
|
||||
<ClInclude Include="src\Decoder\AV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\AdaptiveAV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\MediaFoundationAV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\NVDECAV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\AdaptiveNVDECDecoder.h" />
|
||||
@@ -183,6 +184,7 @@
|
||||
<ClCompile Include="src\Decoder\VideoDecoderFactory.cpp" />
|
||||
|
||||
<ClCompile Include="src\Decoder\AV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\AdaptiveAV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\MediaFoundationAV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\NVDECAV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\AdaptiveNVDECDecoder.cpp" />
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
<!-- Video Processing Components -->
|
||||
<ClCompile Include="src\FileIO\WebMFileReader.cpp" />
|
||||
<ClCompile Include="src\Decoder\AV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\AdaptiveAV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\MediaFoundationAV1Decoder.cpp" />
|
||||
<ClCompile Include="src\Decoder\VideoDecoderFactory.cpp" />
|
||||
<ClCompile Include="src\Decoder\NVDECAV1Decoder.cpp" />
|
||||
@@ -129,6 +130,7 @@
|
||||
<ClInclude Include="src\FileIO\WebMFileReader.h" />
|
||||
<ClInclude Include="src\Decoder\IVideoDecoder.h" />
|
||||
<ClInclude Include="src\Decoder\AV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\AdaptiveAV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\MediaFoundationAV1Decoder.h" />
|
||||
<ClInclude Include="src\Decoder\VideoDecoderFactory.h" />
|
||||
<ClInclude Include="src\Decoder\NVDECAV1Decoder.h" />
|
||||
|
||||
317
vav2/Vav2Player/Vav2Player/src/Decoder/AdaptiveAV1Decoder.cpp
Normal file
317
vav2/Vav2Player/Vav2Player/src/Decoder/AdaptiveAV1Decoder.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
#include "pch.h"
|
||||
#include "AdaptiveAV1Decoder.h"
|
||||
#include "AdaptiveNVDECDecoder.h" // For shared types and utilities
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace Vav2Player {
|
||||
|
||||
AdaptiveAV1Decoder::AdaptiveAV1Decoder() : AV1Decoder() {
|
||||
// Initialize with balanced configuration
|
||||
m_config = AdaptiveUtils::GetBalancedConfig();
|
||||
m_metrics.last_update = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
AdaptiveAV1Decoder::~AdaptiveAV1Decoder() = default;
|
||||
|
||||
bool AdaptiveAV1Decoder::Initialize(const VideoMetadata& metadata, const AdaptiveConfig& config) {
|
||||
m_config = config;
|
||||
return Initialize(metadata);
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::Initialize(const VideoMetadata& metadata) {
|
||||
// Store original dimensions for scaling calculations
|
||||
m_originalWidth = metadata.width;
|
||||
m_originalHeight = metadata.height;
|
||||
m_targetScaledWidth = metadata.width;
|
||||
m_targetScaledHeight = metadata.height;
|
||||
|
||||
// Initialize the base dav1d decoder
|
||||
bool result = AV1Decoder::Initialize(metadata);
|
||||
if (result) {
|
||||
OutputDebugStringA("[AdaptiveAV1Decoder] Initialized with adaptive quality control (post-decode scaling)\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::DecodeFrame(const VideoPacket& input_packet, VideoFrame& output_frame) {
|
||||
return DecodeFrame(input_packet.data.get(), input_packet.size, output_frame);
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::DecodeFrame(const uint8_t* packet_data, size_t packet_size, VideoFrame& output_frame) {
|
||||
auto decode_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Step 1: Decode frame using dav1d at full resolution
|
||||
VideoFrame full_resolution_frame;
|
||||
bool decode_success = AV1Decoder::DecodeFrame(packet_data, packet_size, full_resolution_frame);
|
||||
|
||||
auto decode_end = std::chrono::high_resolution_clock::now();
|
||||
double decode_time = std::chrono::duration<double, std::milli>(decode_end - decode_start).count();
|
||||
|
||||
if (!decode_success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Apply post-decode scaling if quality level requires it
|
||||
if (m_currentQuality != QualityLevel::ULTRA) {
|
||||
auto scale_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
bool scale_success = ScaleDecodedFrame(full_resolution_frame, output_frame);
|
||||
|
||||
auto scale_end = std::chrono::high_resolution_clock::now();
|
||||
double scale_time = std::chrono::duration<double, std::milli>(scale_end - scale_start).count();
|
||||
|
||||
// Add scaling time to decode time for performance analysis
|
||||
decode_time += scale_time;
|
||||
|
||||
if (!scale_success) {
|
||||
// Fallback: use full resolution frame
|
||||
output_frame = std::move(full_resolution_frame);
|
||||
OutputDebugStringA("[AdaptiveAV1Decoder] Scaling failed, using full resolution\n");
|
||||
}
|
||||
} else {
|
||||
// ULTRA quality: use full resolution frame directly
|
||||
output_frame = std::move(full_resolution_frame);
|
||||
}
|
||||
|
||||
// Step 3: Update performance metrics and potentially adjust quality
|
||||
if (m_adaptiveEnabled) {
|
||||
UpdatePerformanceMetrics(decode_time, 0.0); // Render time updated separately
|
||||
AnalyzePerformanceAndAdjust();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::SetQualityLevel(QualityLevel level) {
|
||||
if (level == m_currentQuality) return;
|
||||
|
||||
m_targetQuality = level;
|
||||
CalculateScaledDimensions(level, m_targetScaledWidth, m_targetScaledHeight);
|
||||
m_currentQuality = level; // dav1d doesn't need decoder reconfiguration
|
||||
|
||||
OutputDebugStringA(("[AdaptiveAV1Decoder] Quality changed to " +
|
||||
QualityLevelToString(level) + "\n").c_str());
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::UpdatePerformanceMetrics(double decode_time, double render_time) {
|
||||
std::lock_guard<std::mutex> lock(m_metricsMutex);
|
||||
|
||||
// Update moving averages
|
||||
if (decode_time > 0) {
|
||||
UpdateMovingAverage(m_recentDecodeTimes, decode_time);
|
||||
m_metrics.avg_decode_time_ms = CalculateMovingAverage(m_recentDecodeTimes);
|
||||
}
|
||||
|
||||
if (render_time > 0) {
|
||||
UpdateMovingAverage(m_recentRenderTimes, render_time);
|
||||
m_metrics.avg_render_time_ms = CalculateMovingAverage(m_recentRenderTimes);
|
||||
}
|
||||
|
||||
m_metrics.last_update = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::AnalyzePerformanceAndAdjust() {
|
||||
std::lock_guard<std::mutex> lock(m_metricsMutex);
|
||||
|
||||
double totalFrameTime = m_metrics.avg_decode_time_ms + m_metrics.avg_render_time_ms;
|
||||
|
||||
if (ShouldAdjustQuality(m_metrics.avg_decode_time_ms, m_metrics.avg_render_time_ms)) {
|
||||
QualityLevel optimalQuality = DetermineOptimalQuality(totalFrameTime);
|
||||
|
||||
if (optimalQuality != m_currentQuality) {
|
||||
m_stableFrameCount = 0; // Reset stability counter
|
||||
SetQualityLevel(optimalQuality);
|
||||
} else {
|
||||
m_stableFrameCount++;
|
||||
}
|
||||
} else {
|
||||
m_stableFrameCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::ShouldAdjustQuality(double avgDecodeTime, double avgRenderTime) {
|
||||
double totalTime = avgDecodeTime + avgRenderTime;
|
||||
double targetTime = m_config.target_frame_time_ms;
|
||||
|
||||
// Require minimum frames for stability
|
||||
if (m_stableFrameCount < m_config.stable_frames_required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're outside acceptable performance range
|
||||
bool shouldScaleDown = totalTime > (targetTime * m_config.quality_down_threshold);
|
||||
bool shouldScaleUp = totalTime < (targetTime * m_config.quality_up_threshold) &&
|
||||
m_currentQuality > QualityLevel::ULTRA;
|
||||
|
||||
return shouldScaleDown || shouldScaleUp;
|
||||
}
|
||||
|
||||
QualityLevel AdaptiveAV1Decoder::DetermineOptimalQuality(double totalFrameTime) {
|
||||
double targetTime = m_config.target_frame_time_ms;
|
||||
double ratio = totalFrameTime / targetTime;
|
||||
|
||||
// Determine quality based on performance ratio
|
||||
if (ratio > 2.0) return QualityLevel::MINIMUM; // Extremely slow
|
||||
if (ratio > 1.5) return QualityLevel::LOW; // Very slow
|
||||
if (ratio > 1.2) return QualityLevel::MEDIUM; // Slow
|
||||
if (ratio > 1.0) return QualityLevel::HIGH; // Slightly slow
|
||||
return QualityLevel::ULTRA; // Fast enough for full quality
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::ScaleDecodedFrame(const VideoFrame& input_frame, VideoFrame& output_frame) {
|
||||
// Ensure we have target dimensions calculated
|
||||
if (m_targetScaledWidth == 0 || m_targetScaledHeight == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create output frame with scaled dimensions
|
||||
output_frame.width = m_targetScaledWidth;
|
||||
output_frame.height = m_targetScaledHeight;
|
||||
output_frame.color_space = input_frame.color_space;
|
||||
output_frame.timestamp_seconds = input_frame.timestamp_seconds;
|
||||
|
||||
// Allocate scaled frame buffer
|
||||
if (!output_frame.AllocateYUV420P(m_targetScaledWidth, m_targetScaledHeight)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform CPU-based YUV420P scaling
|
||||
return ScaleYUV420P_CPU(input_frame, output_frame);
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::CalculateScaledDimensions(QualityLevel quality, uint32_t& width, uint32_t& height) {
|
||||
double scaleFactor = GetQualityScaleFactor(quality);
|
||||
|
||||
width = static_cast<uint32_t>(m_originalWidth * scaleFactor);
|
||||
height = static_cast<uint32_t>(m_originalHeight * scaleFactor);
|
||||
|
||||
// Ensure dimensions are even (required for YUV420P)
|
||||
width = (width + 1) & ~1;
|
||||
height = (height + 1) & ~1;
|
||||
|
||||
// Ensure minimum dimensions
|
||||
width = std::max(width, 64u);
|
||||
height = std::max(height, 64u);
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::EnsureScalingBuffer(size_t required_size) {
|
||||
if (m_scalingBufferSize < required_size) {
|
||||
m_scalingBuffer = std::make_unique<uint8_t[]>(required_size);
|
||||
m_scalingBufferSize = required_size;
|
||||
}
|
||||
return m_scalingBuffer != nullptr;
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::ScaleYUV420P_CPU(const VideoFrame& input, VideoFrame& output) {
|
||||
// Scale Y plane
|
||||
if (!ScaleYUVPlane_CPU(
|
||||
input.y_plane.get(), input.y_stride, input.width, input.height,
|
||||
output.y_plane.get(), output.y_stride, output.width, output.height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scale U plane (half resolution)
|
||||
uint32_t input_uv_width = input.width / 2;
|
||||
uint32_t input_uv_height = input.height / 2;
|
||||
uint32_t output_uv_width = output.width / 2;
|
||||
uint32_t output_uv_height = output.height / 2;
|
||||
|
||||
if (!ScaleYUVPlane_CPU(
|
||||
input.u_plane.get(), input.u_stride, input_uv_width, input_uv_height,
|
||||
output.u_plane.get(), output.u_stride, output_uv_width, output_uv_height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scale V plane (half resolution)
|
||||
if (!ScaleYUVPlane_CPU(
|
||||
input.v_plane.get(), input.v_stride, input_uv_width, input_uv_height,
|
||||
output.v_plane.get(), output.v_stride, output_uv_width, output_uv_height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdaptiveAV1Decoder::ScaleYUVPlane_CPU(const uint8_t* src_plane, int src_stride, int src_width, int src_height,
|
||||
uint8_t* dst_plane, int dst_stride, int dst_width, int dst_height) {
|
||||
// Simple bilinear scaling implementation
|
||||
for (int dst_y = 0; dst_y < dst_height; dst_y++) {
|
||||
for (int dst_x = 0; dst_x < dst_width; dst_x++) {
|
||||
// Calculate source coordinates
|
||||
float src_x_f = (static_cast<float>(dst_x) * src_width) / dst_width;
|
||||
float src_y_f = (static_cast<float>(dst_y) * src_height) / dst_height;
|
||||
|
||||
int src_x = static_cast<int>(src_x_f);
|
||||
int src_y = static_cast<int>(src_y_f);
|
||||
|
||||
// Bounds checking
|
||||
src_x = std::min(src_x, src_width - 1);
|
||||
src_y = std::min(src_y, src_height - 1);
|
||||
|
||||
// Simple nearest neighbor for now (can be upgraded to bilinear later)
|
||||
uint8_t pixel_value = src_plane[src_y * src_stride + src_x];
|
||||
dst_plane[dst_y * dst_stride + dst_x] = pixel_value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::UpdateMovingAverage(std::queue<double>& queue, double newValue, size_t maxSize) {
|
||||
queue.push(newValue);
|
||||
while (queue.size() > maxSize) {
|
||||
queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
double AdaptiveAV1Decoder::CalculateMovingAverage(const std::queue<double>& queue) const {
|
||||
if (queue.empty()) return 0.0;
|
||||
|
||||
double sum = 0.0;
|
||||
std::queue<double> temp = queue;
|
||||
while (!temp.empty()) {
|
||||
sum += temp.front();
|
||||
temp.pop();
|
||||
}
|
||||
return sum / queue.size();
|
||||
}
|
||||
|
||||
double AdaptiveAV1Decoder::GetQualityScaleFactor(QualityLevel level) {
|
||||
switch (level) {
|
||||
case QualityLevel::ULTRA: return 1.0; // 100% resolution
|
||||
case QualityLevel::HIGH: return 0.75; // 75% resolution
|
||||
case QualityLevel::MEDIUM: return 0.5; // 50% resolution
|
||||
case QualityLevel::LOW: return 0.35; // 35% resolution
|
||||
case QualityLevel::MINIMUM: return 0.25; // 25% resolution
|
||||
default: return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string AdaptiveAV1Decoder::QualityLevelToString(QualityLevel level) {
|
||||
switch (level) {
|
||||
case QualityLevel::ULTRA: return "ULTRA";
|
||||
case QualityLevel::HIGH: return "HIGH";
|
||||
case QualityLevel::MEDIUM: return "MEDIUM";
|
||||
case QualityLevel::LOW: return "LOW";
|
||||
case QualityLevel::MINIMUM: return "MINIMUM";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceMetrics AdaptiveAV1Decoder::GetPerformanceMetrics() const {
|
||||
std::lock_guard<std::mutex> lock(m_metricsMutex);
|
||||
return m_metrics;
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::SetTargetFrameRate(double fps) {
|
||||
m_config.target_frame_time_ms = 1000.0 / fps;
|
||||
m_config.critical_frame_time_ms = 1000.0 / (fps * 0.6); // 60% of target FPS
|
||||
}
|
||||
|
||||
void AdaptiveAV1Decoder::ForceQualityAdjustment() {
|
||||
m_stableFrameCount = m_config.stable_frames_required; // Force next analysis
|
||||
}
|
||||
|
||||
} // namespace Vav2Player
|
||||
96
vav2/Vav2Player/Vav2Player/src/Decoder/AdaptiveAV1Decoder.h
Normal file
96
vav2/Vav2Player/Vav2Player/src/Decoder/AdaptiveAV1Decoder.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
#include "AV1Decoder.h"
|
||||
#include "AdaptiveNVDECDecoder.h" // Include full definitions of shared types
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
namespace Vav2Player {
|
||||
|
||||
// Enhanced AV1 decoder with adaptive quality adjustment using post-decode scaling
|
||||
class AdaptiveAV1Decoder : public AV1Decoder {
|
||||
public:
|
||||
AdaptiveAV1Decoder();
|
||||
~AdaptiveAV1Decoder() override;
|
||||
|
||||
// Enhanced initialization with adaptive features
|
||||
bool Initialize(const VideoMetadata& metadata) override;
|
||||
bool Initialize(const VideoMetadata& metadata, const AdaptiveConfig& config);
|
||||
|
||||
// Override decode with adaptive logic and post-decode scaling
|
||||
bool DecodeFrame(const VideoPacket& input_packet, VideoFrame& output_frame) override;
|
||||
bool DecodeFrame(const uint8_t* packet_data, size_t packet_size, VideoFrame& output_frame) override;
|
||||
|
||||
// Adaptive quality control
|
||||
void SetQualityLevel(QualityLevel level);
|
||||
QualityLevel GetCurrentQualityLevel() const { return m_currentQuality; }
|
||||
|
||||
// Performance monitoring
|
||||
PerformanceMetrics GetPerformanceMetrics() const;
|
||||
void UpdatePerformanceMetrics(double decode_time, double render_time);
|
||||
|
||||
// Manual override controls
|
||||
void EnableAdaptiveMode(bool enable) { m_adaptiveEnabled = enable; }
|
||||
void SetTargetFrameRate(double fps);
|
||||
void ForceQualityAdjustment(); // Immediate adjustment trigger
|
||||
|
||||
// Configuration management
|
||||
void UpdateConfig(const AdaptiveConfig& config) { m_config = config; }
|
||||
AdaptiveConfig GetConfig() const { return m_config; }
|
||||
|
||||
// Override codec name to indicate adaptive capability
|
||||
std::string GetCodecName() const override { return "AV1 (dav1d adaptive)"; }
|
||||
|
||||
private:
|
||||
// Adaptive control state
|
||||
QualityLevel m_currentQuality = QualityLevel::ULTRA;
|
||||
QualityLevel m_targetQuality = QualityLevel::ULTRA;
|
||||
AdaptiveConfig m_config;
|
||||
|
||||
// Performance monitoring
|
||||
mutable std::mutex m_metricsMutex;
|
||||
PerformanceMetrics m_metrics;
|
||||
std::queue<double> m_recentDecodeTimes;
|
||||
std::queue<double> m_recentRenderTimes;
|
||||
|
||||
// Adaptive decision making
|
||||
std::atomic<bool> m_adaptiveEnabled{true};
|
||||
uint32_t m_stableFrameCount = 0;
|
||||
|
||||
// Original video properties for scaling calculations
|
||||
uint32_t m_originalWidth = 0;
|
||||
uint32_t m_originalHeight = 0;
|
||||
|
||||
// Current scaled properties (for post-decode scaling)
|
||||
uint32_t m_targetScaledWidth = 0;
|
||||
uint32_t m_targetScaledHeight = 0;
|
||||
|
||||
// Post-decode scaling buffer
|
||||
std::unique_ptr<uint8_t[]> m_scalingBuffer;
|
||||
size_t m_scalingBufferSize = 0;
|
||||
|
||||
// Adaptive logic methods
|
||||
void AnalyzePerformanceAndAdjust();
|
||||
bool ShouldAdjustQuality(double avgDecodeTime, double avgRenderTime);
|
||||
QualityLevel DetermineOptimalQuality(double totalFrameTime);
|
||||
|
||||
// Post-decode scaling methods (dav1d specific approach)
|
||||
bool ScaleDecodedFrame(const VideoFrame& input_frame, VideoFrame& output_frame);
|
||||
void CalculateScaledDimensions(QualityLevel quality, uint32_t& width, uint32_t& height);
|
||||
bool EnsureScalingBuffer(size_t required_size);
|
||||
|
||||
// CPU-based scaling implementation
|
||||
bool ScaleYUV420P_CPU(const VideoFrame& input, VideoFrame& output);
|
||||
bool ScaleYUVPlane_CPU(const uint8_t* src_plane, int src_stride, int src_width, int src_height,
|
||||
uint8_t* dst_plane, int dst_stride, int dst_width, int dst_height);
|
||||
|
||||
// Performance calculation helpers
|
||||
void UpdateMovingAverage(std::queue<double>& queue, double newValue, size_t maxSize = 30);
|
||||
double CalculateMovingAverage(const std::queue<double>& queue) const;
|
||||
|
||||
// Quality level utilities
|
||||
static double GetQualityScaleFactor(QualityLevel level);
|
||||
static std::string QualityLevelToString(QualityLevel level);
|
||||
};
|
||||
|
||||
} // namespace Vav2Player
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "VideoDecoderFactory.h"
|
||||
#include "AV1Decoder.h"
|
||||
#include "AdaptiveAV1Decoder.h"
|
||||
#include "MediaFoundationAV1Decoder.h"
|
||||
// #include "VP9Decoder.h" // TODO: activate when VP9 implemented
|
||||
|
||||
@@ -59,7 +60,15 @@ std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateAV1Decoder(DecoderType
|
||||
OutputDebugStringA("[VideoDecoderFactory] Creating NVDEC AV1 decoder\n");
|
||||
return std::make_unique<NVDECAV1Decoder>();
|
||||
}
|
||||
OutputDebugStringA("[VideoDecoderFactory] NVDEC not available, falling back to dav1d\n");
|
||||
OutputDebugStringA("[VideoDecoderFactory] NVDEC not available, falling back to Adaptive dav1d\n");
|
||||
[[fallthrough]];
|
||||
|
||||
case DecoderType::ADAPTIVE_DAV1D:
|
||||
if (s_av1_available) {
|
||||
OutputDebugStringA("[VideoDecoderFactory] Creating Adaptive dav1d AV1 decoder\n");
|
||||
return std::make_unique<AdaptiveAV1Decoder>();
|
||||
}
|
||||
OutputDebugStringA("[VideoDecoderFactory] dav1d not available, falling back to regular dav1d\n");
|
||||
[[fallthrough]];
|
||||
|
||||
case DecoderType::DAV1D:
|
||||
@@ -78,7 +87,7 @@ std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateAV1Decoder(DecoderType
|
||||
break;
|
||||
|
||||
case DecoderType::AUTO:
|
||||
// Try ADAPTIVE_NVDEC first (best user experience), then NVDEC, then dav1d, finally MediaFoundation
|
||||
// Try ADAPTIVE_NVDEC first (best user experience), then ADAPTIVE_DAV1D, then NVDEC, then dav1d, finally MediaFoundation
|
||||
if (s_nvdec_available) {
|
||||
OutputDebugStringA("[VideoDecoderFactory] Auto mode: trying Adaptive NVDEC AV1 decoder first\n");
|
||||
auto decoder = std::make_unique<AdaptiveNVDECDecoder>();
|
||||
@@ -87,6 +96,14 @@ std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateAV1Decoder(DecoderType
|
||||
}
|
||||
}
|
||||
|
||||
if (s_av1_available) {
|
||||
OutputDebugStringA("[VideoDecoderFactory] Auto mode: trying Adaptive dav1d AV1 decoder\n");
|
||||
auto decoder = std::make_unique<AdaptiveAV1Decoder>();
|
||||
if (decoder) {
|
||||
return decoder;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_nvdec_available) {
|
||||
OutputDebugStringA("[VideoDecoderFactory] Auto mode: trying regular NVDEC AV1 decoder\n");
|
||||
auto decoder = std::make_unique<NVDECAV1Decoder>();
|
||||
@@ -96,7 +113,7 @@ std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateAV1Decoder(DecoderType
|
||||
}
|
||||
|
||||
if (s_av1_available) {
|
||||
OutputDebugStringA("[VideoDecoderFactory] Auto mode: trying dav1d AV1 decoder\n");
|
||||
OutputDebugStringA("[VideoDecoderFactory] Auto mode: trying regular dav1d AV1 decoder\n");
|
||||
auto decoder = std::make_unique<AV1Decoder>();
|
||||
if (decoder) {
|
||||
return decoder;
|
||||
|
||||
@@ -14,10 +14,11 @@ public:
|
||||
// Decoder type enumeration
|
||||
enum class DecoderType {
|
||||
DAV1D, // dav1d library based decoder
|
||||
ADAPTIVE_DAV1D, // Adaptive dav1d with dynamic quality control (post-decode scaling)
|
||||
MEDIA_FOUNDATION, // Windows Media Foundation based decoder
|
||||
NVDEC, // NVIDIA NVDEC hardware acceleration decoder
|
||||
ADAPTIVE_NVDEC, // Adaptive NVDEC with dynamic quality control
|
||||
AUTO // Auto selection (ADAPTIVE_NVDEC priority, NVDEC, dav1d, finally MediaFoundation)
|
||||
AUTO // Auto selection (ADAPTIVE_NVDEC priority, ADAPTIVE_DAV1D, NVDEC, dav1d, finally MediaFoundation)
|
||||
};
|
||||
|
||||
// Supported decoder information
|
||||
|
||||
Reference in New Issue
Block a user