Clean code
This commit is contained in:
@@ -97,12 +97,8 @@ namespace winrt::Vav2Player::implementation
|
||||
}
|
||||
m_renderBitmap = nullptr;
|
||||
|
||||
// Additional safety flags
|
||||
m_isInitialized = false;
|
||||
m_isLoaded = false;
|
||||
|
||||
|
||||
m_isInitialized = false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -238,9 +234,6 @@ namespace winrt::Vav2Player::implementation
|
||||
if (m_isLoaded && m_fileReader && m_fileReader->IsFileOpen())
|
||||
{
|
||||
InitializeVideoRenderer();
|
||||
OutputDebugStringA(("Switched to " +
|
||||
std::string(value ? "hardware D3D12" : "software CPU") +
|
||||
" rendering\n").c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -363,7 +356,6 @@ namespace winrt::Vav2Player::implementation
|
||||
m_playbackTimer.Interval(interval);
|
||||
m_playbackTimer.Start();
|
||||
|
||||
// Process first frame immediately
|
||||
ProcessSingleFrame();
|
||||
}
|
||||
|
||||
@@ -408,22 +400,14 @@ namespace winrt::Vav2Player::implementation
|
||||
|
||||
void VideoPlayerControl::ProcessSingleFrame()
|
||||
{
|
||||
OutputDebugStringA("[DEBUG] ProcessSingleFrame() called\n");
|
||||
|
||||
// Simple validation
|
||||
if (!m_isPlaying || !m_fileReader || !m_decoder) {
|
||||
OutputDebugStringA(("[DEBUG] ProcessSingleFrame validation failed - playing:" +
|
||||
std::string(m_isPlaying ? "true" : "false") +
|
||||
" fileReader:" + std::string(m_fileReader ? "valid" : "null") +
|
||||
" decoder:" + std::string(m_decoder ? "valid" : "null") + "\n").c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
OutputDebugStringA("[DEBUG] Reading next packet...\n");
|
||||
VideoPacket packet;
|
||||
if (!m_fileReader->ReadNextPacket(packet))
|
||||
{
|
||||
OutputDebugStringA("[DEBUG] End of video - stopping playback\n");
|
||||
// End of video - stop playback
|
||||
m_isPlaying = false;
|
||||
if (m_playbackTimer) m_playbackTimer.Stop();
|
||||
@@ -431,14 +415,11 @@ namespace winrt::Vav2Player::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
OutputDebugStringA("[DEBUG] Decoding frame...\n");
|
||||
VideoFrame frame;
|
||||
if (!m_decoder->DecodeFrame(packet, frame)) {
|
||||
OutputDebugStringA("[DEBUG] Failed to decode frame - skipping\n");
|
||||
return; // Skip failed frames
|
||||
}
|
||||
|
||||
OutputDebugStringA("[DEBUG] Rendering frame to screen...\n");
|
||||
RenderFrameToScreen(frame);
|
||||
|
||||
m_currentFrame++;
|
||||
@@ -567,16 +548,13 @@ namespace winrt::Vav2Player::implementation
|
||||
bgra_row[x * 4 + 3] = 255; // Alpha
|
||||
}
|
||||
}
|
||||
OutputDebugStringA("[DEBUG] YUV to BGRA conversion completed\n");
|
||||
}
|
||||
|
||||
void VideoPlayerControl::UpdateStatus(winrt::hstring const& message)
|
||||
{
|
||||
m_status = message;
|
||||
OutputDebugStringA(("[DEBUG] Status: " + winrt::to_string(message) + "\n").c_str());
|
||||
}
|
||||
|
||||
|
||||
void VideoPlayerControl::InitializeVideoRenderer()
|
||||
{
|
||||
// Initialize rendering mode based on user selection
|
||||
@@ -607,29 +585,21 @@ namespace winrt::Vav2Player::implementation
|
||||
// Temporarily use CPU rendering until container size is available
|
||||
VideoSwapChainPanel().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Collapsed);
|
||||
VideoImage().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Visible);
|
||||
// Don't change m_useHardwareRendering flag - keep user preference
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr = m_gpuRenderer->Initialize(VideoSwapChainPanel(), containerWidth, containerHeight);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// GPU rendering initialized successfully
|
||||
}
|
||||
else
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
// GPU initialization failed - temporarily use CPU rendering
|
||||
// Don't permanently change m_useHardwareRendering flag
|
||||
VideoSwapChainPanel().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Collapsed);
|
||||
VideoImage().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Visible);
|
||||
// Keep GPU renderer for potential retry later
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayerControl::ResetVideoState()
|
||||
{
|
||||
OutputDebugStringA("[DEBUG] ResetVideoState() called\n");
|
||||
m_currentFrame = 0;
|
||||
m_currentTime = 0.0;
|
||||
m_isLoaded = false;
|
||||
@@ -649,23 +619,18 @@ namespace winrt::Vav2Player::implementation
|
||||
|
||||
bool VideoPlayerControl::CreateDecoder()
|
||||
{
|
||||
OutputDebugStringA("[DEBUG] CreateDecoder() called\n");
|
||||
m_decoder = VideoDecoderFactory::CreateDecoder(VideoCodecType::AV1, m_decoderType);
|
||||
bool success = m_decoder != nullptr;
|
||||
OutputDebugStringA(("[DEBUG] Decoder created: " + std::string(success ? "success" : "failed") + "\n").c_str());
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VideoPlayerControl::InitializeDecoder()
|
||||
{
|
||||
OutputDebugStringA("[DEBUG] InitializeDecoder() called\n");
|
||||
if (!m_decoder) {
|
||||
OutputDebugStringA("[DEBUG] No decoder available\n");
|
||||
return false;
|
||||
}
|
||||
auto metadata = m_fileReader->GetVideoMetadata();
|
||||
bool success = m_decoder->Initialize(metadata);
|
||||
OutputDebugStringA(("[DEBUG] Decoder initialized: " + std::string(success ? "success" : "failed") + "\n").c_str());
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -735,7 +700,6 @@ namespace winrt::Vav2Player::implementation
|
||||
|
||||
void VideoPlayerControl::Seek(double timeSeconds)
|
||||
{
|
||||
OutputDebugStringA(("[DEBUG] Seek to: " + std::to_string(timeSeconds) + "s\n").c_str());
|
||||
if (!m_isLoaded || !m_fileReader) return;
|
||||
|
||||
// Stop playback during seek
|
||||
@@ -758,8 +722,6 @@ namespace winrt::Vav2Player::implementation
|
||||
}
|
||||
|
||||
UpdateStatus(L"Seeked");
|
||||
} else {
|
||||
OutputDebugStringA("[DEBUG] Seek operation failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// YUVCopy.hlsl - GPU-based YUV plane copy compute shader
|
||||
// Replaces CPU memcpy with GPU parallel processing for zero-copy optimization
|
||||
|
||||
// Constant buffer for copy parameters
|
||||
cbuffer CopyParams : register(b0)
|
||||
{
|
||||
uint srcWidth; // Source width in pixels
|
||||
uint srcHeight; // Source height in pixels
|
||||
uint srcPitch; // Source row pitch in bytes
|
||||
uint dstPitch; // Destination row pitch in bytes
|
||||
uint bytesPerPixel; // Bytes per pixel (1 for Y, 1 for U/V)
|
||||
uint padding[3]; // Padding for 16-byte alignment
|
||||
};
|
||||
|
||||
// Input buffer (Ring Buffer mapped memory)
|
||||
StructuredBuffer<uint> srcBuffer : register(t0);
|
||||
|
||||
// Output buffer (GPU upload buffer)
|
||||
RWStructuredBuffer<uint> dstBuffer : register(u0);
|
||||
|
||||
// Thread group size: 8x8 = 64 threads per group
|
||||
[numthreads(8, 8, 1)]
|
||||
void CSMain(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
uint x = id.x;
|
||||
uint y = id.y;
|
||||
|
||||
// Bounds check
|
||||
if (x >= srcWidth || y >= srcHeight)
|
||||
return;
|
||||
|
||||
// Calculate byte offsets for source and destination
|
||||
uint srcByteOffset = y * srcPitch + x * bytesPerPixel;
|
||||
uint dstByteOffset = y * dstPitch + x * bytesPerPixel;
|
||||
|
||||
// Convert byte offsets to uint offsets (4 bytes per uint)
|
||||
uint srcUintOffset = srcByteOffset / 4;
|
||||
uint dstUintOffset = dstByteOffset / 4;
|
||||
|
||||
// Handle byte-aligned copies for different pixel sizes
|
||||
if (bytesPerPixel == 1)
|
||||
{
|
||||
// For Y, U, V planes (1 byte per pixel)
|
||||
uint srcUintIndex = srcUintOffset;
|
||||
uint dstUintIndex = dstUintOffset;
|
||||
uint byteIndexInUint = srcByteOffset % 4;
|
||||
|
||||
// Read source uint and extract the specific byte
|
||||
uint srcValue = srcBuffer[srcUintIndex];
|
||||
uint pixelValue = (srcValue >> (byteIndexInUint * 8)) & 0xFF;
|
||||
|
||||
// Update destination uint with the new pixel value
|
||||
uint dstOriginal = dstBuffer[dstUintIndex];
|
||||
uint dstByteIndex = dstByteOffset % 4;
|
||||
uint mask = 0xFF << (dstByteIndex * 8);
|
||||
uint newValue = (dstOriginal & ~mask) | (pixelValue << (dstByteIndex * 8));
|
||||
|
||||
dstBuffer[dstUintIndex] = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For multi-byte pixels, copy full uints
|
||||
dstBuffer[dstUintOffset] = srcBuffer[srcUintOffset];
|
||||
}
|
||||
}
|
||||
|
||||
// Alternative optimized version for aligned 4-byte copies
|
||||
[numthreads(16, 16, 1)]
|
||||
void CSMainAligned(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
uint x = id.x;
|
||||
uint y = id.y;
|
||||
|
||||
// Process 4 pixels at once for better efficiency
|
||||
uint pixelsPerThread = 4;
|
||||
uint actualX = x * pixelsPerThread;
|
||||
|
||||
if (actualX >= srcWidth || y >= srcHeight)
|
||||
return;
|
||||
|
||||
// Calculate uint-aligned offsets
|
||||
uint srcRowOffset = (y * srcPitch) / 4;
|
||||
uint dstRowOffset = (y * dstPitch) / 4;
|
||||
uint pixelOffset = actualX / 4;
|
||||
|
||||
uint srcIndex = srcRowOffset + pixelOffset;
|
||||
uint dstIndex = dstRowOffset + pixelOffset;
|
||||
|
||||
// Copy one uint (4 bytes) containing 4 Y pixels or 4 U/V pixels
|
||||
dstBuffer[dstIndex] = srcBuffer[srcIndex];
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// YUVToRGB.hlsl - High-performance YUV to RGB conversion shader
|
||||
// Eliminates CPU-based color conversion bottleneck (11-19ms -> 0.1-0.5ms)
|
||||
|
||||
cbuffer ColorConversionConstants : register(b0)
|
||||
{
|
||||
matrix colorMatrix; // BT.709 or BT.2020 color conversion matrix
|
||||
float4 yuvOffsets; // Y, U, V offsets for different formats
|
||||
float4 yuvRanges; // Y, U, V ranges for normalization
|
||||
int2 videoSize; // Video width and height
|
||||
int2 padding; // Padding for 16-byte alignment
|
||||
};
|
||||
|
||||
// Input textures
|
||||
Texture2D yTexture : register(t0); // Y plane (luminance)
|
||||
Texture2D uTexture : register(t1); // U plane (chroma)
|
||||
Texture2D vTexture : register(t2); // V plane (chroma)
|
||||
|
||||
// Samplers
|
||||
SamplerState linearSampler : register(s0);
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float4 position : POSITION;
|
||||
float2 texCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float2 texCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
// Vertex Shader
|
||||
PSInput VSMain(VSInput input)
|
||||
{
|
||||
PSInput output;
|
||||
output.position = input.position;
|
||||
output.texCoord = input.texCoord;
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel Shader - Optimized BT.709 conversion
|
||||
float4 PSMain(PSInput input) : SV_TARGET
|
||||
{
|
||||
// Sample YUV values
|
||||
float y = yTexture.Sample(linearSampler, input.texCoord).r;
|
||||
float u = uTexture.Sample(linearSampler, input.texCoord).r;
|
||||
float v = vTexture.Sample(linearSampler, input.texCoord).r;
|
||||
|
||||
// Normalize to [0,1] range and apply offsets
|
||||
y = (y - yuvOffsets.x) * yuvRanges.x;
|
||||
u = (u - yuvOffsets.y) * yuvRanges.y - 0.5f;
|
||||
v = (v - yuvOffsets.z) * yuvRanges.z - 0.5f;
|
||||
|
||||
// BT.709 conversion matrix (optimized constants)
|
||||
float3 yuv = float3(y, u, v);
|
||||
float3 rgb = mul(colorMatrix, yuv);
|
||||
|
||||
// Clamp to valid range
|
||||
rgb = saturate(rgb);
|
||||
|
||||
return float4(rgb, 1.0f);
|
||||
}
|
||||
|
||||
// Alternative high-performance version with manual matrix
|
||||
float4 PSMainFast(PSInput input) : SV_TARGET
|
||||
{
|
||||
float y = yTexture.Sample(linearSampler, input.texCoord).r;
|
||||
float u = uTexture.Sample(linearSampler, input.texCoord).r;
|
||||
float v = vTexture.Sample(linearSampler, input.texCoord).r;
|
||||
|
||||
// BT.709 conversion with optimized constants
|
||||
float3 rgb;
|
||||
rgb.r = y + 1.402f * (v - 0.5f);
|
||||
rgb.g = y - 0.344f * (u - 0.5f) - 0.714f * (v - 0.5f);
|
||||
rgb.b = y + 1.772f * (u - 0.5f);
|
||||
|
||||
return float4(saturate(rgb), 1.0f);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Simple YUV-to-RGB Compute Shader for AV1 Video Playback
|
||||
// Phase 3: Clean GPU pipeline implementation
|
||||
|
||||
// Input textures
|
||||
Texture2D<float> YTexture : register(t0);
|
||||
Texture2D<float> UTexture : register(t1);
|
||||
Texture2D<float> VTexture : register(t2);
|
||||
|
||||
// Output texture
|
||||
RWTexture2D<float4> OutputTexture : register(u0);
|
||||
|
||||
// Constants for YUV-to-RGB conversion
|
||||
cbuffer ConversionConstants : register(b0)
|
||||
{
|
||||
uint VideoWidth;
|
||||
uint VideoHeight;
|
||||
uint OutputWidth;
|
||||
uint OutputHeight;
|
||||
};
|
||||
|
||||
// BT.709 YUV-to-RGB conversion matrix (standard for HD video)
|
||||
static const float3x3 YUVToRGBMatrix = float3x3(
|
||||
1.164f, 0.000f, 1.596f, // Y -> R
|
||||
1.164f, -0.392f, -0.813f, // Y -> G
|
||||
1.164f, 2.017f, 0.000f // Y -> B
|
||||
);
|
||||
|
||||
// Offsets for limited range YUV (16-235 for Y, 16-240 for UV)
|
||||
static const float3 YUVOffsets = float3(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f);
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void main(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
// Early exit if outside output bounds
|
||||
if (id.x >= OutputWidth || id.y >= OutputHeight)
|
||||
return;
|
||||
|
||||
// Calculate normalized coordinates for input sampling
|
||||
float2 uv = float2(id.x, id.y) / float2(OutputWidth - 1, OutputHeight - 1);
|
||||
|
||||
// Sample Y (full resolution)
|
||||
float Y = YTexture.SampleLevel(0, uv, 0).r;
|
||||
|
||||
// Sample U and V (half resolution for 4:2:0)
|
||||
float2 uvChroma = uv * float2(VideoWidth, VideoHeight) * 0.5f;
|
||||
float U = UTexture.SampleLevel(0, uvChroma / float2(VideoWidth * 0.5f, VideoHeight * 0.5f), 0).r;
|
||||
float V = VTexture.SampleLevel(0, uvChroma / float2(VideoWidth * 0.5f, VideoHeight * 0.5f), 0).r;
|
||||
|
||||
// Convert from limited range to full range
|
||||
float3 yuv = float3(Y, U, V) - YUVOffsets;
|
||||
yuv.x *= 255.0f / 219.0f; // Y: 16-235 -> 0-255
|
||||
yuv.yz *= 255.0f / 224.0f; // UV: 16-240 -> 0-255
|
||||
|
||||
// Apply YUV-to-RGB conversion matrix
|
||||
float3 rgb = mul(YUVToRGBMatrix, yuv);
|
||||
|
||||
// Clamp to valid range and output
|
||||
rgb = saturate(rgb);
|
||||
OutputTexture[id.xy] = float4(rgb, 1.0f);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// YUV to RGB Conversion Shader for AV1 Video Rendering
|
||||
// Optimized for GPU performance with BT.709 color space
|
||||
|
||||
// Input YUV textures (separate planes for YUV420P)
|
||||
Texture2D<float> YPlane : register(t0);
|
||||
Texture2D<float> UPlane : register(t1);
|
||||
Texture2D<float> VPlane : register(t2);
|
||||
|
||||
// Linear sampler for texture filtering
|
||||
SamplerState linearSampler : register(s0);
|
||||
|
||||
// Output render target
|
||||
struct VSOutput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float2 texCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
// Vertex Shader - Full-screen quad
|
||||
VSOutput VSMain(uint vertexID : SV_VertexID)
|
||||
{
|
||||
VSOutput output;
|
||||
|
||||
// Generate full-screen triangle using vertex ID
|
||||
// Covers entire screen with minimal vertex processing
|
||||
output.texCoord = float2((vertexID << 1) & 2, vertexID & 2);
|
||||
output.position = float4(output.texCoord * 2.0 - 1.0, 0.0, 1.0);
|
||||
output.position.y = -output.position.y; // Flip Y for D3D coordinate system
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel Shader - YUV to RGB conversion
|
||||
float4 PSMain(VSOutput input) : SV_TARGET
|
||||
{
|
||||
float2 texCoord = input.texCoord;
|
||||
|
||||
// Sample YUV values from separate texture planes
|
||||
float Y = YPlane.Sample(linearSampler, texCoord).r;
|
||||
|
||||
// For YUV420P, UV planes are half resolution
|
||||
// Sample with automatic bilinear filtering
|
||||
float U = UPlane.Sample(linearSampler, texCoord).r;
|
||||
float V = VPlane.Sample(linearSampler, texCoord).r;
|
||||
|
||||
// Convert from YUV [0,1] range to standard YUV ranges
|
||||
// Y: [16/255, 235/255] -> [0, 1]
|
||||
// UV: [16/255, 240/255] -> [-0.5, 0.5]
|
||||
Y = (Y - 16.0/255.0) * 255.0/(235.0-16.0);
|
||||
U = (U - 128.0/255.0);
|
||||
V = (V - 128.0/255.0);
|
||||
|
||||
// BT.709 YUV to RGB conversion matrix (GPU optimized)
|
||||
// R = Y + 1.5748 * V
|
||||
// G = Y - 0.1873 * U - 0.4681 * V
|
||||
// B = Y + 1.8556 * U
|
||||
float3 rgb;
|
||||
rgb.r = Y + 1.5748 * V;
|
||||
rgb.g = Y - 0.1873 * U - 0.4681 * V;
|
||||
rgb.b = Y + 1.8556 * U;
|
||||
|
||||
// Clamp to valid range and apply gamma correction
|
||||
rgb = saturate(rgb);
|
||||
|
||||
// Apply slight contrast enhancement for better visual quality
|
||||
rgb = pow(rgb, 0.95);
|
||||
|
||||
return float4(rgb, 1.0);
|
||||
}
|
||||
|
||||
// Compute Shader version for batch processing (optional optimization)
|
||||
[numthreads(8, 8, 1)]
|
||||
void CSMain(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
// TODO: Implement compute shader version for ultra-high resolution videos
|
||||
// This would be used for 8K+ content where pixel shader becomes bandwidth limited
|
||||
}
|
||||
Reference in New Issue
Block a user