Select dav1d decoder (WIP)

This commit is contained in:
2025-10-07 21:35:00 +09:00
parent f854da5923
commit 959133058b
14 changed files with 216 additions and 35 deletions

View File

@@ -4,6 +4,8 @@
#include "VavCore/VavCore.h"
#include "src/Logger/SimpleLogger.h"
#include "src/Logger/LogManager.h"
#include "src/Utils/DecoderTypeUtils.h"
#include <sstream>
using namespace winrt;
using namespace winrt::Microsoft::UI::Xaml;
@@ -50,6 +52,37 @@ namespace winrt::Vav2Player::implementation
void App::OnLaunched(LaunchActivatedEventArgs const&)
{
// Log current decoder settings on app launch
try {
auto localSettings = winrt::Windows::Storage::ApplicationData::Current().LocalSettings();
auto values = localSettings.Values();
if (values.HasKey(L"DecoderType")) {
int32_t decoderTypeInt = winrt::unbox_value<int32_t>(values.Lookup(L"DecoderType"));
const char* decoderName = ::Vav2Player::Utils::GetDecoderTypeName(
static_cast<VavCoreDecoderType>(decoderTypeInt));
// Log to UI (LogManager)
std::wstring decoderTypeName(decoderName, decoderName + strlen(decoderName));
std::wostringstream logMsg;
logMsg << L"Current decoder setting: " << decoderTypeName
<< L" (type=" << decoderTypeInt << L")";
::Vav2Player::LogManager::GetInstance().LogInfo(logMsg.str(), L"App");
::Vav2Player::SimpleLogger::GetInstance().LogInfoF(
"[App] Current decoder setting: %s (type=%d)", decoderName, decoderTypeInt);
} else {
::Vav2Player::LogManager::GetInstance().LogInfo(L"No decoder setting found, will use AUTO", L"App");
::Vav2Player::SimpleLogger::GetInstance().LogInfo(
"[App] No decoder setting found, will use AUTO");
}
} catch (...) {
::Vav2Player::LogManager::GetInstance().LogError(L"Failed to read decoder settings", L"App");
::Vav2Player::SimpleLogger::GetInstance().LogError(
"[App] Failed to read decoder settings");
}
window = winrt::make<implementation::MainWindow>();
window.Activate();
}

View File

@@ -323,6 +323,7 @@ namespace winrt::Vav2Player::implementation
// Link FrameProcessor to PlaybackController for timing synchronization
if (m_frameProcessor) {
m_playbackController->SetFrameProcessor(m_frameProcessor.get());
m_frameProcessor->SetDecoderType(m_playbackController->GetDecoderType());
m_frameProcessor->PrepareVideoTexture(videoWidth, videoHeight);
}

View File

