This UI is old and horrible, make an entire new frontend with modern ui while keeping the same functionality (even improving UX). Use your imagination and creativity

#### main.cpp
```cpp
// main.cpp
#include <windows.h>
#include <commdlg.h>  // For file dialog
#include <commctrl.h> // For common controls
#include <shellapi.h> // For drag-and-drop
#include "video_player.h"
#include <string>
#include <cstdio> // For swprintf_s

// Control IDs
#define ID_BUTTON_OPEN 1001
#define ID_BUTTON_PLAY 1002
#define ID_BUTTON_PAUSE 1003
#define ID_BUTTON_STOP 1004
#define ID_SLIDER_SEEK 1005
#define ID_TIMER_UPDATE 1006
#define ID_LISTBOX_AUDIO_TRACKS 1007
#define ID_BUTTON_MUTE_TRACK 1008
#define ID_SLIDER_TRACK_VOLUME 1009
#define ID_SLIDER_MASTER_VOLUME 1010

// Range for the seek slider (higher value = finer granularity)
#define SEEK_SLIDER_MAX 1000

// Editing Control IDs
#define ID_BUTTON_SET_START 1011
#define ID_BUTTON_SET_END 1012
#define ID_BUTTON_CUT 1013
#define ID_CHECKBOX_MERGE_AUDIO 1014
// Global variables
VideoPlayer *g_videoPlayer = nullptr;
HWND g_hButtonOpen, g_hButtonPlay, g_hButtonPause, g_hButtonStop;
HWND g_hSliderSeek;
HWND g_hStatusText;
HWND g_hListBoxAudioTracks, g_hButtonMuteTrack;
HWND g_hSliderTrackVolume, g_hSliderMasterVolume;
HWND g_hLabelAudioTracks, g_hLabelTrackVolume, g_hLabelMasterVolume, g_hLabelEditing;
HWND g_hButtonSetStart, g_hButtonSetEnd, g_hButtonCut, g_hCheckboxMergeAudio;
HWND g_hLabelCutInfo;
double g_cutStartTime = -1.0;
double g_cutEndTime = -1.0;

// Function declarations
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void CreateControls(HWND hwnd);
void OpenVideoFile(HWND hwnd);
void LoadVideoFile(HWND hwnd, const std::wstring& filename);
void UpdateControls();
void UpdateSeekBar();
void UpdateAudioTrackList();
void OnAudioTrackSelectionChanged();
void OnMuteTrackClicked();
void OnTrackVolumeChanged();
void OnMasterVolumeChanged();
void UpdateCutInfoLabel(HWND hwnd);
void OnSetStartClicked(HWND hwnd);
void OnSetEndClicked(HWND hwnd);
void OnCutClicked(HWND hwnd);
std::wstring FormatTime(double totalSeconds, bool showMilliseconds = false);
void RepositionControls(HWND hwnd);


// Window procedure
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        CreateControls(hwnd);
        g_videoPlayer = new VideoPlayer(hwnd);
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)g_videoPlayer);
        SetTimer(hwnd, ID_TIMER_UPDATE, 100, nullptr); // Update every 100ms
        DragAcceptFiles(hwnd, TRUE);
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_BUTTON_OPEN:
            OpenVideoFile(hwnd);
            break;
        case ID_BUTTON_PLAY:
            if (g_videoPlayer && g_videoPlayer->IsLoaded())
            {
                g_videoPlayer->Play();
                UpdateControls();
            }
            break;
        case ID_BUTTON_PAUSE:
            if (g_videoPlayer)
            {
                g_videoPlayer->Pause();
                UpdateControls();
            }
            break;
        case ID_BUTTON_STOP:
            if (g_videoPlayer)
            {
                g_videoPlayer->Stop();
                UpdateControls();
                UpdateSeekBar();
            }
            break;
        case ID_BUTTON_MUTE_TRACK:
            OnMuteTrackClicked();
            break;
        case ID_BUTTON_SET_START:
            OnSetStartClicked(hwnd);
            break;
        case ID_BUTTON_SET_END:
            OnSetEndClicked(hwnd);
            break;
        case ID_BUTTON_CUT:
            OnCutClicked(hwnd);
            break;
        }
        
        // Handle listbox selection changes
        if (HIWORD(wParam) == LBN_SELCHANGE && (HWND)lParam == g_hListBoxAudioTracks)
        {
            OnAudioTrackSelectionChanged();
        }
        break;

    case WM_HSCROLL:
        if ((HWND)lParam == g_hSliderSeek && g_videoPlayer && g_videoPlayer->IsLoaded())
        {
            int pos = (int)SendMessage(g_hSliderSeek, TBM_GETPOS, 0, 0);
            double duration = g_videoPlayer->GetDuration();
            double seekTime = (pos / (double)SEEK_SLIDER_MAX) * duration;

            bool wasPlaying = g_videoPlayer->IsPlaying();
            if (wasPlaying)
                g_videoPlayer->Pause();

            g_videoPlayer->SeekToTime(seekTime);

            if (wasPlaying)
                g_videoPlayer->Play();

            UpdateControls();
        }
        else if ((HWND)lParam == g_hSliderTrackVolume)
        {
            OnTrackVolumeChanged();
        }
        else if ((HWND)lParam == g_hSliderMasterVolume)
        {
            OnMasterVolumeChanged();
        }
        break;

    case WM_TIMER:
        if (wParam == ID_TIMER_UPDATE)
        {
            UpdateSeekBar();
            UpdateControls();
        }
        break;

    case WM_DROPFILES:
    {
        HDROP hDrop = (HDROP)wParam;
        wchar_t filePath[MAX_PATH];
        if (DragQueryFileW(hDrop, 0, filePath, MAX_PATH))
        {
            LoadVideoFile(hwnd, std::wstring(filePath));
        }
        DragFinish(hDrop);
    }
    break;

    case WM_SIZE:
    {
        RepositionControls(hwnd);
    }
    break;

    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;

    case WM_DESTROY:
        if (g_videoPlayer)
        {
            delete g_videoPlayer;
            g_videoPlayer = nullptr;
        }
        KillTimer(hwnd, ID_TIMER_UPDATE);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

void CreateControls(HWND hwnd)
{
    InitCommonControls();

    // Open button
    g_hButtonOpen = CreateWindow(
        L"BUTTON", L"Open Video",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        10, 10, 100, 30,
        hwnd, (HMENU)ID_BUTTON_OPEN,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Play button
    g_hButtonPlay = CreateWindow(
        L"BUTTON", L"Play",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        120, 10, 60, 30,
        hwnd, (HMENU)ID_BUTTON_PLAY,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Pause button
    g_hButtonPause = CreateWindow(
        L"BUTTON", L"Pause",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        190, 10, 60, 30,
        hwnd, (HMENU)ID_BUTTON_PAUSE,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Stop button
    g_hButtonStop = CreateWindow(
        L"BUTTON", L"Stop",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        260, 10, 60, 30,
        hwnd, (HMENU)ID_BUTTON_STOP,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Seek slider
    g_hSliderSeek = CreateWindow(
        TRACKBAR_CLASS, L"Seek",
        WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_BOTH,
        10, 370, 600, 30, // Placeholder position
        hwnd, (HMENU)ID_SLIDER_SEEK,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
    SendMessage(g_hSliderSeek, TBM_SETRANGE, TRUE, MAKELONG(0, SEEK_SLIDER_MAX));
    SendMessage(g_hSliderSeek, TBM_SETPOS, TRUE, 0);

    // Status text
    g_hStatusText = CreateWindow(
        L"STATIC", L"No video loaded",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        10, 410, 600, 20, // Placeholder position
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Audio controls section
    // Audio tracks label
    g_hLabelAudioTracks = CreateWindow(
        L"STATIC", L"Audio Tracks:",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        340, 50, 100, 20, // Placeholder position
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Audio tracks listbox
    g_hListBoxAudioTracks = CreateWindow(
        L"LISTBOX", nullptr,
        WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY,
        340, 75, 200, 100, // Placeholder position
        hwnd, (HMENU)ID_LISTBOX_AUDIO_TRACKS,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Mute track button
    g_hButtonMuteTrack = CreateWindow(
        L"BUTTON", L"Mute/Unmute",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        340, 185, 100, 25, // Placeholder position
        hwnd, (HMENU)ID_BUTTON_MUTE_TRACK,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Track volume label
    g_hLabelTrackVolume = CreateWindow(
        L"STATIC", L"Track Volume:",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        340, 220, 100, 20, // Placeholder position
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Track volume slider
    g_hSliderTrackVolume = CreateWindow(
        TRACKBAR_CLASS, L"Track Volume",
        WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_BOTH,
        340, 245, 200, 30, // Placeholder position
        hwnd, (HMENU)ID_SLIDER_TRACK_VOLUME,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
    SendMessage(g_hSliderTrackVolume, TBM_SETRANGE, TRUE, MAKELONG(0, 200)); // 0-200% volume
    SendMessage(g_hSliderTrackVolume, TBM_SETPOS, TRUE, 100); // Default 100%

    // Master volume label
    g_hLabelMasterVolume = CreateWindow(
        L"STATIC", L"Master Volume:",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        340, 285, 100, 20, // Placeholder position
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    // Master volume slider
    g_hSliderMasterVolume = CreateWindow(
        TRACKBAR_CLASS, L"Master Volume",
        WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_BOTH,
        340, 310, 200, 30, // Placeholder position
        hwnd, (HMENU)ID_SLIDER_MASTER_VOLUME,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
    SendMessage(g_hSliderMasterVolume, TBM_SETRANGE, TRUE, MAKELONG(0, 200)); // 0-200% volume
    SendMessage(g_hSliderMasterVolume, TBM_SETPOS, TRUE, 100); // Default 100%

    // Editing controls section
    g_hLabelEditing = CreateWindow(
        L"STATIC", L"Editing:",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        340, 350, 100, 20, // Placeholder
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    g_hButtonSetStart = CreateWindow(
        L"BUTTON", L"Set Start",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        340, 375, 95, 25, // Placeholder
        hwnd, (HMENU)ID_BUTTON_SET_START,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    g_hButtonSetEnd = CreateWindow(
        L"BUTTON", L"Set End",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        445, 375, 95, 25, // Placeholder
        hwnd, (HMENU)ID_BUTTON_SET_END,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    g_hLabelCutInfo = CreateWindow(
        L"STATIC", L"Cut points not set.",
        WS_VISIBLE | WS_CHILD | SS_LEFT,
        340, 405, 200, 40, // Placeholder
        hwnd, nullptr,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

    g_hButtonCut = CreateWindow(
        L"BUTTON", L"Cut & Save",
        WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        340, 450, 200, 30, // Placeholder
        hwnd, (HMENU)ID_BUTTON_CUT,
        (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);

   g_hCheckboxMergeAudio = CreateWindow(
       L"BUTTON", L"Merge Audios",
       WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
       340, 485, 200, 25, // Placeholder
       hwnd, (HMENU)ID_CHECKBOX_MERGE_AUDIO,
       (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
   SendMessage(g_hCheckboxMergeAudio, BM_SETCHECK, BST_CHECKED, 0);


    // Disable controls until video is loaded
    EnableWindow(g_hButtonPlay, FALSE);
    EnableWindow(g_hButtonPause, FALSE);
    EnableWindow(g_hButtonStop, FALSE);
    EnableWindow(g_hSliderSeek, FALSE);
    EnableWindow(g_hListBoxAudioTracks, FALSE);
    EnableWindow(g_hButtonMuteTrack, FALSE);
    EnableWindow(g_hSliderTrackVolume, FALSE);
    EnableWindow(g_hSliderMasterVolume, FALSE);
    EnableWindow(g_hButtonSetStart, FALSE);
    EnableWindow(g_hButtonSetEnd, FALSE);
    EnableWindow(g_hButtonCut, FALSE);
   EnableWindow(g_hCheckboxMergeAudio, FALSE);
}

void OpenVideoFile(HWND hwnd)
{
    OPENFILENAMEW ofn;
    wchar_t szFile[260] = {0};

    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile) / sizeof(wchar_t);
    ofn.lpstrFilter = L"Video Files\0*.mp4;*.avi;*.mov;*.mkv;*.wmv;*.flv;*.webm;*.m4v;*.3gp\0All Files\0*.*\0";
    ofn.nFilterIndex = 1;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    if (GetOpenFileNameW(&ofn))
    {
        LoadVideoFile(hwnd, std::wstring(szFile));
    }
}

void LoadVideoFile(HWND hwnd, const std::wstring& filename)
{
    if (g_videoPlayer && g_videoPlayer->LoadVideo(filename))
    {
        SetWindowTextW(g_hStatusText, (L"Loaded: " + filename).c_str());
        EnableWindow(g_hButtonPlay, TRUE);
        EnableWindow(g_hButtonPause, TRUE);
        EnableWindow(g_hButtonStop, TRUE);
        EnableWindow(g_hSliderSeek, TRUE);

        // Enable audio controls and populate audio tracks
        UpdateAudioTrackList();
        EnableWindow(g_hListBoxAudioTracks, TRUE);
        EnableWindow(g_hSliderMasterVolume, TRUE);
        if (g_videoPlayer->GetAudioTrackCount() > 0)
        {
            EnableWindow(g_hButtonMuteTrack, TRUE);
            EnableWindow(g_hSliderTrackVolume, TRUE);
            SendMessage(g_hListBoxAudioTracks, LB_SETCURSEL, 0, 0); // Select first track
            OnAudioTrackSelectionChanged();
        }

        // Enable editing controls and reset points
        EnableWindow(g_hButtonSetStart, TRUE);
        EnableWindow(g_hButtonSetEnd, TRUE);
        EnableWindow(g_hButtonCut, TRUE);
        EnableWindow(g_hCheckboxMergeAudio, TRUE);
        g_cutStartTime = -1.0;
        g_cutEndTime = -1.0;
        UpdateCutInfoLabel(hwnd);

        UpdateControls();
        UpdateSeekBar();
    }
    else
    {
        SetWindowTextW(g_hStatusText, L"Failed to load video file");
        MessageBoxW(hwnd, L"Failed to load the video file. Please check FFmpeg setup.", L"Error", MB_OK | MB_ICONERROR);
    }
}

void UpdateControls()
{
    if (!g_videoPlayer)
        return;

    bool isLoaded = g_videoPlayer->IsLoaded();
    bool isPlaying = g_videoPlayer->IsPlaying();

    EnableWindow(g_hButtonPlay, isLoaded && !isPlaying);
    EnableWindow(g_hButtonPause, isLoaded && isPlaying);
    EnableWindow(g_hButtonStop, isLoaded);
    EnableWindow(g_hSliderSeek, isLoaded);

    // Ensure audio controls remain enabled if a video is loaded
    EnableWindow(g_hListBoxAudioTracks, isLoaded && g_videoPlayer->GetAudioTrackCount() > 0);
    EnableWindow(g_hButtonMuteTrack, isLoaded && g_videoPlayer->GetAudioTrackCount() > 0);
    EnableWindow(g_hSliderTrackVolume, isLoaded && g_videoPlayer->GetAudioTrackCount() > 0);
    EnableWindow(g_hSliderMasterVolume, isLoaded);

    // Update editing controls
    EnableWindow(g_hButtonSetStart, isLoaded);
    EnableWindow(g_hButtonSetEnd, isLoaded);
    EnableWindow(g_hButtonCut, isLoaded && g_cutStartTime >= 0 && g_cutEndTime > g_cutStartTime);

   bool canMerge = g_videoPlayer && g_videoPlayer->GetAudioTrackCount() > 1;
   EnableWindow(g_hCheckboxMergeAudio, isLoaded && canMerge);


    if (isLoaded)
    {
        double currentTime = g_videoPlayer->GetCurrentTime();
        double duration = g_videoPlayer->GetDuration();
        std::wstring currentTimeStr = FormatTime(currentTime);
        std::wstring durationStr = FormatTime(duration);
        wchar_t statusText[256];
        swprintf_s(statusText, _countof(statusText),
                   L"Time: %s / %s | Frame: %lld / %lld | %s",
                   currentTimeStr.c_str(), durationStr.c_str(),
                   g_videoPlayer->GetCurrentFrame(), g_videoPlayer->GetTotalFrames(),
                   isPlaying ? L"Playing" : L"Paused");
        SetWindowTextW(g_hStatusText, statusText);
    }
}

void UpdateSeekBar()
{
    if (!g_videoPlayer || !g_videoPlayer->IsLoaded())
        return;
    double currentTime = g_videoPlayer->GetCurrentTime();
    double duration = g_videoPlayer->GetDuration();
    if (duration > 0)
    {
        int pos = (int)((currentTime / duration) * SEEK_SLIDER_MAX);
        SendMessage(g_hSliderSeek, TBM_SETPOS, TRUE, pos);
    }
}

void UpdateAudioTrackList()
{
    if (!g_videoPlayer)
        return;
    
    // Clear existing items
    SendMessage(g_hListBoxAudioTracks, LB_RESETCONTENT, 0, 0);
    
    // Add audio tracks
    int trackCount = g_videoPlayer->GetAudioTrackCount();
    for (int i = 0; i < trackCount; i++)
    {
        std::string trackName = g_videoPlayer->GetAudioTrackName(i);
        std::wstring wTrackName(trackName.begin(), trackName.end());
        
        // Add mute status to the display name
        if (g_videoPlayer->IsAudioTrackMuted(i))
            wTrackName += L" (MUTED)";
        
        SendMessage(g_hListBoxAudioTracks, LB_ADDSTRING, 0, (LPARAM)wTrackName.c_str());
    }
}

void OnAudioTrackSelectionChanged()
{
    if (!g_videoPlayer)
        return;
    
    int selectedIndex = (int)SendMessage(g_hListBoxAudioTracks, LB_GETCURSEL, 0, 0);
    if (selectedIndex != LB_ERR)
    {
        // Update track volume slider
        float volume = g_videoPlayer->GetAudioTrackVolume(selectedIndex);
        int sliderPos = (int)(volume * 100); // Convert to 0-200 range
        SendMessage(g_hSliderTrackVolume, TBM_SETPOS, TRUE, sliderPos);
        
        // Update mute button text
        bool isMuted = g_videoPlayer->IsAudioTrackMuted(selectedIndex);
        SetWindowTextW(g_hButtonMuteTrack, isMuted ? L"Unmute" : L"Mute");
    }
}

void OnMuteTrackClicked()
{
    if (!g_videoPlayer)
        return;
    
    int selectedIndex = (int)SendMessage(g_hListBoxAudioTracks, LB_GETCURSEL, 0, 0);
    if (selectedIndex != LB_ERR)
    {
        bool currentlyMuted = g_videoPlayer->IsAudioTrackMuted(selectedIndex);
        g_videoPlayer->SetAudioTrackMuted(selectedIndex, !currentlyMuted);
        
        // Update the display
        UpdateAudioTrackList();
        SendMessage(g_hListBoxAudioTracks, LB_SETCURSEL, selectedIndex, 0);
        OnAudioTrackSelectionChanged();
    }
}

void OnTrackVolumeChanged()
{
    if (!g_videoPlayer)
        return;
    
    int selectedIndex = (int)SendMessage(g_hListBoxAudioTracks, LB_GETCURSEL, 0, 0);
    if (selectedIndex != LB_ERR)
    {
        int sliderPos = (int)SendMessage(g_hSliderTrackVolume, TBM_GETPOS, 0, 0);
        float volume = sliderPos / 100.0f; // Convert from 0-200 to 0.0-2.0
        g_videoPlayer->SetAudioTrackVolume(selectedIndex, volume);
    }
}

void OnMasterVolumeChanged()
{
    if (!g_videoPlayer)
        return;
    
    int sliderPos = (int)SendMessage(g_hSliderMasterVolume, TBM_GETPOS, 0, 0);
    float volume = sliderPos / 100.0f; // Convert from 0-200 to 0.0-2.0
    g_videoPlayer->SetMasterVolume(volume);
    
    // Update the track volume slider if a track is selected
    int selectedIndex = (int)SendMessage(g_hListBoxAudioTracks, LB_GETCURSEL, 0, 0);
    if (selectedIndex != LB_ERR)
    {
        OnAudioTrackSelectionChanged();
    }
}

std::wstring FormatTime(double totalSeconds, bool showMilliseconds)
{
    if (totalSeconds < 0) totalSeconds = 0;
    int hours = static_cast<int>(totalSeconds) / 3600;
    int minutes = (static_cast<int>(totalSeconds) % 3600) / 60;
    int seconds = static_cast<int>(totalSeconds) % 60;

    wchar_t buffer[64];
    if (showMilliseconds)
    {
        int milliseconds = static_cast<int>((totalSeconds - static_cast<int>(totalSeconds)) * 100);
        if (hours > 0)
            swprintf_s(buffer, _countof(buffer), L"%d:%02d:%02d.%02d", hours, minutes, seconds, milliseconds);
        else
            swprintf_s(buffer, _countof(buffer), L"%02d:%02d.%02d", minutes, seconds, milliseconds);
    }
    else
    {
        if (hours > 0)
            swprintf_s(buffer, _countof(buffer), L"%d:%02d:%02d", hours, minutes, seconds);
        else
            swprintf_s(buffer, _countof(buffer), L"%02d:%02d", minutes, seconds);
    }
    return std::wstring(buffer);
}

void UpdateCutInfoLabel(HWND hwnd)
{
    wchar_t buffer[128];
    if (g_cutStartTime < 0 && g_cutEndTime < 0)
    {
        swprintf_s(buffer, L"Cut points not set.");
    }
    else
    {
        wchar_t startStr[64], endStr[64];
        if (g_cutStartTime >= 0) {
            std::wstring timeStr = FormatTime(g_cutStartTime, true);
            swprintf_s(startStr, _countof(startStr), L"Start: %s", timeStr.c_str());
        } else {
            swprintf_s(startStr, _countof(startStr), L"Start: Not set");
        }

        if (g_cutEndTime >= 0) {
            std::wstring timeStr = FormatTime(g_cutEndTime, true);
            swprintf_s(endStr, _countof(endStr), L"End: %s", timeStr.c_str());
        } else {
            swprintf_s(endStr, _countof(endStr), L"End: Not set");
        }

        swprintf_s(buffer, _countof(buffer), L"%s\n%s", startStr, endStr);
    }
    SetWindowTextW(g_hLabelCutInfo, buffer);
    // Also update the cut button state
    UpdateControls();
}

void OnSetStartClicked(HWND hwnd)
{
    if (!g_videoPlayer || !g_videoPlayer->IsLoaded()) return;
    g_cutStartTime = g_videoPlayer->GetCurrentTime();
    if (g_cutEndTime >= 0 && g_cutStartTime >= g_cutEndTime)
    {
        g_cutEndTime = -1.0; // Invalidate end time if it's before new start time
    }
    UpdateCutInfoLabel(hwnd);
}

void OnSetEndClicked(HWND hwnd)
{
    if (!g_videoPlayer || !g_videoPlayer->IsLoaded()) return;
    double currentTime = g_videoPlayer->GetCurrentTime();
    if (g_cutStartTime >= 0 && currentTime <= g_cutStartTime)
    {
        MessageBoxW(hwnd, L"End point must be after the start point.", L"Invalid Time", MB_OK | MB_ICONWARNING);
        return;
    }
    g_cutEndTime = currentTime;
    UpdateCutInfoLabel(hwnd);
}

void OnCutClicked(HWND hwnd)
{
    if (!g_videoPlayer || g_cutStartTime < 0 || g_cutEndTime <= g_cutStartTime)
    {
        MessageBoxW(hwnd, L"Please set valid start and end points for the cut.", L"Error", MB_OK | MB_ICONERROR);
        return;
    }

    OPENFILENAMEW ofn;
    wchar_t szFile[260] = { 0 };

    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile) / sizeof(wchar_t);
    ofn.lpstrFilter = L"MP4 Video\0*.mp4\0All Files\0*.*\0";
    ofn.nFilterIndex = 1;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
    ofn.lpstrDefExt = L"mp4";

    if (GetSaveFileNameW(&ofn))
    {
        SetWindowTextW(g_hStatusText, L"Cutting video... Please wait.");
        EnableWindow(hwnd, FALSE); // Disable UI during cut

        bool mergeAudio = IsDlgButtonChecked(hwnd, ID_CHECKBOX_MERGE_AUDIO) == BST_CHECKED;
        bool success = g_videoPlayer->CutVideo(std::wstring(szFile), g_cutStartTime, g_cutEndTime, mergeAudio);

        EnableWindow(hwnd, TRUE); // Re-enable UI

        MessageBoxW(hwnd, success ? L"Video successfully cut and saved." : L"Failed to cut the video.",
                    success ? L"Success" : L"Error", MB_OK | (success ? MB_ICONINFORMATION : MB_ICONERROR));
        UpdateControls();
    }
}

void RepositionControls(HWND hwnd)
{
    if (!g_videoPlayer) return;

    RECT clientRect;
    GetClientRect(hwnd, &clientRect);

    // Main controls
    int mainControlsY = 10;
    int mainControlsHeight = 30;
    MoveWindow(g_hButtonOpen, 10, mainControlsY, 100, mainControlsHeight, TRUE);
    MoveWindow(g_hButtonPlay, 120, mainControlsY, 60, mainControlsHeight, TRUE);
    MoveWindow(g_hButtonPause, 190, mainControlsY, 60, mainControlsHeight, TRUE);
    MoveWindow(g_hButtonStop, 260, mainControlsY, 60, mainControlsHeight, TRUE);

    // Audio controls (aligned to the right)
    int audioControlsWidth = 220;
    int audioControlsX = clientRect.right - audioControlsWidth - 10;
    int audioControlsY = 50;

    MoveWindow(g_hLabelAudioTracks, audioControlsX, audioControlsY, 200, 20, TRUE);
    MoveWindow(g_hListBoxAudioTracks, audioControlsX, audioControlsY + 25, 200, 100, TRUE);
    MoveWindow(g_hButtonMuteTrack, audioControlsX, audioControlsY + 135, 100, 25, TRUE);

    MoveWindow(g_hLabelTrackVolume, audioControlsX, audioControlsY + 170, 200, 20, TRUE);
    MoveWindow(g_hSliderTrackVolume, audioControlsX, audioControlsY + 195, 200, 30, TRUE);

    MoveWindow(g_hLabelMasterVolume, audioControlsX, audioControlsY + 235, 200, 20, TRUE);
    MoveWindow(g_hSliderMasterVolume, audioControlsX, audioControlsY + 260, 200, 30, TRUE);

    // Editing controls (below audio)
    int editingControlsY = audioControlsY + 260 + 40;
    MoveWindow(g_hLabelEditing, audioControlsX, editingControlsY, 200, 20, TRUE);
    MoveWindow(g_hButtonSetStart, audioControlsX, editingControlsY + 25, 95, 25, TRUE);
    MoveWindow(g_hButtonSetEnd, audioControlsX + 105, editingControlsY + 25, 95, 25, TRUE);
    MoveWindow(g_hLabelCutInfo, audioControlsX, editingControlsY + 55, 200, 40, TRUE);
    MoveWindow(g_hButtonCut, audioControlsX, editingControlsY + 100, 200, 30, TRUE);
    MoveWindow(g_hCheckboxMergeAudio, audioControlsX, editingControlsY + 135, 200, 25, TRUE);

    // Video area (takes up remaining space)
    int videoSectionWidth = clientRect.right - audioControlsWidth - 30;
    int bottomControlsHeight = 100;
    g_videoPlayer->SetPosition(
        10,
        mainControlsY + mainControlsHeight + 10,
        videoSectionWidth,
        clientRect.bottom - (mainControlsY + mainControlsHeight + 10) - bottomControlsHeight
    );

    // Bottom controls
    int bottomControlsY = clientRect.bottom - 90;
    MoveWindow(g_hSliderSeek, 10, bottomControlsY, videoSectionWidth, 30, TRUE);
    MoveWindow(g_hStatusText, 10, bottomControlsY + 40, videoSectionWidth, 20, TRUE);

    // Redraw all controls
    InvalidateRect(hwnd, NULL, TRUE);
}
// Entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
    const wchar_t CLASS_NAME[] = L"VideoEditorClass";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0, CLASS_NAME, L"Video Editor - Preview",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 1000, 700,
        nullptr, nullptr, hInstance, nullptr);

    if (!hwnd)
        return 0;
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0) > 0)
    {
        if (msg.message == WM_KEYDOWN && msg.wParam == VK_SPACE)
        {
            if (g_videoPlayer && g_videoPlayer->IsLoaded())
            {
                if (g_videoPlayer->IsPlaying())
                    g_videoPlayer->Pause();
                else
                    g_videoPlayer->Play();
                UpdateControls();
            }
            continue;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
```

