Fix 2x2 Grid change bug
This commit is contained in:
@@ -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 -->
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user