@@ -1,6 +1,8 @@
#include "pch.h"
#include "FrameProcessor.h"
#include "../Utils/DecoderTypeUtils.h"
#include "../Logger/SimpleLogger.h"
#include "../Logger/LogManager.h"
#include <iostream>
#include <Windows.h>
@@ -28,6 +30,22 @@ void FrameProcessor::SetDispatcherQueue(winrt::Microsoft::UI::Dispatching::Dispa
m_dispatcherQueue = queue;
}
void FrameProcessor::SetDecoderType(VavCoreDecoderType type)
{
m_decoderType = type;
// Log to UI (LogManager)
std::wstring decoderTypeName(Utils::GetDecoderTypeName(type),
Utils::GetDecoderTypeName(type) + strlen(Utils::GetDecoderTypeName(type)));
std::wstring logMsg = L"Decoder type set to: " + decoderTypeName +
L" (type=" + std::to_wstring(static_cast<int>(type)) + L")";
LogManager::GetInstance().LogInfo(logMsg, L"FrameProcessor");
// Also log to console for debugging
LOGF_INFO("[FrameProcessor] Decoder type set to: %s (type=%d)",
Utils::GetDecoderTypeName(type), static_cast<int>(type));
}
void FrameProcessor::PrepareVideoTexture(uint32_t width, uint32_t height)
{
if (m_renderer) {
@@ -54,24 +72,37 @@ bool FrameProcessor::ProcessFrame(VavCorePlayer* player,
return false;
}
// Get next RGBA texture from renderer (triple buffering)
ID3D12Resource* rgbaTexture = m_renderer->GetNextRGBATextureForCUDAInterop();
if (!rgbaTexture) {
LOGF_ERROR("[FrameProcessor] Failed to get next RGBA texture");
m_frameProcessing.store(false);
if (onComplete) onComplete(false);
return false;
}
// Decode frame to D3D12 surface (blocking)
// Decode strategy based on decoder type
auto decodeStart = std::chrono::high_resolution_clock::now();
VavCoreVideoFrame vavFrame = {};
VavCoreResult result = vavcore_decode_to_surface(
player,
VAVCORE_SURFACE_D3D12_RESOURCE,
rgbaTexture,
&vavFrame
);
VavCoreResult result;
if (m_decoderType == VAVCORE_DECODER_DAV1D) {
// DAV1D: CPU decoding only
LOGF_DEBUG("[FrameProcessor] Using DAV1D CPU decode path");
result = vavcore_decode_next_frame(player, &vavFrame);
if (result == VAVCORE_SUCCESS) {
vavFrame.surface_type = VAVCORE_SURFACE_CPU;
LOGF_DEBUG("[FrameProcessor] DAV1D decode success, surface_type=CPU");
}
} else {
// NVDEC/Hardware: D3D12 surface decoding
ID3D12Resource* rgbaTexture = m_renderer->GetNextRGBATextureForCUDAInterop();
if (!rgbaTexture) {
LOGF_ERROR("[FrameProcessor] Failed to get next RGBA texture");
m_frameProcessing.store(false);
if (onComplete) onComplete(false);
return false;
}
result = vavcore_decode_to_surface(
player,
VAVCORE_SURFACE_D3D12_RESOURCE,
rgbaTexture,
&vavFrame
);
}
auto decodeEnd = std::chrono::high_resolution_clock::now();
double decodeTime = std::chrono::duration<double, std::milli>(decodeEnd - decodeStart).count();

View File

@@ -23,6 +23,10 @@ public:
// Set renderer for frame output
void SetRenderer(D3D12VideoRenderer* renderer);
// Set decoder type (to choose decode strategy)
void SetDecoderType(VavCoreDecoderType type);
VavCoreDecoderType GetDecoderType() const { return m_decoderType; }
// Set dispatcher queue for UI thread callbacks
void SetDispatcherQueue(winrt::Microsoft::UI::Dispatching::DispatcherQueue const& queue);
@@ -48,6 +52,9 @@ private:
D3D12VideoRenderer* m_renderer = nullptr; // Non-owning pointer
winrt::Microsoft::UI::Dispatching::DispatcherQueue m_dispatcherQueue{ nullptr };
// Decoder configuration
VavCoreDecoderType m_decoderType = VAVCORE_DECODER_AUTO;
// Processing state (prevents NVDEC surface queue overflow)
std::atomic<bool> m_frameProcessing{false};

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include "PlaybackController.h"
#include "FrameProcessor.h"
#include "../Utils/DecoderTypeUtils.h"
#include "../Logger/SimpleLogger.h"
#include <chrono>
#include <sstream>
@@ -12,6 +13,9 @@ PlaybackController::PlaybackController()
// NOTE: VavCore is initialized globally in App.xaml.cpp
// Do NOT call vavcore_initialize() here to avoid duplicate initialization
LOGF_INFO("[PlaybackController] Constructor called (VavCore already initialized)");
// Load decoder settings from ApplicationData.LocalSettings
LoadDecoderSettings();
}
PlaybackController::~PlaybackController()
@@ -205,13 +209,62 @@ void PlaybackController::Seek(double timeSeconds)
}
}
void PlaybackController::LoadDecoderSettings()
{
try {
// Load decoder settings from Windows.Storage.ApplicationData.Current.LocalSettings
auto localSettings = winrt::Windows::Storage::ApplicationData::Current().LocalSettings();
auto values = localSettings.Values();
if (values.HasKey(L"DecoderType")) {
int32_t decoderTypeInt = winrt::unbox_value<int32_t>(values.Lookup(L"DecoderType"));
m_decoderType = static_cast<VavCoreDecoderType>(decoderTypeInt);
// Log to UI (LogManager)
std::wstring decoderTypeName(Utils::GetDecoderTypeName(m_decoderType),
Utils::GetDecoderTypeName(m_decoderType) + strlen(Utils::GetDecoderTypeName(m_decoderType)));
std::wstring logMsg = L"Loaded decoder settings: " + decoderTypeName +
L" (type=" + std::to_wstring(static_cast<int>(m_decoderType)) + L")";
LogManager::GetInstance().LogInfo(logMsg, L"PlaybackController");
LOGF_INFO("[PlaybackController] Loaded decoder settings: %s (type=%d)",
Utils::GetDecoderTypeName(m_decoderType), static_cast<int>(m_decoderType));
} else {
// No saved settings, use default
m_decoderType = VAVCORE_DECODER_AUTO;
LogManager::GetInstance().LogInfo(L"No saved decoder settings, using default: AUTO", L"PlaybackController");
LOGF_INFO("[PlaybackController] No saved decoder settings, using default: AUTO");
}
} catch (const std::exception& e) {
// Fallback to AUTO if loading fails
m_decoderType = VAVCORE_DECODER_AUTO;
std::string errorMsg = "Failed to load decoder settings: " + std::string(e.what()) + ", using AUTO";
std::wstring wErrorMsg(errorMsg.begin(), errorMsg.end());
LogManager::GetInstance().LogError(wErrorMsg, L"PlaybackController");
LOGF_ERROR("[PlaybackController] Failed to load decoder settings: %s, using AUTO", e.what());
}
}
void PlaybackController::SetDecoderType(VavCoreDecoderType type)
{
m_decoderType = type;
// Log to UI (LogManager)
std::wstring decoderTypeName(Utils::GetDecoderTypeName(type),
Utils::GetDecoderTypeName(type) + strlen(Utils::GetDecoderTypeName(type)));
std::wstring logMsg = L"Decoder type changed to: " + decoderTypeName +
L" (type=" + std::to_wstring(static_cast<int>(type)) + L")";
LogManager::GetInstance().LogInfo(logMsg, L"PlaybackController");
LOGF_INFO("[PlaybackController] Decoder type changed to: %s (type=%d)",
Utils::GetDecoderTypeName(type), static_cast<int>(type));
if (m_vavCorePlayer) {
vavcore_set_decoder_type(m_vavCorePlayer, type);
LOGF_INFO("[PlaybackController] Decoder type set to %d", static_cast<int>(type));
LogManager::GetInstance().LogInfo(L"Applied decoder type to active VavCore player", L"PlaybackController");
LOGF_INFO("[PlaybackController] Applied decoder type to active VavCore player");
}
}