#### video_player.cpp
```cpp
// video_player.cpp
#include "video_player.h"
#include <iostream>
#include <d2d1.h>
#include <d2d1helper.h>
#include <dxgiformat.h>
#pragma comment(lib, "d2d1.lib")
#include <algorithm>
#include <cstring>
#include <chrono>

// Link with Windows Audio libraries
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "winmm.lib")

VideoPlayer::VideoPlayer(HWND parent)
    : parentWindow(parent), formatContext(nullptr), codecContext(nullptr),
      frame(nullptr), frameRGB(nullptr), packet(nullptr), swsContext(nullptr),
      buffer(nullptr), videoStreamIndex(-1), frameWidth(0), frameHeight(0),
      isLoaded(false), isPlaying(false), frameRate(0), currentFrame(0),
      totalFrames(0), currentPts(0.0), duration(0.0), videoWindow(nullptr),
      d2dFactory(nullptr), d2dRenderTarget(nullptr), d2dBitmap(nullptr), playbackTimer(0),
      deviceEnumerator(nullptr), audioDevice(nullptr), audioClient(nullptr),
      renderClient(nullptr), audioFormat(nullptr), bufferFrameCount(0),
      audioInitialized(false), audioThreadRunning(false),
      playbackThreadRunning(false),
      audioSampleRate(44100), audioChannels(2), audioSampleFormat(AV_SAMPLE_FMT_S16)
{
  InitializeD2D();
  CreateVideoWindow();
  InitializeAudio();
}

VideoPlayer::~VideoPlayer()
{
  UnloadVideo();
  CleanupAudio();
  CleanupD2D();
  if (playbackThreadRunning)
  {
    playbackThreadRunning = false;
    if (playbackThread.joinable())
      playbackThread.join();
  }
  if (videoWindow)
    DestroyWindow(videoWindow);
}

void VideoPlayer::CreateVideoWindow()
{
  videoWindow = CreateWindow(
      L"STATIC", nullptr,
      WS_CHILD | WS_VISIBLE | SS_BLACKRECT,
      10, 10, 640, 480,
      parentWindow, nullptr,
      (HINSTANCE)GetWindowLongPtr(parentWindow, GWLP_HINSTANCE),
      nullptr);
  if (videoWindow)
  {
    CreateRenderTarget();
  }
}

bool VideoPlayer::LoadVideo(const std::wstring &filename)
{
  UnloadVideo();

  int bufSize = WideCharToMultiByte(CP_UTF8, 0, filename.c_str(), -1, nullptr, 0, nullptr, nullptr);
  std::string utf8Filename(bufSize, 0);
  WideCharToMultiByte(CP_UTF8, 0, filename.c_str(), -1, &utf8Filename[0], bufSize, nullptr, nullptr);

  formatContext = avformat_alloc_context();
  if (avformat_open_input(&formatContext, utf8Filename.c_str(), nullptr, nullptr) < 0)
    return false;
  if (avformat_find_stream_info(formatContext, nullptr) < 0)
  {
    avformat_close_input(&formatContext);
    return false;
  }

  videoStreamIndex = -1;
  for (unsigned i = 0; i < formatContext->nb_streams; i++)
  {
    if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    {
      videoStreamIndex = i;
      break;
    }
  }
  if (videoStreamIndex < 0)
  {
    avformat_close_input(&formatContext);
    return false;
  }

  if (!InitializeDecoder())
  {
    UnloadVideo();
    return false;
  }

  // Initialize audio tracks
  if (!InitializeAudioTracks())
  {
    std::cout << "Warning: Failed to initialize audio tracks" << std::endl;
  }

  isLoaded = true;
  currentFrame = 0;
  AVStream *vs = formatContext->streams[videoStreamIndex];
  AVRational guessed = av_guess_frame_rate(formatContext, vs, nullptr);
  frameRate = guessed.num && guessed.den ? av_q2d(guessed) : 0.0;
  if (frameRate <= 0.0)
    frameRate = av_q2d(vs->avg_frame_rate);
  if (frameRate <= 0.0)
    frameRate = av_q2d(vs->r_frame_rate);
  if (frameRate <= 0.0 && vs->time_base.den)
    frameRate = (double)vs->time_base.den / vs->time_base.num;
  if (frameRate <= 0.0)
    frameRate = 30.0; // Fallback

  totalFrames = vs->nb_frames
                    ? vs->nb_frames
                    : (vs->duration != AV_NOPTS_VALUE
                           ? (int64_t)(av_q2d(vs->time_base) * vs->duration * frameRate)
                           : 0);

  if (formatContext->duration != AV_NOPTS_VALUE)
    duration = formatContext->duration / (double)AV_TIME_BASE;
  else if (vs->duration != AV_NOPTS_VALUE)
    duration = av_q2d(vs->time_base) * vs->duration;
  else if (totalFrames > 0 && frameRate > 0)
    duration = totalFrames / frameRate;
  else
    duration = 0.0;
  currentPts = 0.0;
  return true;
}

bool VideoPlayer::InitializeDecoder()
{
  AVStream *vs = formatContext->streams[videoStreamIndex];
  AVCodecParameters *cp = vs->codecpar;
  const AVCodec *codec = avcodec_find_decoder(cp->codec_id);
  if (!codec)
    return false;

  codecContext = avcodec_alloc_context3(codec);
  if (!codecContext)
    return false;
  if (avcodec_parameters_to_context(codecContext, cp) < 0)
  {
    avcodec_free_context(&codecContext);
    return false;
  }
  if (avcodec_open2(codecContext, codec, nullptr) < 0)
  {
    avcodec_free_context(&codecContext);
    return false;
  }

  frameWidth = codecContext->width;
  frameHeight = codecContext->height;
  frame = av_frame_alloc();
  frameRGB = av_frame_alloc();
  packet = av_packet_alloc();
  if (!frame || !frameRGB || !packet)
  {
    CleanupDecoder();
    return false;
  }

  int numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGRA, frameWidth, frameHeight, 32);
  buffer = (uint8_t *)av_malloc(numBytes);
  av_image_fill_arrays(frameRGB->data, frameRGB->linesize, buffer,
                       AV_PIX_FMT_BGRA, frameWidth, frameHeight, 32);

  swsContext = sws_getContext(
      frameWidth, frameHeight, codecContext->pix_fmt,
      frameWidth, frameHeight, AV_PIX_FMT_BGRA,
      SWS_BILINEAR, nullptr, nullptr, nullptr);
  if (!swsContext)
  {
    CleanupDecoder();
    return false;
  }

  return true;
}

void VideoPlayer::CleanupDecoder()
{
  if (swsContext)
    sws_freeContext(swsContext), swsContext = nullptr;
  if (buffer)
    av_free(buffer), buffer = nullptr;
  if (packet)
    av_packet_free(&packet), packet = nullptr;
  if (frameRGB)
    av_frame_free(&frameRGB), frameRGB = nullptr;
  if (frame)
    av_frame_free(&frame), frame = nullptr;
  if (codecContext)
    avcodec_free_context(&codecContext), codecContext = nullptr;
}

void VideoPlayer::UnloadVideo()
{
  Stop();
  CleanupAudioTracks();
  CleanupDecoder();
  if (formatContext)
  {
    avformat_close_input(&formatContext);
    formatContext = nullptr;
  }
  isLoaded = false;
  videoStreamIndex = -1;
  currentFrame = 0;
  currentPts = 0.0;
  totalFrames = 0;
  duration = 0.0;
}

bool VideoPlayer::Play()
{
  if (!isLoaded || isPlaying)
    return false;
  isPlaying = true;
  
  // Start audio thread if we have audio tracks
  if (!audioTracks.empty() && audioInitialized)
  {
    HRESULT hr = audioClient->Start();
    if (FAILED(hr))
    {
      std::cerr << "Failed to start audio client: " << std::hex << hr << std::endl;
      // Continue without audio or handle error appropriately
    }
    audioThreadRunning = true;
    audioThread = std::thread(&VideoPlayer::AudioThreadFunction, this);
  }
  playbackThreadRunning = true;
  playbackThread = std::thread(&VideoPlayer::PlaybackThreadFunction, this);
  return true;
}

void VideoPlayer::Pause()
{
  if (isPlaying)
  {
    isPlaying = false;
    
    // Stop audio thread
    if (audioThreadRunning)
    {
      audioThreadRunning = false;
      audioCondition.notify_all();
      if (audioThread.joinable())
        audioThread.join();
    }
    
    if (playbackThreadRunning)
    {
      playbackThreadRunning = false;
      if (playbackThread.joinable())
      {
        if (std::this_thread::get_id() == playbackThread.get_id())
          playbackThread.detach();
        else
          playbackThread.join();
      }
    }
  }
}

void VideoPlayer::Stop()
{
  Pause();
  currentFrame = 0;
  if (isLoaded)
  {
    av_seek_frame(formatContext, videoStreamIndex, 0, AVSEEK_FLAG_FRAME);
    avcodec_flush_buffers(codecContext);
    
    // Flush audio codec buffers
    for (auto& track : audioTracks)
    {
      if (track->codecContext)
        avcodec_flush_buffers(track->codecContext);
    }
    
    // Clear audio buffers
    std::lock_guard<std::mutex> lock(audioMutex);
    for (auto& tr : audioTracks)
      tr->buffer.clear();
  }
}

bool VideoPlayer::DecodeNextFrame()
{
  if (!isLoaded)
    return false;

  while (true)
  {
    int ret = av_read_frame(formatContext, packet);
    if (ret < 0)
    {
      Stop();
      return false;
    }

    if (packet->stream_index == videoStreamIndex)
    {
      ret = avcodec_send_packet(codecContext, packet);
      av_packet_unref(packet);
      if (ret < 0)
        continue;

      while (true)
      {
        ret = avcodec_receive_frame(codecContext, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
          break;
        if (ret < 0)
          return false;

        sws_scale(
            swsContext,
            (uint8_t const *const *)frame->data, frame->linesize,
            0, frameHeight,
            frameRGB->data, frameRGB->linesize);
        AVStream *vs = formatContext->streams[videoStreamIndex];
        if (frame->best_effort_timestamp != AV_NOPTS_VALUE)
          currentPts = frame->best_effort_timestamp * av_q2d(vs->time_base);
        else if (frame->pts != AV_NOPTS_VALUE)
          currentPts = frame->pts * av_q2d(vs->time_base);
        else
          currentPts += (frameRate > 0 ? 1.0 / frameRate : 0.0);
        currentFrame++;
        UpdateDisplay();
        return true;
      }
    }
    else
    {
      // Check if this is an audio packet
      for (auto& track : audioTracks)
      {
        if (packet->stream_index == track->streamIndex)
        {
          ProcessAudioFrame(packet);
          break;
        }
      }
      av_packet_unref(packet);
    }
  }
  return false; // Should never reach here
}

void VideoPlayer::UpdateDisplay()
{
  if (!d2dRenderTarget || !frameRGB->data[0])
    return;

  if (!d2dBitmap)
  {
    D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(
        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE));
    d2dRenderTarget->CreateBitmap(
        D2D1::SizeU(frameWidth, frameHeight),
        frameRGB->data[0],
        frameRGB->linesize[0],
        props,
        &d2dBitmap);
  }
  else
  {
    D2D1_RECT_U rect = {0, 0, (UINT32)frameWidth, (UINT32)frameHeight};
    d2dBitmap->CopyFromMemory(&rect, frameRGB->data[0], frameRGB->linesize[0]);
  }

  d2dRenderTarget->BeginDraw();
  d2dRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black));
  D2D1_SIZE_F size = d2dRenderTarget->GetSize();
  float targetAspect = size.width / size.height;
  float videoAspect = static_cast<float>(frameWidth) / frameHeight;
  float drawWidth = size.width;
  float drawHeight = size.height;
  float offsetX = 0.0f;
  float offsetY = 0.0f;
  if (targetAspect > videoAspect)
  {
    drawHeight = size.height;
    drawWidth = drawHeight * videoAspect;
    offsetX = (size.width - drawWidth) / 2.0f;
  }
  else
  {
    drawWidth = size.width;
    drawHeight = drawWidth / videoAspect;
    offsetY = (size.height - drawHeight) / 2.0f;
  }

  d2dRenderTarget->DrawBitmap(
      d2dBitmap,
      D2D1::RectF(offsetX, offsetY, offsetX + drawWidth, offsetY + drawHeight),
      1.0f,
      D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
  d2dRenderTarget->EndDraw();
}

void VideoPlayer::SeekToFrame(int64_t frameNumber)
{
  if (!isLoaded || frameNumber < 0 || frameNumber >= totalFrames)
    return;
  AVStream *vs = formatContext->streams[videoStreamIndex];
  AVRational fps = av_d2q(frameRate, 100000);
  int64_t ts = av_rescale_q(frameNumber, av_inv_q(fps), vs->time_base);
  av_seek_frame(formatContext, videoStreamIndex, ts, AVSEEK_FLAG_BACKWARD);
  avcodec_flush_buffers(codecContext);
  for (auto &track : audioTracks)
  {
    if (track->codecContext)
      avcodec_flush_buffers(track->codecContext);
  }
  {
    std::lock_guard<std::mutex> lock(audioMutex);
    for (auto& tr : audioTracks)
      tr->buffer.clear();
  }
  currentFrame = frameNumber;
  currentPts = frameNumber / frameRate;
  DecodeNextFrame();
}

void VideoPlayer::SeekToTime(double seconds)
{
  if (!isLoaded)
    return;
  AVStream *vs = formatContext->streams[videoStreamIndex];
  int64_t ts = (int64_t)(seconds / av_q2d(vs->time_base));
  av_seek_frame(formatContext, videoStreamIndex, ts, AVSEEK_FLAG_BACKWARD);
  avcodec_flush_buffers(codecContext);
  for (auto &track : audioTracks)
  {
    if (track->codecContext)
      avcodec_flush_buffers(track->codecContext);
  }
  {
    std::lock_guard<std::mutex> lock(audioMutex);
    for (auto& tr : audioTracks)
      tr->buffer.clear();
  }
  currentFrame = (int64_t)(seconds * frameRate);
  currentPts = seconds;
  DecodeNextFrame();
}

double VideoPlayer::GetDuration() const
{
  return isLoaded ? duration : 0.0;
}

double VideoPlayer::GetCurrentTime() const
{
  return currentPts;
}

void VideoPlayer::SetPosition(int x, int y, int width, int height)
{
  if (!videoWindow)
    return;
  SetWindowPos(videoWindow, nullptr, x, y, width, height, SWP_NOZORDER);
  if (d2dRenderTarget)
  {
    d2dRenderTarget->Resize(D2D1::SizeU(width, height));
  }
  InvalidateRect(videoWindow, nullptr, TRUE);
  UpdateWindow(videoWindow);
}

void VideoPlayer::Render()
{
  if (isLoaded && !isPlaying)
    DecodeNextFrame();
}

void CALLBACK VideoPlayer::TimerProc(HWND hwnd, UINT, UINT_PTR, DWORD)
{
  VideoPlayer *player = (VideoPlayer *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  if (player && player->isPlaying)
    player->DecodeNextFrame();
}

void VideoPlayer::OnTimer()
{
  if (isPlaying)
    DecodeNextFrame();
}

// Audio track management methods
std::string VideoPlayer::GetAudioTrackName(int trackIndex) const
{
  if (trackIndex < 0 || trackIndex >= static_cast<int>(audioTracks.size()))
    return "";
  return audioTracks[trackIndex]->name;
}

bool VideoPlayer::IsAudioTrackMuted(int trackIndex) const
{
  if (trackIndex < 0 || trackIndex >= static_cast<int>(audioTracks.size()))
    return false;
  return audioTracks[trackIndex]->isMuted;
}

void VideoPlayer::SetAudioTrackMuted(int trackIndex, bool muted)
{
  if (trackIndex < 0 || trackIndex >= static_cast<int>(audioTracks.size()))
    return;
  audioTracks[trackIndex]->isMuted = muted;
}

float VideoPlayer::GetAudioTrackVolume(int trackIndex) const
{
  if (trackIndex < 0 || trackIndex >= static_cast<int>(audioTracks.size()))
    return 0.0f;
  return audioTracks[trackIndex]->volume;
}

void VideoPlayer::SetAudioTrackVolume(int trackIndex, float volume)
{
  if (trackIndex < 0 || trackIndex >= static_cast<int>(audioTracks.size()))
    return;
  float clampedVolume = volume < 0.0f ? 0.0f : (volume > 2.0f ? 2.0f : volume);
  audioTracks[trackIndex]->volume = clampedVolume;
}

void VideoPlayer::SetMasterVolume(float volume)
{
  float clampedVolume = volume < 0.0f ? 0.0f : (volume > 2.0f ? 2.0f : volume);
  for (auto& track : audioTracks)
  {
    track->volume = clampedVolume;
  }
}

// Audio initialization and cleanup
bool VideoPlayer::InitializeAudio()
{
  HRESULT hr = CoInitialize(nullptr);
  if (FAILED(hr))
    return false;

  hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
                        __uuidof(IMMDeviceEnumerator), (void**)&deviceEnumerator);
  if (FAILED(hr))
    return false;

  hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &audioDevice);
  if (FAILED(hr))
    return false;

  hr = audioDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)&audioClient);
  if (FAILED(hr))
    return false;

  // Get the default audio format
  WAVEFORMATEX *deviceFormat = nullptr;
  hr = audioClient->GetMixFormat(&deviceFormat);
  if (FAILED(hr))
    return false;

  // Set up our desired format (16-bit stereo at 44.1kHz)
  audioFormat = (WAVEFORMATEX*)CoTaskMemAlloc(sizeof(WAVEFORMATEX));
  audioFormat->wFormatTag = WAVE_FORMAT_PCM;
  audioFormat->nChannels = 2;
  audioFormat->nSamplesPerSec = 44100;
  audioFormat->wBitsPerSample = 16;
  audioFormat->nBlockAlign = (audioFormat->nChannels * audioFormat->wBitsPerSample) / 8;
  audioFormat->nAvgBytesPerSec = audioFormat->nSamplesPerSec * audioFormat->nBlockAlign;
  audioFormat->cbSize = 0;

  hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, audioFormat, nullptr);
  if (FAILED(hr))
  {
    // Try with device format if our format fails
    CoTaskMemFree(audioFormat);
    audioFormat = deviceFormat;
    hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, audioFormat, nullptr);
    if (FAILED(hr))
      return false;
  }
  else
  {
    CoTaskMemFree(deviceFormat);
  }

  // Update audio configuration to match the initialized format
  audioSampleRate = audioFormat->nSamplesPerSec;
  audioChannels = audioFormat->nChannels;

  hr = audioClient->GetBufferSize(&bufferFrameCount);
  if (FAILED(hr))
    return false;

  hr = audioClient->GetService(__uuidof(IAudioRenderClient), (void**)&renderClient);
  if (FAILED(hr))
    return false;

  audioInitialized = true;
  return true;
}

void VideoPlayer::CleanupAudio()
{
  if (audioThreadRunning)
  {
    audioThreadRunning = false;
    audioCondition.notify_all();
    if (audioThread.joinable())
      audioThread.join();
  }

  if (renderClient)
  {
    renderClient->Release();
    renderClient = nullptr;
  }
  if (audioClient)
  {
    audioClient->Release();
    audioClient = nullptr;
  }
  if (audioDevice)
  {
    audioDevice->Release();
    audioDevice = nullptr;
  }
  if (deviceEnumerator)
  {
    deviceEnumerator->Release();
    deviceEnumerator = nullptr;
  }
  if (audioFormat)
  {
    CoTaskMemFree(audioFormat);
    audioFormat = nullptr;
  }
  
  audioInitialized = false;
  CoUninitialize();
}

bool VideoPlayer::InitializeAudioTracks()
{
  if (!formatContext)
    return false;

  // Find all audio streams
  for (unsigned i = 0; i < formatContext->nb_streams; i++)
  {
    if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
    {
      auto track = std::make_unique<AudioTrack>();
      track->streamIndex = i;
      
      // Get codec and create context
      AVCodecParameters *codecpar = formatContext->streams[i]->codecpar;
      const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
      if (!codec)
        continue;

      track->codecContext = avcodec_alloc_context3(codec);
      if (!track->codecContext)
        continue;

      if (avcodec_parameters_to_context(track->codecContext, codecpar) < 0)
      {
        avcodec_free_context(&track->codecContext);
        continue;
      }

      if (avcodec_open2(track->codecContext, codec, nullptr) < 0)
      {
        avcodec_free_context(&track->codecContext);
        continue;
      }

      // Allocate frame
      track->frame = av_frame_alloc();
      if (!track->frame)
      {
        avcodec_free_context(&track->codecContext);
        continue;
      }

      // Set up resampler
      track->swrContext = swr_alloc();
      if (!track->swrContext)
      {
        av_frame_free(&track->frame);
        avcodec_free_context(&track->codecContext);
        continue;
      }

      // Configure resampler to convert to our output format
      AVChannelLayout in_ch_layout, out_ch_layout;
      av_channel_layout_from_mask(&in_ch_layout, track->codecContext->ch_layout.nb_channels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO);
      av_channel_layout_from_mask(&out_ch_layout, AV_CH_LAYOUT_STEREO);
      
      av_opt_set_chlayout(track->swrContext, "in_chlayout", &in_ch_layout, 0);
      av_opt_set_chlayout(track->swrContext, "out_chlayout", &out_ch_layout, 0);
      av_opt_set_int(track->swrContext, "in_sample_rate", track->codecContext->sample_rate, 0);
      av_opt_set_int(track->swrContext, "out_sample_rate", audioSampleRate, 0);
      av_opt_set_sample_fmt(track->swrContext, "in_sample_fmt", track->codecContext->sample_fmt, 0);
      av_opt_set_sample_fmt(track->swrContext, "out_sample_fmt", audioSampleFormat, 0);

      if (swr_init(track->swrContext) < 0)
      {
        swr_free(&track->swrContext);
        av_frame_free(&track->frame);
        avcodec_free_context(&track->codecContext);
        continue;
      }

      // Set track name
      AVDictionaryEntry *title = av_dict_get(formatContext->streams[i]->metadata, "title", nullptr, 0);
      if (title)
        track->name = title->value;
      else
        track->name = "Audio Track " + std::to_string(audioTracks.size() + 1);

      audioTracks.push_back(std::move(track));
    }
  }

  return !audioTracks.empty();
}

void VideoPlayer::CleanupAudioTracks()
{
  for (auto& track : audioTracks)
  {
    if (track->swrContext)
      swr_free(&track->swrContext);
    if (track->frame)
      av_frame_free(&track->frame);
    if (track->codecContext)
      avcodec_free_context(&track->codecContext);
  }
  audioTracks.clear();
}

bool VideoPlayer::ProcessAudioFrame(AVPacket *audioPacket)
{
  if (!audioInitialized || audioTracks.empty())
    return false;

  // Find the corresponding audio track
  AudioTrack *track = nullptr;
  for (auto& t : audioTracks)
  {
    if (t->streamIndex == audioPacket->stream_index)
    {
      track = t.get();
      break;
    }
  }

  if (!track || track->isMuted)
    return false;

  // Decode audio frame
  int ret = avcodec_send_packet(track->codecContext, audioPacket);
  if (ret < 0)
    return false;

  ret = avcodec_receive_frame(track->codecContext, track->frame);
  if (ret < 0)
    return false;

  // Resample audio
  int outSamples = swr_get_out_samples(track->swrContext, track->frame->nb_samples);
  std::vector<uint8_t> resampledData(outSamples * audioChannels * sizeof(int16_t));
  uint8_t *outPtr = resampledData.data();
  
  int convertedSamples = swr_convert(track->swrContext, &outPtr, outSamples,
                                    (const uint8_t**)track->frame->data, track->frame->nb_samples);
  if (convertedSamples < 0)
    return false;

  // Store raw samples in track buffer
  resampledData.resize(convertedSamples * audioChannels * sizeof(int16_t));
  {
    std::lock_guard<std::mutex> lock(audioMutex);
    int16_t* samples = reinterpret_cast<int16_t*>(resampledData.data());
    track->buffer.insert(track->buffer.end(),
                         samples,
                         samples + convertedSamples * audioChannels);
  }
  audioCondition.notify_one();

  return true;
}

void VideoPlayer::AudioThreadFunction()
{
  if (!audioClient || !renderClient)
    return;

  HRESULT hr; // Declare hr here

  while (audioThreadRunning)
  {
    std::unique_lock<std::mutex> lock(audioMutex);
    audioCondition.wait(lock, [this] { return HasBufferedAudio() || !audioThreadRunning; });

    if (!audioThreadRunning)
      break;

    if (!HasBufferedAudio())
      continue;

    // Get available buffer space
    UINT32 numFramesPadding;
    hr = audioClient->GetCurrentPadding(&numFramesPadding);
    if (FAILED(hr))
      continue;

    UINT32 numFramesAvailable = bufferFrameCount - numFramesPadding;
    if (numFramesAvailable == 0)
    {
      lock.unlock();
      Sleep(1);
      continue;
    }

    // Get render buffer
    BYTE *pData;
    hr = renderClient->GetBuffer(numFramesAvailable, &pData);
    if (FAILED(hr))
      continue;

    // Mix audio from all tracks
    MixAudioTracks(pData, numFramesAvailable);

    hr = renderClient->ReleaseBuffer(numFramesAvailable, 0);
    if (FAILED(hr))
      continue;

    lock.unlock();
  }

  audioClient->Stop();
}

void VideoPlayer::MixAudioTracks(uint8_t *outputBuffer, int frameCount)
{
  memset(outputBuffer, 0, frameCount * audioChannels * sizeof(int16_t));
  int16_t *out = reinterpret_cast<int16_t*>(outputBuffer);
  int totalSamples = frameCount * audioChannels;

  for (int frame = 0; frame < frameCount; ++frame)
  {
    std::vector<int32_t> mix(audioChannels, 0);
    for (auto& track : audioTracks)
    {
      if (track->isMuted)
        continue;
      if (track->buffer.size() >= static_cast<size_t>(audioChannels))
      {
        for (int ch = 0; ch < audioChannels; ++ch)
        {
          int16_t val = track->buffer.front();
          track->buffer.pop_front();
          mix[ch] += static_cast<int32_t>(val * track->volume);
        }
      }
    }
    for (int ch = 0; ch < audioChannels; ++ch)
    {
      int32_t v = mix[ch];
      if (v > 32767) v = 32767;
      if (v < -32768) v = -32768;
      out[frame * audioChannels + ch] = static_cast<int16_t>(v);
    }
  }
}

bool VideoPlayer::HasBufferedAudio() const
{
  for (const auto& track : audioTracks)
  {
    if (!track->buffer.empty())
      return true;
  }
  return false;
}

void VideoPlayer::PlaybackThreadFunction()
{
  auto startTime = std::chrono::high_resolution_clock::now();
  double startPts = currentPts;
  while (playbackThreadRunning)
  {
    if (!DecodeNextFrame())
      break;

    double target = currentPts - startPts;
    double elapsed = std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
    double delay = target - elapsed;
    if (delay > 0)
      std::this_thread::sleep_for(std::chrono::duration<double>(delay));
  }
  isPlaying = false;
}

bool VideoPlayer::CutVideo(const std::wstring &outputFilename, double startTime, double endTime, bool mergeAudio)
{
    if (!isLoaded) return false;

    // Convert filename to UTF-8
    int bufSize = WideCharToMultiByte(CP_UTF8, 0, outputFilename.c_str(), -1, nullptr, 0, nullptr, nullptr);
    std::string utf8OutputFilename(bufSize, 0);
    WideCharToMultiByte(CP_UTF8, 0, outputFilename.c_str(), -1, &utf8OutputFilename[0], bufSize, nullptr, nullptr);

    AVFormatContext* outFormatContext = nullptr;
    int ret = avformat_alloc_output_context2(&outFormatContext, nullptr, nullptr, utf8OutputFilename.c_str());
    if (ret < 0 || !outFormatContext) {
        std::cerr << "Could not create output context" << std::endl;
        return false;
    }

    std::vector<int> stream_mapping;
    int out_stream_index = 0;
    std::vector<int> unmuted_audio_streams;

    // Map video stream
    stream_mapping.push_back(out_stream_index++);
    AVStream* video_out_stream = avformat_new_stream(outFormatContext, nullptr);
    avcodec_parameters_copy(video_out_stream->codecpar, formatContext->streams[videoStreamIndex]->codecpar);
    video_out_stream->codecpar->codec_tag = 0;

    // Identify unmuted audio streams
    for (const auto& track : audioTracks) {
        if (!track->isMuted) {
            unmuted_audio_streams.push_back(track->streamIndex);
        }
    }

    if (mergeAudio && unmuted_audio_streams.size() > 1) {
        // Create a single audio stream for merging
        AVStream* audio_out_stream = avformat_new_stream(outFormatContext, nullptr);
        avcodec_parameters_copy(audio_out_stream->codecpar, formatContext->streams[unmuted_audio_streams[0]]->codecpar);
        audio_out_stream->codecpar->codec_tag = 0;
    } else {
        // Map each unmuted audio stream individually
        for (int stream_index : unmuted_audio_streams) {
            stream_mapping.push_back(out_stream_index++);
            AVStream* audio_out_stream = avformat_new_stream(outFormatContext, nullptr);
            avcodec_parameters_copy(audio_out_stream->codecpar, formatContext->streams[stream_index]->codecpar);
            audio_out_stream->codecpar->codec_tag = 0;
        }
    }

    // Open output file
    if (!(outFormatContext->oformat->flags & AVFMT_NOFILE)) {
        ret = avio_open(&outFormatContext->pb, utf8OutputFilename.c_str(), AVIO_FLAG_WRITE);
        if (ret < 0) {
            // Error handling
            avformat_free_context(outFormatContext);
            return false;
        }
    }

    AVDictionary* opts = nullptr;
    if (mergeAudio && unmuted_audio_streams.size() > 1) {
        std::string filter_spec;
        for (int stream_index : unmuted_audio_streams) {
            filter_spec += "[0:" + std::to_string(stream_index) + "]";
        }
        filter_spec += "amix=inputs=" + std::to_string(unmuted_audio_streams.size()) + "[a]";
        av_dict_set(&opts, "filter_complex", filter_spec.c_str(), 0);
        av_dict_set(&opts, "map", "0:v", 0);
        av_dict_set(&opts, "map", "[a]", 0);
    }
    
    // Write header
    ret = avformat_write_header(outFormatContext, &opts);
    av_dict_free(&opts);
    if (ret < 0) {
        // Error handling
        avio_closep(&outFormatContext->pb);
        avformat_free_context(outFormatContext);
        return false;
    }

    // Seek to start time
    ret = av_seek_frame(formatContext, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
    if (ret < 0) {
       // Error handling
       avformat_free_context(outFormatContext);
       return false;
    }

    AVPacket pkt;
    std::vector<int64_t> start_ts(formatContext->nb_streams, AV_NOPTS_VALUE);
    while (av_read_frame(formatContext, &pkt) >= 0) {
        double ts_seconds = pkt.pts * av_q2d(formatContext->streams[pkt.stream_index]->time_base);
        if (ts_seconds > endTime) {
            av_packet_unref(&pkt);
            break;
        }

        bool is_unmuted_audio = false;
        for (int stream_idx : unmuted_audio_streams) {
            if (pkt.stream_index == stream_idx) {
                is_unmuted_audio = true;
                break;
            }
        }

        if (pkt.stream_index != videoStreamIndex && !is_unmuted_audio) {
            av_packet_unref(&pkt);
            continue;
        }

        if (ts_seconds >= startTime) {
            if (start_ts[pkt.stream_index] == AV_NOPTS_VALUE) {
                start_ts[pkt.stream_index] = pkt.pts;
            }
            int64_t offset = start_ts[pkt.stream_index];

            AVStream* inStream = formatContext->streams[pkt.stream_index];
            AVStream* outStream;

            if (mergeAudio && is_unmuted_audio) {
                outStream = outFormatContext->streams[1]; // Merged audio stream
                pkt.stream_index = 1;
            } else if (pkt.stream_index == videoStreamIndex) {
                 outStream = outFormatContext->streams[0]; // Video stream
                 pkt.stream_index = 0;
            } else {
                int current_audio_stream = 0;
                for(size_t i = 0; i < unmuted_audio_streams.size(); ++i){
                    if(unmuted_audio_streams[i] == inStream->index){
                        current_audio_stream = i;
                        break;
                    }
                }
                outStream = outFormatContext->streams[1 + current_audio_stream];
                pkt.stream_index = 1 + current_audio_stream;
            }


            pkt.pts = av_rescale_q(pkt.pts - offset, inStream->time_base, outStream->time_base);
            if (pkt.dts != AV_NOPTS_VALUE)
                pkt.dts = av_rescale_q(pkt.dts - offset, inStream->time_base, outStream->time_base);
            if(pkt.dts > pkt.pts) pkt.dts = pkt.pts;
            pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
            pkt.pos = -1;

            ret = av_interleaved_write_frame(outFormatContext, &pkt);
            if (ret < 0) {
                // Error handling...
                break;
            }
        }
        av_packet_unref(&pkt);
    }

    av_write_trailer(outFormatContext);
    if (!(outFormatContext->oformat->flags & AVFMT_NOFILE)) {
        avio_closep(&outFormatContext->pb);
    }
    avformat_free_context(outFormatContext);

    // Reset format context for further use
    av_seek_frame(formatContext, -1, 0, AVSEEK_FLAG_BACKWARD);

    return true;
}

bool VideoPlayer::InitializeD2D()
{
  return SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory));
}

bool VideoPlayer::CreateRenderTarget()
{
  if (!d2dFactory || !videoWindow)
    return false;
  RECT rc;
  GetClientRect(videoWindow, &rc);
  D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
  HRESULT hr = d2dFactory->CreateHwndRenderTarget(
      D2D1::RenderTargetProperties(),
      D2D1::HwndRenderTargetProperties(videoWindow, size),
      &d2dRenderTarget);
  return SUCCEEDED(hr);
}

void VideoPlayer::CleanupD2D()
{
  if (d2dBitmap)
  {
    d2dBitmap->Release();
    d2dBitmap = nullptr;
  }
  if (d2dRenderTarget)
  {
    d2dRenderTarget->Release();
    d2dRenderTarget = nullptr;
  }
  if (d2dFactory)
  {
    d2dFactory->Release();
    d2dFactory = nullptr;
  }
}
```

