Files
video-v1/vav2/platforms/windows/applications/vav2player/Vav2Player/MainVideoPage.xaml.cpp

299 lines
10 KiB
C++

#include "pch.h"
#include "MainVideoPage.xaml.h"
#if __has_include("MainVideoPage.g.cpp")
#include "MainVideoPage.g.cpp"
#endif
using namespace winrt;
using namespace winrt::Microsoft::UI::Xaml;
namespace winrt::Vav2Player::implementation
{
MainVideoPage::MainVideoPage()
{
InitializeComponent();
}
winrt::Windows::Foundation::IAsyncAction MainVideoPage::OpenFileButton_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try
{
// Create file picker
winrt::Windows::Storage::Pickers::FileOpenPicker picker;
picker.ViewMode(winrt::Windows::Storage::Pickers::PickerViewMode::Thumbnail);
picker.SuggestedStartLocation(winrt::Windows::Storage::Pickers::PickerLocationId::VideosLibrary);
// Add supported video file types
picker.FileTypeFilter().Append(L".webm");
picker.FileTypeFilter().Append(L".mkv");
picker.FileTypeFilter().Append(L".mp4");
picker.FileTypeFilter().Append(L".avi");
// Initialize picker with window handle - use simple approach for Page
try {
auto initializeWithWindow = picker.as<IInitializeWithWindow>();
// Get the active window handle
HWND hWnd = GetActiveWindow();
if (hWnd == nullptr)
{
hWnd = GetForegroundWindow();
}
if (hWnd != nullptr)
{
initializeWithWindow->Initialize(hWnd);
}
}
catch (...)
{
// If window handle initialization fails, continue without it
// FileOpenPicker might still work in some cases
}
// Show picker and get selected file
auto file = co_await picker.PickSingleFileAsync();
if (file != nullptr)
{
auto filePath = file.Path();
// Load video using VideoPlayerControl
if (VideoPlayer()) {
VideoPlayer().LoadVideo(filePath);
}
// Update UI
if (StatusText()) {
StatusText().Text(L"Loading video: " + filePath);
}
if (PlayButton()) PlayButton().IsEnabled(true);
if (PauseButton()) PauseButton().IsEnabled(true);
if (StopButton()) StopButton().IsEnabled(true);
}
else
{
if (StatusText()) {
StatusText().Text(L"No file selected");
}
}
}
catch (...)
{
if (StatusText()) {
StatusText().Text(L"Failed to open file picker or load video");
}
}
}
void MainVideoPage::TestDecodeButton_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (StatusText()) {
StatusText().Text(L"Test decode functionality - Coming soon");
}
} catch (...) {
// Ignore errors during initialization
}
}
void MainVideoPage::PlayButton_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (VideoPlayer()) {
VideoPlayer().Play();
}
if (StatusText()) {
StatusText().Text(L"Playing video...");
}
} catch (...) {
if (StatusText()) {
StatusText().Text(L"Failed to play video");
}
}
}
void MainVideoPage::PauseButton_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (VideoPlayer()) {
VideoPlayer().Pause();
}
if (StatusText()) {
StatusText().Text(L"Video paused");
}
} catch (...) {
if (StatusText()) {
StatusText().Text(L"Failed to pause video");
}
}
}
void MainVideoPage::StopButton_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (VideoPlayer()) {
VideoPlayer().Stop();
}
if (StatusText()) {
StatusText().Text(L"Video stopped");
}
} catch (...) {
if (StatusText()) {
StatusText().Text(L"Failed to stop video");
}
}
}
void MainVideoPage::DecoderSelectionComboBox_SelectionChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const&)
{
try {
if (StatusText()) {
StatusText().Text(L"Decoder selection changed");
}
} catch (...) {
// Ignore errors during initialization
}
}
void MainVideoPage::EnableFileOutputCheckBox_Checked(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (OutputFormatComboBox()) {
OutputFormatComboBox().IsEnabled(true);
}
if (StatusText()) {
StatusText().Text(L"File output enabled");
}
} catch (...) {
// Ignore errors during initialization
}
}
void MainVideoPage::EnableFileOutputCheckBox_Unchecked(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&)
{
try {
if (OutputFormatComboBox()) {
OutputFormatComboBox().IsEnabled(false);
}
if (StatusText()) {
StatusText().Text(L"File output disabled");
}
} catch (...) {
// Ignore errors during initialization
}
}
void MainVideoPage::OutputFormatComboBox_SelectionChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const&)
{
try {
if (StatusText()) {
StatusText().Text(L"Output format changed");
}
} catch (...) {
// Ignore errors during initialization
}
}
// Helper methods - actual implementations
void MainVideoPage::ConvertYUVToBGRA(const VavCoreVideoFrame& yuv_frame, uint8_t* bgra_buffer, uint32_t width, uint32_t height)
{
const uint8_t* y_plane = yuv_frame.y_plane;
const uint8_t* u_plane = yuv_frame.u_plane;
const uint8_t* v_plane = yuv_frame.v_plane;
const int32_t y_stride = yuv_frame.y_stride;
const int32_t u_stride = yuv_frame.u_stride;
const int32_t v_stride = yuv_frame.v_stride;
// Lookup table optimization
static bool lookup_initialized = false;
static int16_t r_v_table[256];
static int16_t g_u_table[256];
static int16_t g_v_table[256];
static int16_t b_u_table[256];
if (!lookup_initialized) {
for (int i = 0; i < 256; i++) {
int uv_val = i - 128;
r_v_table[i] = (409 * uv_val + 128) >> 8;
g_u_table[i] = (100 * uv_val + 128) >> 8;
g_v_table[i] = (208 * uv_val + 128) >> 8;
b_u_table[i] = (516 * uv_val + 128) >> 8;
}
lookup_initialized = true;
}
// Process 4 pixels at a time for cache efficiency
for (uint32_t row = 0; row < height; row += 2) {
for (uint32_t col = 0; col < width; col += 2) {
// UV values are one per 2x2 block
uint32_t uv_row = row / 2;
uint32_t uv_col = col / 2;
if (uv_row >= height / 2 || uv_col >= width / 2) continue;
int u = u_plane[uv_row * u_stride + uv_col];
int v = v_plane[uv_row * v_stride + uv_col];
// Get conversion coefficients from lookup table
int r_offset = r_v_table[v];
int g_u_offset = g_u_table[u];
int g_v_offset = g_v_table[v];
int b_offset = b_u_table[u];
// Process 4 pixels in 2x2 block
for (int dy = 0; dy < 2 && (row + dy) < height; dy++) {
for (int dx = 0; dx < 2 && (col + dx) < width; dx++) {
uint32_t pixel_row = row + dy;
uint32_t pixel_col = col + dx;
int y = y_plane[pixel_row * y_stride + pixel_col];
int y_scaled = (298 * (y - 16) + 128) >> 8;
// RGB calculation
int r = std::clamp(y_scaled + r_offset, 0, 255);
int g = std::clamp(y_scaled - g_u_offset - g_v_offset, 0, 255);
int b = std::clamp(y_scaled + b_offset, 0, 255);
// Store as BGRA format
uint32_t pixel_offset = (pixel_row * width + pixel_col) * 4;
bgra_buffer[pixel_offset + 0] = static_cast<uint8_t>(b);
bgra_buffer[pixel_offset + 1] = static_cast<uint8_t>(g);
bgra_buffer[pixel_offset + 2] = static_cast<uint8_t>(r);
bgra_buffer[pixel_offset + 3] = 255;
}
}
}
}
}
void MainVideoPage::RenderFrameToScreen(const VavCoreVideoFrame& frame, winrt::Microsoft::UI::Xaml::Media::Imaging::WriteableBitmap& bitmap, std::vector<uint8_t>& bgra_buffer)
{
// Check for valid frame and bitmap
if (!frame.y_plane || !bitmap) {
return;
}
try {
// Convert YUV to BGRA
ConvertYUVToBGRA(frame, bgra_buffer.data(), frame.width, frame.height);
// Get direct access to WriteableBitmap pixel buffer
auto buffer = bitmap.PixelBuffer();
auto byteAccess = buffer.as<::IBufferByteAccess>();
uint8_t* dest_pixels = nullptr;
byteAccess->Buffer(&dest_pixels);
if (dest_pixels) {
// Direct memory copy to minimize overhead
memcpy(dest_pixels, bgra_buffer.data(), bgra_buffer.size());
// Invalidate bitmap to trigger UI update
bitmap.Invalidate();
}
}
catch (...) {
// Ignore rendering errors
}
}
}