View File

@@ -102,6 +102,7 @@ private:
// Helper methods
bool InitializeVavCore();
void CleanupVavCore();
void LoadDecoderSettings(); // Load decoder settings from ApplicationData.LocalSettings
void StartTimingThread();
void StopTimingThread();
void TimingThreadLoop();

View File

@@ -155,8 +155,13 @@ HRESULT D3D12VideoRenderer::RenderVideoFrame(const VavCoreVideoFrame& frame, Vav
// Get current back buffer
ID3D12Resource* backBuffer = m_renderTargets[m_frameIndex].Get();
// Get RTV handle for current back buffer
UINT rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += m_frameIndex * rtvDescriptorSize;
// Delegate rendering to backend
hr = backend->RenderToBackBuffer(frame, backBuffer, m_commandList.Get());
hr = backend->RenderToBackBuffer(frame, backBuffer, m_commandList.Get(), rtvHandle);
if (FAILED(hr)) {
return hr;
}
@@ -477,8 +482,16 @@ HRESULT D3D12VideoRenderer::InitializeBackends() {
}
IVideoBackend* D3D12VideoRenderer::SelectBackend(const VavCoreVideoFrame& frame) {
// For now, always use RGBA Surface backend for GPU-decoded frames
// Future: Check frame.surface_type to select appropriate backend
// Select backend based on frame surface type
if (frame.surface_type == VAVCORE_SURFACE_D3D12_RESOURCE) {
// Hardware decoder (NVDEC) - D3D12 RGBA texture
return m_rgbaSurfaceBackend.get();
} else if (frame.surface_type == VAVCORE_SURFACE_CPU) {
// Software decoder (dav1d) - CPU YUV data
return m_yuv420pUploadBackend.get();
}
// Default to RGBA backend
return m_rgbaSurfaceBackend.get();
}

View File

@@ -39,10 +39,12 @@ public:
// Frame rendering
// Renders the given frame to the specified back buffer
// rtvHandle: Render target view handle (used by backends that render directly)
virtual HRESULT RenderToBackBuffer(
const VavCoreVideoFrame& frame,
ID3D12Resource* backBuffer,
ID3D12GraphicsCommandList* commandList) = 0;
ID3D12GraphicsCommandList* commandList,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle) = 0;
// Format information
// Returns an identifier for the format this backend supports

