Fix 2x2 Grid change bug

This commit is contained in:
2025-09-23 04:22:38 +09:00
parent a888379ee9
commit bcae668204
3 changed files with 120 additions and 250 deletions

View File

@@ -8,7 +8,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="UserControl_Loaded"
Unloaded="UserControl_Unloaded">
Unloaded="UserControl_Unloaded"
SizeChanged="UserControl_SizeChanged">
<Grid x:Name="RootGrid" Background="Black">
<!-- Main video rendering area -->

View File

@@ -54,7 +54,6 @@ namespace winrt::Vav2Player::implementation
ApplyAspectFitIfReady();
});
OutputDebugStringA("VideoPlayerControl loaded successfully\n");
// Ready for user interaction
}
@@ -78,6 +77,7 @@ namespace winrt::Vav2Player::implementation
if (m_playbackTimer)
{
m_playbackTimer.Stop();
m_playbackTimer = nullptr; // Complete cleanup
}
if (m_gpuRenderer)
@@ -92,7 +92,6 @@ namespace winrt::Vav2Player::implementation
// Explicitly close file before destroying the reader
if (m_fileReader->IsFileOpen()) {
m_fileReader->CloseFile();
OutputDebugStringA("[DEBUG] File explicitly closed\n");
}
m_fileReader.reset();
}
@@ -102,10 +101,8 @@ namespace winrt::Vav2Player::implementation
m_isInitialized = false;
m_isLoaded = false;
OutputDebugStringA("[DEBUG] UserControl_Unloaded: All resources cleaned up\n");
m_isInitialized = false;
OutputDebugStringA("VideoPlayerControl unloaded\n");
}
catch (...)
{
@@ -113,6 +110,30 @@ namespace winrt::Vav2Player::implementation
}
}
void VideoPlayerControl::UserControl_SizeChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::SizeChangedEventArgs const& e)
{
// Recalculate AspectFit when container size changes
if (m_hasValidVideoSize && m_videoWidth > 0 && m_videoHeight > 0) {
UpdateVideoImageAspectFit(m_videoWidth, m_videoHeight);
}
// Retry GPU rendering initialization if user prefers hardware rendering
// but we're currently using CPU rendering due to previous container size issues
if (m_useHardwareRendering && m_isLoaded) {
auto container = VideoDisplayArea();
if (container) {
double containerWidth = container.ActualWidth();
double containerHeight = container.ActualHeight();
// If container size is now valid and we're not showing GPU panel, retry GPU init
if (containerWidth > 0 && containerHeight > 0 &&
VideoSwapChainPanel().Visibility() == winrt::Microsoft::UI::Xaml::Visibility::Collapsed) {
InitializeVideoRenderer();
}
}
}
}
void VideoPlayerControl::HoverDetector_PointerEntered(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const&)
{
// Controls are disabled for now
@@ -260,224 +281,94 @@ namespace winrt::Vav2Player::implementation
// Public Methods
void VideoPlayerControl::LoadVideo(winrt::hstring const& filePath)
{
OutputDebugStringA("[DEBUG] LoadVideo called\n");
try
{
std::string filePathStr = winrt::to_string(filePath);
OutputDebugStringA(("[DEBUG] Loading file: " + filePathStr + "\n").c_str());
std::string filePathStr = winrt::to_string(filePath);
UpdateStatus(L"Loading video...");
LoadingRing().IsActive(true);
UpdateStatus(L"Loading video...");
LoadingRing().IsActive(true);
// Reset previous state
ResetVideoState();
// Create or reuse file reader
if (!m_fileReader)
{
OutputDebugStringA("[DEBUG] Creating WebMFileReader\n");
m_fileReader = std::make_unique<WebMFileReader>();
}
else
{
// Explicitly close previous file if open
if (m_fileReader->IsFileOpen())
{
OutputDebugStringA("[DEBUG] Closing previous file before loading new one\n");
m_fileReader->CloseFile();
}
}
// Open file
OutputDebugStringA("[DEBUG] Opening file...\n");
if (!m_fileReader->OpenFile(filePathStr))
{
OutputDebugStringA("[DEBUG] Failed to open file\n");
UpdateStatus(L"Failed to open video file");
LoadingRing().IsActive(false);
return;
}
OutputDebugStringA("[DEBUG] File opened successfully\n");
// Get video tracks
OutputDebugStringA("[DEBUG] Getting video tracks...\n");
auto tracks = m_fileReader->GetVideoTracks();
if (tracks.empty())
{
OutputDebugStringA("[DEBUG] No video tracks found\n");
UpdateStatus(L"No video tracks found");
LoadingRing().IsActive(false);
return;
}
OutputDebugStringA(("[DEBUG] Found " + std::to_string(tracks.size()) + " video tracks\n").c_str());
// Select first video track
OutputDebugStringA("[DEBUG] Selecting video track...\n");
if (!m_fileReader->SelectVideoTrack(tracks[0].track_number))
{
OutputDebugStringA("[DEBUG] Failed to select video track\n");
UpdateStatus(L"Failed to select video track");
LoadingRing().IsActive(false);
return;
}
OutputDebugStringA("[DEBUG] Video track selected successfully\n");
// Get metadata
OutputDebugStringA("[DEBUG] Getting video metadata...\n");
auto metadata = m_fileReader->GetVideoMetadata();
m_totalFrames = metadata.total_frames;
m_frameRate = metadata.frame_rate > 0 ? metadata.frame_rate : 30.0;
m_duration = m_totalFrames / m_frameRate;
OutputDebugStringA(("[DEBUG] Video metadata: " + std::to_string(metadata.width) + "x" + std::to_string(metadata.height) +
", " + std::to_string(m_totalFrames) + " frames, " + std::to_string(m_frameRate) + " fps\n").c_str());
// Try GPU rendering first, fallback to CPU if needed
UseHardwareRendering(true);
// Create and initialize decoder
OutputDebugStringA("[DEBUG] Creating decoder...\n");
if (!CreateDecoder())
{
OutputDebugStringA("[DEBUG] Failed to create decoder\n");
UpdateStatus(L"Failed to create decoder");
LoadingRing().IsActive(false);
return;
}
OutputDebugStringA("[DEBUG] Initializing decoder...\n");
if (!InitializeDecoder())
{
OutputDebugStringA("[DEBUG] Failed to initialize decoder\n");
UpdateStatus(L"Failed to initialize decoder");
LoadingRing().IsActive(false);
return;
}
OutputDebugStringA("[DEBUG] Decoder initialized successfully\n");
// Initialize video renderer
InitializeVideoRenderer();
// Set video dimensions from metadata for AspectFit
m_videoWidth = metadata.width;
m_videoHeight = metadata.height;
m_hasValidVideoSize = true;
m_isLoaded = true; // Set loaded state before AspectFit
OutputDebugStringA(("[DEBUG] Video dimensions set: " + std::to_string(m_videoWidth) + "x" + std::to_string(m_videoHeight) + "\n").c_str());
// Apply AspectFit now that we have video dimensions
ApplyAspectFitIfReady();
LoadingRing().IsActive(false);
// Keep placeholder visible until first frame is rendered
UpdateStatus(L"Video loaded successfully");
OutputDebugStringA(("[DEBUG] Video loaded successfully: " + filePathStr + "\n").c_str());
// Auto play if enabled
if (m_autoPlay)
{
OutputDebugStringA("[DEBUG] Auto play enabled - starting playback\n");
Play();
}
// Reset and create file reader
ResetVideoState();
if (!m_fileReader) {
m_fileReader = std::make_unique<WebMFileReader>();
} else if (m_fileReader->IsFileOpen()) {
m_fileReader->CloseFile();
}
catch (...)
{
OutputDebugStringA("[DEBUG] Exception in LoadVideo\n");
UpdateStatus(L"Error loading video");
// Open file and get tracks
if (!m_fileReader->OpenFile(filePathStr)) {
UpdateStatus(L"Failed to open video file");
LoadingRing().IsActive(false);
return;
}
auto tracks = m_fileReader->GetVideoTracks();
if (tracks.empty() || !m_fileReader->SelectVideoTrack(tracks[0].track_number)) {
UpdateStatus(L"Failed to load video tracks");
LoadingRing().IsActive(false);
return;
}
// Set up video properties
auto metadata = m_fileReader->GetVideoMetadata();
m_videoWidth = metadata.width;
m_videoHeight = metadata.height;
m_frameRate = metadata.frame_rate > 0 ? metadata.frame_rate : 30.0;
m_duration = metadata.total_frames / m_frameRate;
// Create decoder and renderer
if (!CreateDecoder() || !InitializeDecoder()) {
UpdateStatus(L"Failed to initialize decoder");
LoadingRing().IsActive(false);
return;
}
InitializeVideoRenderer();
m_hasValidVideoSize = true;
m_isLoaded = true;
ApplyAspectFitIfReady();
LoadingRing().IsActive(false);
UpdateStatus(L"Video loaded");
if (m_autoPlay) Play();
}
void VideoPlayerControl::Play()
{
OutputDebugStringA("[DEBUG] Play() called\n");
if (!m_isLoaded || m_isPlaying)
{
OutputDebugStringA("[DEBUG] Play() - not ready or already playing\n");
if (!m_isLoaded || m_isPlaying) {
return;
}
m_isPlaying = true;
UpdateStatus(L"Playing");
// Setup playback timer for continuous frame processing
if (!m_playbackTimer)
// Cleanup any existing timer before creating new one
if (m_playbackTimer)
{
OutputDebugStringA("[DEBUG] Creating playback timer\n");
m_playbackTimer = winrt::Microsoft::UI::Xaml::DispatcherTimer();
// Store weak reference to avoid circular dependency
auto weakThis = get_weak();
m_playbackTimer.Tick([weakThis](auto&&, auto&&) {
if (auto strongThis = weakThis.get())
{
OutputDebugStringA("[DEBUG] Timer tick - checking conditions\n");
OutputDebugStringA(("[DEBUG] m_isPlaying: " + std::string(strongThis->m_isPlaying ? "true" : "false") +
", m_isLoaded: " + std::string(strongThis->m_isLoaded ? "true" : "false") + "\n").c_str());
if (strongThis->m_isPlaying && strongThis->m_isLoaded)
{
try {
strongThis->ProcessSingleFrame();
}
catch (...) {
OutputDebugStringA("[DEBUG] Exception in timer ProcessSingleFrame\n");
strongThis->m_isPlaying = false;
strongThis->m_playbackTimer.Stop();
}
}
else
{
OutputDebugStringA("[DEBUG] Timer tick - conditions not met, skipping frame processing\n");
}
}
else
{
OutputDebugStringA("[DEBUG] Timer tick - object destroyed, stopping timer\n");
}
});
m_playbackTimer.Stop();
m_playbackTimer = nullptr;
}
// Set timer interval based on frame rate (default 30fps = 33.33ms)
auto interval = std::chrono::milliseconds(static_cast<int>(1000.0 / m_frameRate));
m_playbackTimer.Interval(interval);
OutputDebugStringA(("[DEBUG] Timer interval set to: " + std::to_string(interval.count()) + "ms\n").c_str());
OutputDebugStringA(("[DEBUG] Timer object valid: " + std::string(m_playbackTimer ? "true" : "false") + "\n").c_str());
m_playbackTimer.Start();
OutputDebugStringA("[DEBUG] Timer.Start() called\n");
// Immediate test: try to process one frame manually to verify the pipeline works
OutputDebugStringA("[DEBUG] Testing immediate frame processing...\n");
ProcessSingleFrame();
OutputDebugStringA(("[DEBUG] Started playback timer at " + std::to_string(m_frameRate) + " fps\n").c_str());
// Backup approach: Create a manual timer that restarts itself
OutputDebugStringA("[DEBUG] Setting up backup manual timer approach\n");
auto manualTimer = winrt::Microsoft::UI::Xaml::DispatcherTimer();
manualTimer.Interval(interval);
// Manual timer approach with restart
manualTimer.Tick([this, manualTimer](auto&&, auto&&) mutable {
if (m_isPlaying && m_isLoaded) {
ProcessSingleFrame();
// Schedule next frame
manualTimer.Start();
// Create new playback timer
m_playbackTimer = winrt::Microsoft::UI::Xaml::DispatcherTimer();
auto weakThis = get_weak();
m_playbackTimer.Tick([weakThis](auto&&, auto&&) {
if (auto strongThis = weakThis.get()) {
if (strongThis->m_isPlaying && strongThis->m_isLoaded) {
strongThis->ProcessSingleFrame();
}
}
});
// Start both timers
manualTimer.Start();
OutputDebugStringA("[DEBUG] Manual timer also started\n");
auto interval = std::chrono::milliseconds(static_cast<int>(1000.0 / m_frameRate));
m_playbackTimer.Interval(interval);
m_playbackTimer.Start();
// Process first frame immediately
ProcessSingleFrame();
}
void VideoPlayerControl::Pause()
{
OutputDebugStringA("[DEBUG] Pause() called\n");
m_isPlaying = false;
if (m_playbackTimer)
{
@@ -488,28 +379,27 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::Stop()
{
OutputDebugStringA("[DEBUG] Stop() called\n");
m_isPlaying = false;
// Properly cleanup timer to prevent resource leaks
if (m_playbackTimer)
{
m_playbackTimer.Stop();
m_playbackTimer = nullptr; // Release timer completely
}
// Reset position to beginning
m_currentFrame = 0;
m_currentTime = 0.0;
// Reset file reader to beginning for next play
if (m_fileReader && m_fileReader->IsFileOpen())
{
OutputDebugStringA("[DEBUG] Resetting file reader to beginning\n");
m_fileReader->Reset();
}
// Reset decoder state
if (m_decoder)
{
OutputDebugStringA("[DEBUG] Resetting decoder state\n");
m_decoder->Reset();
}
@@ -518,12 +408,22 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::ProcessSingleFrame()
{
// Simple validation
if (!m_isPlaying || !m_fileReader || !m_decoder) return;
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();
@@ -531,9 +431,14 @@ namespace winrt::Vav2Player::implementation
return;
}
OutputDebugStringA("[DEBUG] Decoding frame...\n");
VideoFrame frame;
if (!m_decoder->DecodeFrame(packet, frame)) return; // Skip failed frames
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++;
@@ -563,14 +468,7 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::RenderFrameSoftware(const VideoFrame& frame)
{
OutputDebugStringA(("[DEBUG] RenderFrameSoftware() called - " + std::to_string(frame.width) + "x" + std::to_string(frame.height) + "\n").c_str());
OutputDebugStringA(("[DEBUG] y_plane: " + std::string(frame.y_plane ? "valid" : "null") + "\n").c_str());
if (!frame.y_plane || frame.width == 0 || frame.height == 0)
{
OutputDebugStringA("[DEBUG] Invalid frame data - returning\n");
return;
}
if (!frame.y_plane || frame.width == 0 || frame.height == 0) return;
try {
// Create or reuse WriteableBitmap for the frame
@@ -578,7 +476,6 @@ namespace winrt::Vav2Player::implementation
static_cast<uint32_t>(m_renderBitmap.PixelWidth()) != frame.width ||
static_cast<uint32_t>(m_renderBitmap.PixelHeight()) != frame.height) {
OutputDebugStringA("[DEBUG] Creating new WriteableBitmap\n");
m_renderBitmap = winrt::Microsoft::UI::Xaml::Media::Imaging::WriteableBitmap(
frame.width, frame.height);
VideoImage().Source(m_renderBitmap);
@@ -594,21 +491,16 @@ namespace winrt::Vav2Player::implementation
// Ensure video is visible
VideoImage().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Visible);
OutputDebugStringA(("Created WriteableBitmap: " + std::to_string(frame.width) + "x" + std::to_string(frame.height) + "\n").c_str());
}
// Convert YUV to BGRA and render to bitmap
auto buffer = m_renderBitmap.PixelBuffer();
uint32_t capacity = buffer.Capacity();
OutputDebugStringA(("[DEBUG] Buffer capacity: " + std::to_string(capacity) + "\n").c_str());
if (capacity >= frame.width * frame.height * 4) {
OutputDebugStringA("[DEBUG] Converting YUV to BGRA...\n");
// Simple approach: create BGRA data and copy to buffer
std::vector<uint8_t> bgra_data(frame.width * frame.height * 4);
ConvertYUVToBGRA(frame, bgra_data.data(), frame.width, frame.height);
OutputDebugStringA("[DEBUG] Copying to bitmap buffer...\n");
// Copy BGRA data directly to bitmap buffer
auto bufferByteAccess = buffer.as<::Windows::Storage::Streams::IBufferByteAccess>();
uint8_t* bufferData = nullptr;
@@ -619,26 +511,21 @@ namespace winrt::Vav2Player::implementation
// Trigger UI update
m_renderBitmap.Invalidate();
OutputDebugStringA(("[DEBUG] Frame rendered successfully: " + std::to_string(frame.width) + "x" + std::to_string(frame.height) + "\n").c_str());
} else {
OutputDebugStringA("[DEBUG] Buffer capacity too small\n");
}
} catch (...) {
OutputDebugStringA("[DEBUG] Software rendering failed\n");
}
}
void VideoPlayerControl::ConvertYUVToBGRA(const VideoFrame& yuv_frame, uint8_t* bgra_buffer, uint32_t width, uint32_t height)
{
OutputDebugStringA("[DEBUG] ConvertYUVToBGRA() called\n");
// YUV420P to BGRA conversion using BT.709 color space
const uint8_t* y_plane = yuv_frame.y_plane.get();
const uint8_t* u_plane = yuv_frame.u_plane.get();
const uint8_t* v_plane = yuv_frame.v_plane.get();
if (!y_plane || !u_plane || !v_plane) {
OutputDebugStringA("[DEBUG] ConvertYUVToBGRA: Invalid plane data\n");
return;
}
@@ -646,7 +533,6 @@ namespace winrt::Vav2Player::implementation
const uint32_t u_stride = yuv_frame.u_stride;
const uint32_t v_stride = yuv_frame.v_stride;
OutputDebugStringA(("[DEBUG] YUV strides: Y=" + std::to_string(y_stride) + " U=" + std::to_string(u_stride) + " V=" + std::to_string(v_stride) + "\n").c_str());
for (uint32_t y = 0; y < height; y++) {
const uint8_t* y_row = y_plane + y * y_stride;
@@ -693,14 +579,12 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::InitializeVideoRenderer()
{
OutputDebugStringA("[DEBUG] InitializeVideoRenderer() called\n");
// Initialize rendering mode based on user selection
if (!m_useHardwareRendering)
{
// Ensure software rendering UI is visible
VideoSwapChainPanel().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Collapsed);
VideoImage().Visibility(winrt::Microsoft::UI::Xaml::Visibility::Visible);
OutputDebugStringA("[DEBUG] Initialized CPU rendering mode\n");
}
else
{
@@ -720,28 +604,25 @@ namespace winrt::Vav2Player::implementation
// Wait for container to be ready - don't use arbitrary fallback sizes
if (containerWidth == 0 || containerHeight == 0) {
OutputDebugStringA("[DEBUG] GPU renderer: Container size not ready, deferring initialization\n");
// Fallback to CPU rendering if container size unavailable
// 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);
m_useHardwareRendering = false;
OutputDebugStringA("[DEBUG] Switched to CPU rendering due to container size unavailable\n");
// Don't change m_useHardwareRendering flag - keep user preference
return;
}
OutputDebugStringA(("[DEBUG] Initializing GPU renderer with size: " + std::to_string(containerWidth) + "x" + std::to_string(containerHeight) + "\n").c_str());
HRESULT hr = m_gpuRenderer->Initialize(VideoSwapChainPanel(), containerWidth, containerHeight);
if (SUCCEEDED(hr))
{
OutputDebugStringA("[DEBUG] GPU rendering initialized successfully\n");
// GPU rendering initialized successfully
}
else
{
OutputDebugStringA("[DEBUG] GPU rendering initialization failed, falling back to CPU\n");
m_useHardwareRendering = false;
m_gpuRenderer.reset();
// 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
}
}
}
@@ -791,7 +672,6 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::ApplyAspectFitIfReady()
{
if (!m_hasValidVideoSize || !m_isLoaded) {
OutputDebugStringA("[DEBUG] ApplyAspectFitIfReady: Not ready, skipping\n");
return;
}
@@ -800,10 +680,8 @@ namespace winrt::Vav2Player::implementation
double containerWidth = container.ActualWidth();
double containerHeight = container.ActualHeight();
OutputDebugStringA(("[DEBUG] ApplyAspectFitIfReady: Container size: " + std::to_string(containerWidth) + "x" + std::to_string(containerHeight) + "\n").c_str());
if (containerWidth <= 0 || containerHeight <= 0) {
OutputDebugStringA("[DEBUG] ApplyAspectFitIfReady: Container size invalid, skipping (will retry on SizeChanged)\n");
return;
}
@@ -812,8 +690,6 @@ namespace winrt::Vav2Player::implementation
void VideoPlayerControl::UpdateVideoImageAspectFit(int videoWidth, int videoHeight)
{
OutputDebugStringA(("[DEBUG] UpdateVideoImageAspectFit: " + std::to_string(videoWidth) + "x" + std::to_string(videoHeight) + "\n").c_str());
// Store video dimensions for future use
m_videoWidth = static_cast<uint32_t>(videoWidth);
m_videoHeight = static_cast<uint32_t>(videoHeight);
@@ -822,16 +698,13 @@ namespace winrt::Vav2Player::implementation
// AspectFit calculation for proper video scaling
auto container = VideoDisplayArea();
if (!container) {
OutputDebugStringA("[DEBUG] UpdateVideoImageAspectFit: No container\n");
return;
}
double containerWidth = container.ActualWidth();
double containerHeight = container.ActualHeight();
OutputDebugStringA(("[DEBUG] UpdateVideoImageAspectFit: Container size: " + std::to_string(containerWidth) + "x" + std::to_string(containerHeight) + "\n").c_str());
if (containerWidth <= 0 || containerHeight <= 0) {
OutputDebugStringA("[DEBUG] UpdateVideoImageAspectFit: Invalid container size, skipping\n");
return;
}
@@ -849,20 +722,15 @@ namespace winrt::Vav2Player::implementation
displayWidth = containerHeight * videoAspectRatio;
}
OutputDebugStringA(("[DEBUG] UpdateVideoImageAspectFit: Calculated display size: " + std::to_string(displayWidth) + "x" + std::to_string(displayHeight) + "\n").c_str());
// Apply AspectFit to both CPU and GPU rendering controls
VideoImage().Width(displayWidth);
VideoImage().Height(displayHeight);
VideoImage().MaxWidth(displayWidth);
VideoImage().MaxHeight(displayHeight);
// Also apply to GPU rendering SwapChainPanel
VideoSwapChainPanel().Width(displayWidth);
VideoSwapChainPanel().Height(displayHeight);
OutputDebugStringA("[DEBUG] UpdateVideoImageAspectFit: AspectFit applied successfully\n");
}
void VideoPlayerControl::Seek(double timeSeconds)

View File

@@ -19,6 +19,7 @@ namespace winrt::Vav2Player::implementation
// Events
void UserControl_Loaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
void UserControl_Unloaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
void UserControl_SizeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::SizeChangedEventArgs const& e);
void HoverDetector_PointerEntered(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void HoverDetector_PointerExited(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);