#### video_player.h
```c
#ifndef VIDEO_PLAYER_H
#define VIDEO_PLAYER_H

#include <windows.h>

#include <string>
#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/rational.h>
#include <libavutil/avutil.h>
}

#include <vector>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
#include <atomic>

// Audio output using Windows Audio Session API (WASAPI)
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <audiopolicy.h>

// Audio track structure
struct AudioTrack {
    int streamIndex;
    AVCodecContext *codecContext;
    SwrContext *swrContext;
    AVFrame *frame;
    bool isMuted;
    float volume;
    std::string name;
    std::deque<int16_t> buffer;
    
    AudioTrack() : streamIndex(-1), codecContext(nullptr), swrContext(nullptr),
                   frame(nullptr), isMuted(false), volume(1.0f) {}
};

class VideoPlayer
{
private:
  AVFormatContext *formatContext;
  AVCodecContext *codecContext;
  AVFrame *frame;
  AVFrame *frameRGB;
  AVPacket *packet;
  struct SwsContext *swsContext;
  uint8_t *buffer;
  int videoStreamIndex;
  int frameWidth, frameHeight;
  bool isLoaded;
  bool isPlaying;
  double frameRate;
  int64_t currentFrame;
  int64_t totalFrames;
  double currentPts;
  double duration;

  HWND parentWindow;
  HWND videoWindow;

  // Direct2D rendering components
  ID2D1Factory* d2dFactory;
  ID2D1HwndRenderTarget* d2dRenderTarget;
  ID2D1Bitmap* d2dBitmap;

  // Timer for playback
  UINT_PTR playbackTimer;
  // Threaded playback
  std::thread playbackThread;
  std::atomic<bool> playbackThreadRunning;

  // Audio components
  std::vector<std::unique_ptr<AudioTrack>> audioTracks;
  IMMDeviceEnumerator *deviceEnumerator;
  IMMDevice *audioDevice;
  IAudioClient *audioClient;
  IAudioRenderClient *renderClient;
  WAVEFORMATEX *audioFormat;
  UINT32 bufferFrameCount;
  bool audioInitialized;
  
  // Audio threading
  std::thread audioThread;
  std::atomic<bool> audioThreadRunning;
  std::mutex audioMutex;
  std::condition_variable audioCondition;
  
  // Audio settings
  int audioSampleRate;
  int audioChannels;
  AVSampleFormat audioSampleFormat;

public:
  VideoPlayer(HWND parent);
  ~VideoPlayer();

  bool LoadVideo(const std::wstring &filename);
  void UnloadVideo();
  bool Play();
  void Pause();
  void Stop();
  bool IsPlaying() const { return isPlaying; }
  bool IsLoaded() const { return isLoaded; }

  void SeekToFrame(int64_t frameNumber);
  void SeekToTime(double seconds);

  double GetDuration() const;
  double GetCurrentTime() const;
  int64_t GetCurrentFrame() const { return currentFrame; }
  int64_t GetTotalFrames() const { return totalFrames; }

  void SetPosition(int x, int y, int width, int height);
  void Render();

  // Audio track management
  int GetAudioTrackCount() const { return static_cast<int>(audioTracks.size()); }
  std::string GetAudioTrackName(int trackIndex) const;
  bool IsAudioTrackMuted(int trackIndex) const;
  void SetAudioTrackMuted(int trackIndex, bool muted);
  float GetAudioTrackVolume(int trackIndex) const;
  void SetAudioTrackVolume(int trackIndex, float volume);
  void SetMasterVolume(float volume);
  bool CutVideo(const std::wstring& outputFilename, double startTime, double endTime, bool mergeAudio);

  // Timer callback
  static void CALLBACK TimerProc(HWND hwnd, UINT msg, UINT_PTR timerId, DWORD time);
  void OnTimer();

private:
  bool InitializeDecoder();
  void CleanupDecoder();
  bool DecodeNextFrame();
  void UpdateDisplay();
  void CreateVideoWindow();
  
  // Audio methods
  bool InitializeAudio();
  void CleanupAudio();
  bool InitializeAudioTracks();
  void CleanupAudioTracks();
  void AudioThreadFunction();
  void PlaybackThreadFunction();
  bool ProcessAudioFrame(AVPacket *audioPacket);
  void MixAudioTracks(uint8_t *outputBuffer, int frameCount);
  bool HasBufferedAudio() const;

  // Direct2D helpers
  bool InitializeD2D();
  void CleanupD2D();
  bool CreateRenderTarget();
};
#endif // VIDEO_PLAYER_H
```