View File

@@ -130,8 +130,11 @@ HRESULT RGBASurfaceBackend::CreateVideoTexture(uint32_t width, uint32_t height)
HRESULT RGBASurfaceBackend::RenderToBackBuffer(
const VavCoreVideoFrame& frame,
ID3D12Resource* backBuffer,
ID3D12GraphicsCommandList* commandList)
ID3D12GraphicsCommandList* commandList,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle)
{
// RGBASurfaceBackend doesn't need RTV (uses CopyResource)
(void)rtvHandle;
if (!m_initialized) {
return E_NOT_VALID_STATE;
}
@@ -183,8 +186,8 @@ HRESULT RGBASurfaceBackend::RenderToBackBuffer(
barrierToRT.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
commandList->ResourceBarrier(1, &barrierToRT);
// Create RTV for back buffer
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle;
// Create RTV for back buffer (not needed anymore - use rtvHandle from parameter)
D3D12_CPU_DESCRIPTOR_HANDLE backBufferRtvHandle;
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
@@ -201,8 +204,8 @@ HRESULT RGBASurfaceBackend::RenderToBackBuffer(
return hr;
}
rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
m_device->CreateRenderTargetView(backBuffer, &rtvDesc, rtvHandle);
backBufferRtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
m_device->CreateRenderTargetView(backBuffer, &rtvDesc, backBufferRtvHandle);
// Set graphics pipeline
commandList->SetPipelineState(m_pipelineState.Get());
@@ -219,7 +222,7 @@ HRESULT RGBASurfaceBackend::RenderToBackBuffer(
commandList->SetGraphicsRootConstantBufferView(1, m_constantBuffer->GetGPUVirtualAddress());
// Set render target
commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
commandList->OMSetRenderTargets(1, &backBufferRtvHandle, FALSE, nullptr);
// Set viewport and scissor
D3D12_VIEWPORT viewport = {};

View File

@@ -51,7 +51,8 @@ public:
HRESULT RenderToBackBuffer(
const VavCoreVideoFrame& frame,
ID3D12Resource* backBuffer,
ID3D12GraphicsCommandList* commandList) override;
ID3D12GraphicsCommandList* commandList,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle) override;
int GetSupportedFormatId() const override {
return 1;

View File

@@ -429,7 +429,8 @@ HRESULT YUV420PUploadBackend::UpdateColorMatrix(const VavCoreVideoFrame& frame)
HRESULT YUV420PUploadBackend::RenderToBackBuffer(
const VavCoreVideoFrame& frame,
ID3D12Resource* backBuffer,
ID3D12GraphicsCommandList* commandList)
ID3D12GraphicsCommandList* commandList,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle)
{
if (!m_initialized || !m_yTexture) return E_NOT_VALID_STATE;
@@ -442,7 +443,7 @@ HRESULT YUV420PUploadBackend::RenderToBackBuffer(
hr = ExecuteYUVToRGBConversion(commandList);
if (FAILED(hr)) return hr;
hr = RenderRGBToBackBuffer(commandList, backBuffer);
hr = RenderRGBToBackBuffer(commandList, backBuffer, rtvHandle);
if (FAILED(hr)) return hr;
m_currentBufferIndex = (m_currentBufferIndex + 1) % BufferCount;
@@ -499,14 +500,18 @@ HRESULT YUV420PUploadBackend::ExecuteYUVToRGBConversion(ID3D12GraphicsCommandLis
return S_OK;
}
HRESULT YUV420PUploadBackend::RenderRGBToBackBuffer(ID3D12GraphicsCommandList* commandList, ID3D12Resource* backBuffer) {
HRESULT YUV420PUploadBackend::RenderRGBToBackBuffer(
ID3D12GraphicsCommandList* commandList,
ID3D12Resource* backBuffer,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle)
{
UpdateConstantBuffer();
D3D12_RESOURCE_DESC backBufferDesc = backBuffer->GetDesc();
D3D12_RESOURCE_BARRIER barrier = ResourceBarrierTransition(backBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
commandList->ResourceBarrier(1, &barrier);
// Set render target - this part needs a proper RTV handle from the renderer orchestrator
// For now, assuming it's handled outside
// Set render target
commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
commandList->SetGraphicsRootSignature(m_graphicsRootSignature.Get());
commandList->SetPipelineState(m_graphicsPipelineState.Get());

View File

@@ -49,7 +49,8 @@ public:
HRESULT RenderToBackBuffer(
const VavCoreVideoFrame& frame,
ID3D12Resource* backBuffer,
ID3D12GraphicsCommandList* commandList) override;
ID3D12GraphicsCommandList* commandList,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle) override;
HRESULT UpdateFrame(const VavCoreVideoFrame& frame) override;
@@ -138,7 +139,10 @@ private:
HRESULT CopyUploadToGPU(ID3D12GraphicsCommandList* commandList, uint32_t bufferIndex);
HRESULT ExecuteYUVToRGBConversion(ID3D12GraphicsCommandList* commandList);
HRESULT RenderRGBToBackBuffer(ID3D12GraphicsCommandList* commandList, ID3D12Resource* backBuffer);
HRESULT RenderRGBToBackBuffer(
ID3D12GraphicsCommandList* commandList,
ID3D12Resource* backBuffer,
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle);
// Shader compilation
HRESULT CompileComputeShader();

View File

@@ -0,0 +1,24 @@
#pragma once
#include "VavCore/VavCore.h"
namespace Vav2Player {
namespace Utils {
// Utility function to convert VavCoreDecoderType enum to human-readable string
// Used by: PlaybackController, FrameProcessor, App, SettingsPage
inline const char* GetDecoderTypeName(VavCoreDecoderType type)
{
switch (type) {
case VAVCORE_DECODER_AUTO: return "AUTO";
case VAVCORE_DECODER_DAV1D: return "dav1d (Software)";
case VAVCORE_DECODER_NVDEC: return "NVDEC (NVIDIA)";
case VAVCORE_DECODER_VPL: return "Intel VPL";
case VAVCORE_DECODER_AMF: return "AMD AMF";
case VAVCORE_DECODER_MEDIA_FOUNDATION: return "Media Foundation";
default: return "UNKNOWN";
}
}
} // namespace Utils
} // namespace Vav2Player

View File

@@ -780,6 +780,9 @@ VAVCORE_API VavCoreResult vavcore_decode_to_surface(VavCorePlayer* player,
break;
case VAVCORE_SURFACE_D3D12_RESOURCE:
frame->surface_data.d3d12.d3d12_resource = target_surface;
// CRITICAL FIX: Copy CUDA fence value for D3D12-CUDA synchronization
// This fence value is set by NVDECAV1Decoder after CUDA kernel completion
frame->surface_data.d3d12.fence_value = videoFrame.sync_fence_value;
break;
case VAVCORE_SURFACE_CUDA_DEVICE:
// CUDA device pointer will be set by decoder implementation