; This program requires libmpv-2.dll file in the script directory ; libmpv-2.dll can be downloaded at: https://github.com/shinchiro/mpv-winbuild-cmake/releases ; File name: mpv-dev-x86_64-YYYYMMDD-git-f9190e5.7z #AutoIt3Wrapper_UseX64=Y #include #include #include #include #include #include #include #include $sDLL = @ScriptDir & "\libmpv-2.dll" Global $hMPV_DLL = DllOpen($sDLL) If $hMPV_DLL = -1 Then ; Thanks to @Dan_555 for the web-link suggestion $iMsgBoxAnswer = MsgBox(270596,"Error","libmpv-2.dll file cannot be loaded." & @CRLF & _ "Do you want to open the link to the download page" & @CRLF & _ "in your web browser?" & @CRLF & @CRLF & _ "Download, and extract the .dll from, the .7z file" & @CRLF & _ 'starting with "mpv-dev-x86_64".' & @CRLF & _ "Copy it into the script folder, then restart this app.") if $iMsgBoxAnswer = 6 Then ShellExecute ("https://github.com/shinchiro/mpv-winbuild-cmake/releases") EndIf Exit EndIf ; The following 3 options will become available for dynamic change when zPlayer is fully migrated to libmpv-2.dll ; Chagne $sKeepAspect to "no" if you want the video image to fill the GUI disregarding aspect ratio Global $iAspect, $sKeepAspect = "yes" ; Change $sDisplayAlbumArt to "no" if you do not want to display the album art of an audio file Global $sDisplayAlbumArt = "yes" ; Change audio mode to suit your taste ; 1 : Normal, 2 : Deep Bass, 3 : Crystal Clear, 4 : Pop/Rock, 5 : Cinema Voice, 6 : Midnight, 7 : Speech/Podcast Global $iAudioMode = 1 Global $iStartPos = 0 Global $iVolume = 50 ;Global $aPlaylist, $sFolder ;_PlaylistCreate() Global $hUser32DLL = DllOpen("user32.dll") HotKeySet("^!{right}", _PlayNext) ; Play next file HotKeySet("^!{left}", _PlayPrevious) ; Play previous file HotKeySet("^!{up}", _VolumeUp) ; Increase application volume level HotKeySet("^!{down}", _VolumeDown) ; Decrease application volume level ; Alternate hotkeys for Ctrl+Alt+Arrows in case they are used by Windows for changing screen orientation HotKeySet("^!{.}", _PlayNext) ; Play next file HotKeySet("^!{,}", _PlayPrevious) ; Play previous file HotKeySet("^!{=}", _VolumeUp) ; Increase application volume level HotKeySet("^!{-}", _VolumeDown) ; Decrease application volume level HotKeySet("^!{END}", _Exit) HotKeySet("^!l", _PlaylistDisplay) HotKeySet("^!{]}", _SpeedUp) HotKeySet("^!{[}", _SpeedDown) HotKeySet("^!{BS}", _SpeedRevert) HotKeySet("^!p", _PlayPause) Global $aPos = WinGetPos("[Class:Shell_TrayWnd]") ; 0, 1032, 1920, 48 Global $iClientHeight = $aPos[1] Global $iClientWidth = $aPos[2] ; Create GUI to parent video Global $iVideoWidth = Int($iClientWidth/3*2) Global $iVideoHeight = Int($iVideoWidth*9/16) Global $aVideoDefPos[4] Global $hVideoGUI = GUICreate("AutoIt 4K MPV Player", $iVideoWidth, $iVideoHeight, -1, -1, $WS_OVERLAPPEDWINDOW) Global $idAspect_Hotkey = GUICtrlCreateDummy() ; Press "a" key to keep aspect on or off Global $idShot_Hotkey = GUICtrlCreateDummy() ; Press "s" key to take screenshot Global $idF11_Hotkey = GUICtrlCreateDummy() ; Press "F11" key to turn full screen mode on or off Global $idEsc_Hotkey = GUICtrlCreateDummy() ; Press "Esc" key to turn full screen mode off Global $aAccel[4][2] = [["a", $idAspect_Hotkey], ["s", $idShot_Hotkey], ["{F11}", $idF11_Hotkey], ["{ESC}", $idEsc_Hotkey]] GUISetAccelerators($aAccel, $hVideoGUI) ; These hotkeys work only when $hVideoGUI is active ; Global variables for window metrics $aPos = WinGetPos($hVideoGUI) Global $iBorderWidth = ($aPos[2]-$iVideoWidth)/2 ; 8 Global $iTitleHeight = $aPos[3]-$iVideoHeight-$iBorderWidth ; 31 Global $iMaximizedTitleHeight ; 23 ; Create video controls at the bottom of $hVideoGUI Global $iVCHeight = 60 Global $iSliderLength2, $iProgBarWidth = 10 Global $iVCLeft, $iVCRight, $iVCBottom, $iVCTop Global $hVCGui, $idSlider2, $idProgBar2, $idRepeatAB2, $idCurrentPos2, $idLength2, $idExit, $idPlay2 Global $idPrevious2, $idRepeat2, $idNext2, $idSpeaker2, $idUp2, $idDown2, $idVolume2, $idFullScreen, $idSetDefaultSize Global $iRepeatCurrentFile, $iMute, $iMediaLength, $iFullScreen, $iMaximized Global $iLastX, $iLastY, $iLastW, $iLastH _VCCreate() Global $hLoading = GUICreate("", 600, 50, -1, 300, $WS_POPUPWINDOW, $WS_EX_TOPMOST) GUISetFont(10, 0, 0, "Arial Bold", $hLoading) $idLoading = GUICtrlCreateLabel("", 10, 18, 580, 18, BitOR($SS_NOPREFIX, $SS_CENTER)) GUIRegisterMsg($WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED") ; To sync movements of $hVideoGUI and $hVCGui Global $pHandle = DllCall($hMPV_DLL, "ptr:cdecl", "mpv_create")[0] If Not $pHandle Then Exit _mpv_set_options() DllCall($hMPV_DLL, "int:cdecl", "mpv_initialize", "ptr", $pHandle) ; Optional "Warm-up" strategy ; 1. Play a Windows sytem media file at 0 volume to warm up the device _mpv_set_property($pHandle, "volume", 0, "double") _mpv_command($pHandle, "loadfile", @WindowsDir & "\Media\Windows Notify System Generic.wav") ; 2. Use this if the stuttering persists; then set "pause" to "no" in _PlayFile() _mpv_set_property($pHandle, "pause", "yes", "string") Global $aPlaylist, $sFolder _PlaylistCreate() Global $iIndex = 1 Global $aMsg, $sMsg, $iPlayPrevious, $sIdle, $aMouse, $iHitTest, $iCurrentPos, $iPaused Global $iDoubleclickTime = DllCall($hUser32DLL, 'uint', 'GetDoubleClickTime')[0], $iClickCount, $iTimer _mpv_set_property($pHandle, "keepaspect", $sKeepAspect, "string") _mpv_set_property($pHandle, "volume", 100, "double") _mpv_command($pHandle, "set", "ao-volume", $iVolume) _mpv_observe_property($pHandle, 100, "osd-dimensions", 1) ; string _mpv_observe_property($pHandle, 101, "duration", 5) ; double _mpv_observe_property($pHandle, 102, "time-pos", 5) ; double _mpv_observe_property($pHandle, 103, "idle-active", 3) ; flag (boolean) Global $isAudio, $isVideo, $bTransition, $bFileReady Global $doubleclickTime = DllCall($hUser32DLL, 'uint', 'GetDoubleClickTime')[0] If $iStartPos > 0 Then ; when resuming playback from preious session's last position _mpv_set_option_string($pHandle, "start", String($iStartPos)) _AudioModeSet($iAudioMode, True) ; fade-in ; This will be reset to normal in main loop when the first file is finished EndIf Global $h1, $h2, $n _PlayFile() While 1 $aMsg = GUIGetMsg(1) $sMsg = $aMsg[0] Switch $aMsg[1] Case $hVideoGUI Switch $sMsg Case $GUI_EVENT_CLOSE _PlayNext() Case $GUI_EVENT_MAXIMIZE $iMaximized = 1 If $iMaximizedTitleHeight = 0 Then Local $aPos1 = WinGetClientSize($hVideoGUI) $iMaximizedTitleHeight = $iClientHeight-$aPos1[1] EndIf Case $GUI_EVENT_RESTORE $iMaximized = 0 Case $GUI_EVENT_RESIZED If $iFullScreen+$iMaximized = 0 And $sKeepAspect = "yes" Then _VideoResize() EndIf Case $GUI_EVENT_PRIMARYDOWN _VideoClicked() Case $idAspect_Hotkey _AspectToggler() Case $idShot_Hotkey Local $sTimestamp = @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & @SEC Local $sFilePath = @ScriptDir & "\Shot_" & $sTimestamp & ".jpg" _mpv_command($pHandle, "screenshot-to-file", $sFilePath) _mpv_command($pHandle, "show-text", "Screenshot Saved", "2000") Case $idF11_Hotkey _FullScreen() Case $idEsc_Hotkey If $iFullScreen = 1 Then _FullScreen() EndIf EndSwitch Case $hVCGui Switch $sMsg Case $idDown2 _VolumeDown() Case $idUp2 _VolumeUp() Case $idPlay2 _PlayPause() Case $idPrevious2 _PlayPrevious() Case $idNext2 _PlayNext() Case $idExit _Exit() Case $idSpeaker2 _mpv_command($pHandle, "cycle", "mute") If $iMute = 0 Then GUICtrlSetData($idSpeaker2, "🔇") _Audio_Action("SetMute", True) $iMute = 1 Else GUICtrlSetData($idSpeaker2, "🔊") _Audio_MasterVolume("UnMute") _Audio_Action("SetMute", False) $iMute = 0 EndIf Case $idRepeat2 If GUICtrlRead($idRepeat2) = "U" Then $iRepeatCurrentFile = 1 GUICtrlSetData($idRepeat2, "0") Else $iRepeatCurrentFile = 0 GUICtrlSetData($idRepeat2, "U") EndIf Case $idFullScreen _FullScreen() Case $idSetDefaultSize If $iFullScreen+$iMaximized = 0 Then If $aVideoDefPos[2] = 0 Then GUICtrlSetColor($idSetDefaultSize, 0xFF0055) $aVideoDefPos = WinGetPos($hVideoGUI) GUICtrlSetTip($idSetDefaultSize, "Unset your default size and position") Else GUICtrlSetColor($idSetDefaultSize, 0x000000) Local $w, $h, $x, $y $w = ($isVideo = 1) ? $iVideoWidth : 500 If $sKeepAspect = "yes" Then $h = Round($w/$iAspect) If $h > $iClientHeight-$iTitleHeight Then $h = $iClientHeight-$iTitleHeight $w = Round($h*$iAspect) EndIf EndIf If $isVideo <> 1 Or $sKeepAspect = "no" Then $h = 500 EndIf $w += $iBorderWidth*2 $h += $iTitleHeight+$iBorderWidth $x = ($iClientWidth-$w)/2 $y = ($iClientHeight-$h)/2 WinMove($hVideoGUI, "", $x, $y, $w, $h) $aVideoDefPos[0] = 0 $aVideoDefPos[1] = 0 $aVideoDefPos[2] = 0 $aVideoDefPos[3] = 0 GUICtrlSetTip($idSetDefaultSize, "Set this size and position as your default") EndIf EndIf While _IsPressed("01", $hUser32DLL) Sleep(10) WEnd Case $idSlider2 _Slider() EndSwitch EndSwitch ; --- Receive mpv event --- Local $pEvent = _mpv_wait_event($pHandle, 0) If $pEvent = 0 Then ContinueLoop Local $tEvent = DllStructCreate("int event_id;int error;uint64 reply_userdata;ptr data", $pEvent) Local $iEventId = DllStructGetData($tEvent, "event_id") If $iEventId = 22 Then ; MPV_EVENT_PROPERTY_CHANGE Local $pPropData = DllStructGetData($tEvent, "data") ; mpv_event_property structure: name(ptr), format(int), data(ptr) Local $tProp = DllStructCreate("ptr name;int format;ptr val", $pPropData) ; 1. read property string from pointer Local $pName = DllStructGetData($tProp, "name") Local $sName = _PtrToStringAnsi($pName) ; convert a pointer to string, like "time-pos" Local $iFormat = DllStructGetData($tProp, "format") Local $pVal = DllStructGetData($tProp, "val") If $pVal = 0 Then ContinueLoop ; 2. extract data for each property Switch $sName Case "time-pos" If $iFormat = 5 Then ; MPV_FORMAT_DOUBLE Local $tDouble = DllStructCreate("double", $pVal) Local $fCur = DllStructGetData($tDouble, 1) $iCurrentPos = Int($fCur) If $fCur >= $iMediaLength - 1.5 And $bTransition = False Then $bTransition = True $bTransition = True AdlibUnRegister("_VCShow") AdlibUnRegister("_VideoRefresh") AdlibUnRegister("_VolumeSync") EndIf EndIf Case "duration" If $iFormat = 5 Then ; MPV_FORMAT_DOUBLE Local $tDouble = DllStructCreate("double", $pVal) $iMediaLength = DllStructGetData($tDouble, 1) GUICtrlSetData($idLength2, _SecondsToTime(Int($iMediaLength))) EndIf Case "idle-active" If $iFormat = 3 Then ; MPV_FORMAT_FLAG Local $tInt = DllStructCreate("int", $pVal) If DllStructGetData($tInt, 1) <> 0 Then $bTransition = True AdlibUnRegister("_VCShow") AdlibUnRegister("_VideoRefresh") AdlibUnRegister("_VolumeSync") AdlibUnRegister("_Progress") WinSetTrans($hVCGui, "", 0) If $iMaximized + $iFullScreen = 0 Then GUISetState(@SW_HIDE, $hVideoGUI) EndIf If $iRepeatCurrentFile <> 1 Then If $iPlayPrevious = 0 Then $iIndex += 1 If $iIndex > $aPlaylist[0] Then $iIndex = 1 Else $iIndex -= 1 If $iIndex = 0 Then $iIndex = $aPlaylist[0] EndIf EndIf $iPlayPrevious = 0 If $iStartPos > 0 Then $iStartPos = 0 _mpv_set_option_string($pHandle, "start", "0") _AudioModeSet($iAudioMode, False) ; No fade-in EndIf _PlayFile() EndIf EndIf EndSwitch EndIf Sleep(10) WEnd Func _ActivateSpeakers() ; Adlib function to keep the speakers continuously active during pause Beep(1, 1) ; once in 30 seconds EndFunc Func _AspectToggler() ; Called by Ctrl+Alt+a hotkey If $sKeepAspect = "yes" Then $sKeepAspect = "no" Local $sMsg = "Keep aspect: No" Else $sKeepAspect = "yes" _VideoResize() Local $sMsg = "Keep aspect: Yes" EndIf _mpv_set_property($pHandle, "keepaspect", $sKeepAspect, "string") _mpv_command($pHandle, "show-text", $sMsg) EndFunc ; _AspectToggler Func _Audio_Action($action, $value) ; Each action takes about 6 milliseconds ; https://www.autoitscript.com/forum/topic/211638-how-can-i-getset-mute-state-of-windows-volume-mixer/?do=findComment&comment=1531412 Local $oIAudioSessionManager2 = _Audio_GetIAudioSessionManager2() If Not IsObj($oIAudioSessionManager2) Then Return Local Const $sIID_IAudioSessionEnumerator = "{e2f5bb11-0570-40ca-acdd-3aa01277dee8}" Local Const $sTagIAudioSessionEnumerator = "GetCount hresult(int*);GetSession hresult(int;ptr*)" ;Local Const $sIID_IAudioSessionControl = "{f4b1a599-7266-4319-a8ca-e70acb11e8cd}" Local Const $sTagIAudioSessionControl = "GetState hresult(int*);GetDisplayName hresult(ptr);" & _ "SetDisplayName hresult(wstr);GetIconPath hresult(ptr);" & _ "SetIconPath hresult(wstr;ptr);GetGroupingParam hresult(ptr*);" & _ "SetGroupingParam hresult(ptr;ptr);RegisterAudioSessionNotification hresult(ptr);" & _ "UnregisterAudioSessionNotification hresult(ptr);" Local Const $sIID_IAudioSessionControl2 = "{bfb7ff88-7239-4fc9-8fa2-07c950be9c6d}" Local Const $sTagIAudioSessionControl2 = $sTagIAudioSessionControl & "GetSessionIdentifier hresult(ptr)" & _ "GetSessionInstanceIdentifier hresult(ptr);" & _ "GetProcessId hresult(dword*);IsSystemSoundsSession hresult();" & _ "SetDuckingPreferences hresult(bool);" ; http://answers.awesomium.com/questions/3398/controlling-the-sound-using-pinvoke-the-volume-mix.html Local Const $sIID_ISimpleAudioVolume = "{87CE5498-68D6-44E5-9215-6DA47EF883D8}" Local Const $sTagISimpleAudioVolume = _ "SetMasterVolume hresult(float;ptr);" & _ "GetMasterVolume hresult(float*);" & _ "SetMute hresult(int;ptr);" & _ "GetMute hresult(int*)" Local $pIAudioSessionEnumerator, $oIAudioSessionEnumerator If $oIAudioSessionManager2.GetSessionEnumerator($pIAudioSessionEnumerator) < 0 Then Return $oIAudioSessionEnumerator = ObjCreateInterface($pIAudioSessionEnumerator, $sIID_IAudioSessionEnumerator, $sTagIAudioSessionEnumerator) If Not IsObj($oIAudioSessionEnumerator) Then Return SetError(1) Local $i, $nSessions, $pIAudioSessionControl2, $oIAudioSessionControl2 Local $ProcessID, $oISimpleAudioVolume Local $error = 1 If $oIAudioSessionEnumerator.GetCount($nSessions) >= 0 Then For $i = 0 To $nSessions - 1 If $oIAudioSessionEnumerator.GetSession($i, $pIAudioSessionControl2) >= 0 Then $oIAudioSessionControl2 = ObjCreateInterface($pIAudioSessionControl2, $sIID_IAudioSessionControl2, $sTagIAudioSessionControl2) If @error Then ContinueLoop $oIAudioSessionControl2.GetProcessId($ProcessID) If $ProcessID = @AutoItPID Then $oISimpleAudioVolume = ObjCreateInterface($pIAudioSessionControl2, $sIID_ISimpleAudioVolume, $sTagISimpleAudioVolume) If @error Then ContinueLoop $oIAudioSessionControl2.AddRef() ;stabilize Switch $action Case "SetMute" ; Run(@SystemDir & "\sndvol.exe") ; https://learn.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-isimpleaudiovolume-setmute If $oISimpleAudioVolume.SetMute($value, Null) >= 0 Then $error = 0 ExitLoop EndIf Case "GetMute" ; https://learn.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-isimpleaudiovolume-getmute If $oISimpleAudioVolume.GetMute($value) >= 0 Then $error = 0 ExitLoop EndIf Case "SetVolume" If $oISimpleAudioVolume.SetMasterVolume($value, 0) >= 0 Then $error = 0 ExitLoop EndIf Case "GetVolume" If $oISimpleAudioVolume.GetMasterVolume($value) >= 0 Then $error = 0 ExitLoop EndIf EndSwitch EndIf EndIf Next EndIf $oISimpleAudioVolume = 0 $oIAudioSessionControl2 = 0 $oIAudioSessionEnumerator = 0 Return SetError($error, 0, $value) EndFunc ;==>_Audio_Action Func _Audio_GetIAudioSessionManager2() ; Used in _Audio_Action() Local Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}" Local Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}" Local Const $sTagIMMDeviceEnumerator = _ "EnumAudioEndpoints hresult(int;dword;ptr*);" & _ "GetDefaultAudioEndpoint hresult(int;int;ptr*);" & _ "GetDevice hresult(wstr;ptr*);" & _ "RegisterEndpointNotificationCallback hresult(ptr);" & _ "UnregisterEndpointNotificationCallback hresult(ptr)" Local Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}" Local Const $sTagIMMDevice = _ "Activate hresult(struct*;dword;ptr;ptr*);" & _ "OpenPropertyStore hresult(dword;ptr*);" & _ "GetId hresult(wstr*);" & _ "GetState hresult(dword*)" Local Const $sIID_IAudioSessionManager2 = "{77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f}" Local Const $sTagIAudioSessionManager = "GetAudioSessionControl hresult(ptr;dword;ptr*);" & _ "GetSimpleAudioVolume hresult(ptr;dword;ptr*);" Local Const $sTagIAudioSessionManager2 = $sTagIAudioSessionManager & "GetSessionEnumerator hresult(ptr*);" & _ "RegisterSessionNotification hresult(ptr);" & _ "UnregisterSessionNotification hresult(ptr);" & _ "RegisterDuckNotification hresult(wstr;ptr);" & _ "UnregisterDuckNotification hresult(ptr)" Local $_oIAudioSessionManager2 = 0 Local Const $eMultimedia = 1, $CLSCTX_INPROC_SERVER = 0x01 Local $pIMMDevice, $oMMDevice, $pIAudioSessionManager2 Local $oMMDeviceEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $sTagIMMDeviceEnumerator) If IsObj($oMMDeviceEnumerator) Then If $oMMDeviceEnumerator.GetDefaultAudioEndpoint(0, $eMultimedia, $pIMMDevice) >= 0 Then $oMMDevice = ObjCreateInterface($pIMMDevice, $sIID_IMMDevice, $sTagIMMDevice) If IsObj($oMMDevice) Then Local $tGUID = DllStructCreate("ulong Data1;ushort Data2;ushort Data3;byte Data4[8]") DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $sIID_IAudioSessionManager2, "struct*", $tGUID) If $oMMDevice.Activate($tGUID, $CLSCTX_INPROC_SERVER, 0, $pIAudioSessionManager2) >= 0 Then $_oIAudioSessionManager2 = ObjCreateInterface($pIAudioSessionManager2, $sIID_IAudioSessionManager2, $sTagIAudioSessionManager2) EndIf $oMMDevice = 0 EndIf EndIf $oMMDeviceEnumerator = 0 EndIf If IsObj($_oIAudioSessionManager2) Then Return $_oIAudioSessionManager2 EndIf EndFunc ;==>_Audio_GetIAudioSessionManager2 Func _Audio_MasterVolume($action) ; To sync zPlayer's mute state with the audio device's mute state ; https://www.autoitscript.com/forum/topic/84834-control-vista-master-volume/ Local Const $CLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}" Local Const $IID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}" Local Const $tagIMMDeviceEnumerator = _ "EnumAudioEndpoints hresult(int;dword;ptr*);" & _ "GetDefaultAudioEndpoint hresult(int;int;ptr*);" & _ "GetDevice hresult(wstr;ptr*);" & _ "RegisterEndpointNotificationCallback hresult(ptr);" & _ "UnregisterEndpointNotificationCallback hresult(ptr)" Local Const $IID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}" Local Const $tagIMMDevice = _ "Activate hresult(struct*;dword;ptr;ptr*);" & _ "OpenPropertyStore hresult(dword;ptr*);" & _ "GetId hresult(wstr*);" & _ "GetState hresult(dword*)" Local Const $eRender = 0, $eConsole = 0 Local Const $IID_IAudioEndpointVolume = "{5CDF2C82-841E-4546-9722-0CF74078229A}" Local Const $tagIAudioEndpointVolume = _ "RegisterControlChangeNotify hresult(ptr);" & _ "UnregisterControlChangeNotify hresult(ptr);" & _ "GetChannelCount hresult(uint*);" & _ "SetMasterVolumeLevel hresult(float;ptr);" & _ "SetMasterVolumeLevelScalar hresult(float;ptr);" & _ "GetMasterVolumeLevel hresult(float*);" & _ "GetMasterVolumeLevelScalar hresult(float*);" & _ "SetChannelVolumeLevel hresult(uint;float;ptr);" & _ "SetChannelVolumeLevelScalar hresult(uint;float;ptr);" & _ "GetChannelVolumeLevel hresult(uint;float*);" & _ "GetChannelVolumeLevelScalar hresult(uint;float*);" & _ "SetMute hresult(int;ptr);" & _ "GetMute hresult(int*);" & _ "GetVolumeStepInfo hresult(uint*;uint*);" & _ "VolumeStepUp hresult(ptr);" & _ "VolumeStepDown hresult(ptr);" & _ "QueryHardwareSupport hresult(dword*);" & _ "GetVolumeRange hresult(float*;float*;float*)" Local $oIAudioEndpointVolume = 0;, $err = 1 ; create device enumerator interface Local $oDevEnum = ObjCreateInterface($CLSID_MMDeviceEnumerator, $IID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator) If IsObj($oDevEnum) Then ; get default audio endpoint interface pointer Local $pDefaultDevice = 0 If $oDevEnum.GetDefaultAudioEndpoint($eRender, $eConsole, $pDefaultDevice) >= 0 Then ; create default audio endpoint interface Local $oIMMDevice = ObjCreateInterface($pDefaultDevice, $IID_IMMDevice, $tagIMMDevice) If IsObj($oIMMDevice) Then ; get endpoint volume interface pointer Local $pEndpointVolume = 0 Local $tGUID = DllStructCreate("ulong Data1;ushort Data2;ushort Data3;byte Data4[8]") DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $IID_IAudioEndpointVolume, "struct*", $tGUID) If $oIMMDevice.Activate($tGUID, 1, 0, $pEndpointVolume) >= 0 Then ; create endpoint volume interface $oIAudioEndpointVolume = ObjCreateInterface($pEndpointVolume, $IID_IAudioEndpointVolume, $tagIAudioEndpointVolume) EndIf $oIMMDevice = 0 EndIf EndIf $oDevEnum = 0 EndIf If $action = "GetMute" Then ; Get mute state of the audio device Local $bMute = 0 $oIAudioEndpointVolume.GetMute($bMute) Return $bMute ; 0 - not muted, 1 - muted ElseIf $action = "UnMute" Then ; Set mute state of the audio device $oIAudioEndpointVolume.SetMute(0, 0) ; 1st parameter: 1 to mute, 0 to unmute EndIf EndFunc ;==>_Audio_MasterVolume Func _AudioModeSet($iModeIndex, $bFadeIn = False) Local $sAF = "" Switch $iModeIndex Case 1 ; Normal $sAF = "" Case 2 ; Deep Bass $sAF = "lowshelf=f=150:g=12" Case 3 ; Crystal Clear $sAF = "highshelf=f=3000:g=10" Case 4 ; Pop/Rock $sAF = "lowshelf=f=100:g=6,highshelf=f=8000:g=6" Case 5 ; Cinema Voice $sAF = "lowshelf=f=150:g=8,loudnorm=I=-12" Case 6 ; Midnight $sAF = "loudnorm=I=-12,dynaudnorm=f=150:g=10" Case 7 ; Speech/Podcast $sAF = "highpass=f=200,equalizer=f=2000:width_type=h:width=1000:g=5" Case Else $sAF = "" EndSwitch ; For fade-in of 4 seconds when resuming playback from previous session If $bFadeIn Then If $sAF <> "" Then $sAF &= "," $sAF &= "afade=t=in:ss=0:d=5" EndIf ;~ ; When changing the mode, you can reduce sound level by 3 dB ;~ If $iModeIndex > 1 Then ;~ $sAF &= ",volume=-3dB" ;~ EndIf _mpv_set_property($pHandle, "af", $sAF, "str") EndFunc Func _Exit() ; Terminates the program (Click "🞭" in $hVCGui or pres Ctrl+Alt+End) GUIRegisterMsg($WM_WINDOWPOSCHANGED, "") _mpv_command($pHandle, "stop") DllCall($hMPV_DLL, "void:cdecl", "mpv_terminate_destroy", "ptr", $pHandle) DllClose($hMPV_DLL) DllClose($hUser32DLL) GUIDelete($hVCGui) GUIDelete($hVideoGUI) GUIDelete($hLoading) Exit EndFunc ; _Exit Func _FullScreen() ; Video in full screen mode on/off (Click ⇔/⇙ $hVCGui) While _IsPressed("01", $hUser32DLL) Sleep(50) WEnd WinSetTrans($hVCGui, "", 0) If $iFullScreen = 0 Then $iFullScreen = 1 GUICtrlSetData($idFullScreen, "⇙") GUISetStyle($WS_POPUP, -1, $hVideoGUI) WinMove($hVideoGUI, "", 0, 0, @DesktopWidth, @DesktopHeight) WinSetOnTop($hVideoGUI, "", 1) Else $iFullScreen = 0 $iMaximized = 0 GUICtrlSetData($idFullScreen, "⇔") GUISetStyle($WS_OVERLAPPEDWINDOW, -1, $hVideoGUI) WinSetOnTop($hVideoGUI, "", 0) If $isVideo = 1 Or $isAudio = 2 Then ; $isVideo, $isAudio, $iVideoWidth and $iAspect defined in _Playfile() Local $x, $y, $w, $h If $isVideo = 1 Then $w = $iVideoWidth Else $w = 500 EndIf If $aVideoDefPos[2] > 0 Then $w = $aVideoDefPos[2] - $iBorderWidth * 2 EndIf If $sKeepAspect = "yes" Then $h = Int($w/$iAspect) If $h > $iClientHeight-$iTitleHeight-$iBorderWidth Then $h = $iClientHeight-$iTitleHeight-$iBorderWidth $w = Int($h*$iAspect) EndIf Else $h = _Min($w, $iClientHeight) EndIf If $aVideoDefPos[2] = 0 Then $x = ($iClientWidth-$w-$iBorderWidth*2)/2 $y = ($iClientHeight-$h-$iTitleHeight-$iBorderWidth)/2 Else $x = $aVideoDefPos[0] $y = $aVideoDefPos[1] EndIf $w += $iBorderWidth*2 $h += $iTitleHeight+$iBorderWidth WinMove($hVideoGUI, "", $x, $y, $w, $h) EndIf EndIf EndFunc ; _FullScreen Func _GetVideoCardSpec() ; Get video card spec, to be used for setting hardware acceleration options Local $oWMIService = ObjGet("winmgmts:\\.\root\cimv2") Local $colItems = $oWMIService.ExecQuery("SELECT Name, AdapterRAM FROM Win32_VideoController") Local $hasExternalGPU = False Local $gpuName = "" If IsObj($colItems) Then For $oItem In $colItems $gpuName = $oItem.Name If StringInStr($gpuName, "NVIDIA") Or StringInStr($gpuName, "Radeon") Or StringInStr($gpuName, "RTX") Or StringInStr($gpuName, "GTX") Then ; Embedded GPU may require other method to check its availability $hasExternalGPU = True EndIf If $oItem.AdapterRAM >= 2147483648 Then ; Embedded GPU may show lower RAM size $hasExternalGPU = True EndIf Next EndIf If $hasExternalGPU Then Return "high" Else Return "low" EndIf EndFunc ; _GetVideoCardSpec Func _ParseMpvJson($sJson, $sKey) Local $aMatch = StringRegExp($sJson, '"' & $sKey & '":\s*(-?\d+)', 1) If @error Then Return 0 Return Number($aMatch[0]) EndFunc Func _PlayFile() ; Invoked by the main loop when the player is in idle state Local Static $iUnplayables _mpv_set_property($pHandle, "speed", 1.0, "double") If $isVideo + $isAudio = 0 Then ; when this app starts Sleep(300) ; allow time for the device to warm up before playing the first file _mpv_set_property($pHandle, "pause", "no", "string") ; "pause" set to "yes" in app initialization EndIf _mpv_command($pHandle, "loadfile", $sFolder & $aPlaylist[$iIndex]) $iAspect = 0 Local $sVideoCheck = "" For $i = 1 To 100 ; wait time lenghened to 10 seconds, as per @bladem2003's suggestion for loading network files If $i = 6 Then ; show $hLoading window when the loading takes more than 0.5 second GUICtrlSetData($idLoading, "Loading: " & $aPlaylist[$iIndex]) GUISetState(@SW_SHOW, $hLoading) EndIf Sleep(100) Local $iTracks = _mpv_get_property($pHandle, "track-list/count", "double") If $iTracks > 0 Then $sVideoCheck = _mpv_get_property($pHandle, "video", "string") If $sVideoCheck <> "no" And $sVideoCheck <> "" Then $iAspect = _mpv_get_property($pHandle, "video-params/aspect", "double") If $iAspect > 0 Then ExitLoop ElseIf $sVideoCheck = "no" Then $iAspect = 1 ExitLoop ; audio only EndIf EndIf Next ; ConsoleWrite("Wait loops: " & $i & @CRLF) GUISetState(@SW_HIDE, $hLoading) If $i > 200 Then MsgBox(0, "Error", $aPlaylist[$iIndex] & @CRLF & "This file could not be loaded.") $iUnplayables += 1 If $iUnplayables >= $aPlaylist[0] Then _Exit() $iIndex += 1 If $iIndex > $aPlaylist[0] Then $iIndex = 1 _mpv_command($pHandle, "stop") Return _PlayFile() EndIf Local $aRet = DllCall($hMPV_DLL, "str:cdecl", "mpv_get_property_string", "ptr", $pHandle, "str", "track-list") Local $sTrackList = $aRet[0] $isVideo = 0 $isAudio = 0 If StringInStr($sTrackList, '"albumart":true') Then If $sDisplayAlbumArt = "yes" Then ; audio file with album art $isAudio = 2 ; display album art Else $isAudio = 1 ; do not display album art EndIf ElseIf StringInStr($sTrackList, '"type":"video"') Then ; video file $isVideo = 1 Else $isAudio = 1 ; audio file with no album art EndIf WinSetTitle($hVideoGUI, "", $aPlaylist[$iIndex]) If $isVideo = 1 Or $isAudio = 2 Then Local $x, $y, $w, $h If $isVideo = 1 Then $w = $iVideoWidth Else $w = 500 EndIf If $aVideoDefPos[2] > 0 Then $w = $aVideoDefPos[2] - $iBorderWidth * 2 EndIf If $sKeepAspect = "yes" Then $h = Int($w/$iAspect) If $h > $iClientHeight-$iTitleHeight-$iBorderWidth Then $h = $iClientHeight-$iTitleHeight-$iBorderWidth $w = Int($h*$iAspect) EndIf Else $h = _Min($w, $iClientHeight) EndIf If $iMaximized+$iFullScreen = 0 Then If $aVideoDefPos[2] = 0 Then $x = ($iClientWidth-$w-$iBorderWidth*2)/2 $y = ($iClientHeight-$h-$iTitleHeight-$iBorderWidth)/2 Else $x = $aVideoDefPos[0] $y = $aVideoDefPos[1] EndIf $w += $iBorderWidth*2 $h += $iTitleHeight+$iBorderWidth WinMove($hVideoGUI, "", $x, $y, $w, $h) ElseIf $iFullScreen = 1 Then WinSetOnTop($hVideoGUI, "", 1) WinMove($hVideoGUI, "", 0, 0, @DesktopWidth, @DesktopHeight) ElseIf $iMaximized = 1 Then WinMove($hVideoGUI, "", 0, 0, @DesktopWidth, $iClientHeight) EndIf GUISetState(@SW_SHOW, $hVideoGUI) GUISetState(@SW_SHOW, $hVCGui) WinActivate($hVideoGUI) GUICtrlSetData($idLength2, _SecondsToTime(Int($iMediaLength))) AdlibRegister("_VCShow") AdlibRegister("_VideoRefresh", 300000) Else ; audio file WinSetOnTop($hVideoGUI, "", 0) WinMove($hVideoGUI, "", 0, @DesktopHeight-50) GUISetState(@SW_SHOW, $hVideoGUI) EndIf $iMediaLength = _mpv_get_property($pHandle, "duration") AdlibRegister("_Progress") AdlibRegister("_VolumeSync", 500) $bTransition = False EndFunc ; _PlayFile Func _PlaylistCreate() ; Create a playlist at the beginning of the program Local $sFileTypes = "*.mp4;*.wmv;*.avi;*.mkv;*.flv;*.webM;*.mp3;*.asf;*.wav;*.wma;*.ogg;*.ape;*.flac" Local $sFiles, $sMsg, $iRet $sFiles = FileOpenDialog("Load one or more video files", "", "Video (" & $sFileTypes & ")", 7) If $sFiles = "" Then Exit If Not StringInStr($sFiles, "|") Then Local $iPos = StringInStr($sFiles, "\", 0, -1) $sFiles = StringLeft($sFiles, $iPos) & "|" & StringMid($sFiles, $iPos+1) EndIf $aPlaylist = StringSplit($sFiles, "|") ; Folder name|File 1|File 2... $sFolder = $aPlaylist[1] If StringRight($sFolder, 1) <> "\" Then $sFolder &= "\" $sFile = $sFolder & $aPlaylist[2] _ArrayDelete($aPlaylist, 1) $aPlaylist[0] = UBound($aPlaylist)-1 EndFunc ; _PlaylistCreate Func _PlaylistDisplay() ; _ArrayDisplay($aPlaylist) (press Ctrl+Alt+L) If $iFullScreen = 1 Then Return If WinExists("Playlist") Then WinClose("Playlist") Else _ArrayDisplay($aPlaylist, "Playlist") EndIf EndFunc ; _PlaylistDisplay Func _PlayNext() ; Play next file (click "▶" or press Ctrl+Alt+Right) $bTransition = True $iRepeatCurrentFile = 0 ; Turn off file repeat mode GUICtrlSetData($idRepeat2, "U") If $iPaused = 1 Then _PlayPause() EndIf Sleep(500) _mpv_command($pHandle, "stop") EndFunc ; _PlayNext Func _PlayPause() ; Toggle between play and pause _mpv_command($pHandle, "cycle", "pause") If $iPaused = 0 Then GUICtrlSetData($idPlay2, "▶") $iPaused = 1 AdlibUnRegister("_Progress") AdlibRegister("_ActivateSpeakers", 30000) Else GUICtrlSetData($idPlay2, "❚❚") $iPaused = 0 AdlibRegister("_Progress") AdlibUnRegister("_ActivateSpeakers") EndIf EndFunc ; _PlayPause Func _PlayPrevious() ; Play privious file (click "◀" or press Ctrl+Alt+Left) $bTransition = True $iRepeatCurrentFile = 0 ; Turn off file repeat mode GUICtrlSetData($idRepeat2, "U") $iPlayPrevious = 1 If $iPaused = 1 Then _PlayPause() EndIf Sleep(500) _mpv_command($pHandle, "stop") EndFunc ; _PlayPrevious Func _Progress() ; Adlib to update position of progress bar and current position label in $hVCGui ; If $bTransition Then Return Local Static $iTime $iTime += 1 If $iTime = 4 Then GUICtrlSetData($idCurrentPos2, _SecondsToTime($iCurrentPos)) $iTime = 0 EndIf GUICtrlSetPos($idProgBar2, $iCurrentPos/Int($iMediaLength)*$iSliderLength2 + $iProgBarWidth/2) EndFunc ; _Progress Func _PtrToStringAnsi($pPtr) ; Read ANSI string from a pointer If $pPtr = 0 Then Return "" Local $tStruct = DllStructCreate("char[32767]", $pPtr) Return DllStructGetData($tStruct, 1) EndFunc ; _PtrToStringAnsi Func _SecondsToTime($iSeconds) ; Transform seconds to 00:00:00 time format Local $iH = Int($iSeconds / 3600) Local $iM = Int(Mod($iSeconds, 3600) / 60) Local $iS = Mod($iSeconds, 60) If $iMediaLength > 3600 Then Return StringFormat("%02d:%02d:%02d", $iH, $iM, $iS) Else Return StringFormat("%02d:%02d", $iM, $iS) EndIf EndFunc ; _SecondsToTime Func _Slider() ; Drag and drop the progrss bar or click anywhere on the slider to jump to a new media position AdlibUnRegister("_Progress") Local $x2, $mediaPos, $lastPos While _IsPressed("01", $hUser32DLL) $x2 = MouseGetPos(0) - ($iVCLeft + $iProgBarWidth / 2) ; Clamp If $x2 > $iSliderLength2 Then $x2 = $iSliderLength2 If $x2 < 0 Then $x2 = 0 $mediaPos = Int($x2 / $iSliderLength2 * $iMediaLength) GUICtrlSetPos($idProgBar2, $x2) GUICtrlSetData($idCurrentPos2, _SecondsToTime($mediaPos)) Sleep(10) WEnd _mpv_command($pHandle, "seek", $mediaPos, "absolute+exact") If $iPaused = 1 Then _PlayPause() Else AdlibRegister("_Progress") EndIf EndFunc ; _Slider Func _SpeedDown() ; Decrease play speed by 0.1x _mpv_command($pHandle, "add", "speed", -0.1) Local $currentSpeed = _mpv_get_property($pHandle, "speed", "double") Local $osdText = "Speed: " & StringFormat("%.1f", $currentSpeed) & "x" _mpv_command($pHandle, "show-text", $osdText, "2000") EndFunc ; _SpeedDown Func _SpeedRevert() ; Revert play speed to default 1.0x _mpv_command($pHandle, "set", "speed", 1.0) _mpv_command($pHandle, "show-text", "Speed: 1.0x", "2000") EndFunc ; _SpeedRever Func _SpeedUp() ; Increase play speed by 0.1x _mpv_command($pHandle, "add", "speed", 0.1) Local $currentSpeed = _mpv_get_property($pHandle, "speed", "double") Local $osdText = "Speed: " & StringFormat("%.1f", $currentSpeed) & "x" _mpv_command($pHandle, "show-text", $osdText, "2000") EndFunc ; _SpeedUp Func _VCCreate() ; Create $hVCGui and video controls $iVCLeft = ($iClientWidth-$iVideoWidth)/2 $iVCTop = ($iClientHeight-$iVideoWidth)/2 $hVCGui = GUICreate("", $iVideoWidth, $iVCHeight, $iVCLeft, $iVCTop, $WS_POPUP, $WS_EX_LAYERED, $hVideoGUI) GUISetFont(10, 400, 0, "Arial", $hVCGui) $idSlider2 = GUICtrlCreateLabel("", 0, 5, $iVideoWidth, 14, BitOR($SS_NOPREFIX, $SS_LEFTNOWORDWRAP)) GUICtrlSetBkColor(-1, 0xD0D0D0) GUICtrlSetFont(-1, 10) GUICtrlSetResizing(-1, $GUI_DOCKBORDERS) $idRepeatAB2 = GUICtrlCreateLabel("", 0, 7, 10, 12) ; Pink bar to indicate A-B repeat positions in slider GUICtrlSetBkColor(-1, 0xD580FF) GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetState(-1, $GUI_HIDE) $idProgBar2 = GUICtrlCreateLabel("", 0, 7, $iProgBarWidth, 12) GUICtrlSetBkColor(-1, 0x566573) GUICtrlSetResizing(-1, $GUI_DOCKSIZE) $idCurrentPos2 = GUICtrlCreateLabel("00.00", 10, 23, 60, 15, $SS_RIGHT) GUICtrlSetFont(-1, 10, 600) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKSIZE) $idLength2 = GUICtrlCreateLabel("00:00", $iVideoWidth-70, 23, 60, 15, $SS_LEFT) GUICtrlSetFont(-1, 10, 600) GUICtrlSetResizing(-1, $GUI_DOCKRIGHT+$GUI_DOCKSIZE) $idExit = GUICtrlCreateLabel("🞭", $iVideoWidth/2-110, 23, 15, 25, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 21, 400) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idPlay2 = GUICtrlCreateLabel("❚❚", $iVideoWidth/2-74, 27, 16, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont($idPlay2, 17) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idPrevious2 = GUICtrlCreateLabel("◀", $iVideoWidth/2-42, 28, 16, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idRepeat2 = GUICtrlCreateLabel("U", $iVideoWidth/2-30, 28, 16, 20, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 10, 900) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idNext2 = GUICtrlCreateLabel("▶", $iVideoWidth/2-18, 28, 16, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idSpeaker2 = GUICtrlCreateLabel("🔊", $iVideoWidth/2+14, 27, 16, 18, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 15, 400) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idUp2 = GUICtrlCreateLabel("▲", $iVideoWidth/2+30, 22, 15, 15, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 10) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) GUICtrlSetTip(-1, $iVolume) $idDown2 = GUICtrlCreateLabel("▼", $iVideoWidth/2+30, 36, 15, 15, $SS_CENTER);, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 10) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) GUICtrlSetTip(-1, $iVolume) $idFullScreen = GUICtrlCreateLabel("⇔", $iVideoWidth/2+58, 23, 20, 24, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 20, 600) GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) $idSetDefaultSize = GUICtrlCreateLabel("✅", $iVideoWidth/2+92, 28, 20, 20, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 12, 600) If $aVideoDefPos[2] = 0 Then GUICtrlSetColor($idSetDefaultSize, 0x000000) Else GUICtrlSetColor($idSetDefaultSize, 0xFF0055) EndIf GUICtrlSetResizing(-1, $GUI_DOCKHCENTER+$GUI_DOCKBOTTOM+$GUI_DOCKSIZE) GUICtrlSetTip(-1, "Set this size and position as your default") GUISetState(@SW_HIDE, $hVCGui) EndFunc ; _VCCreate Func _VCResize() ; Resize $hCVGui when $hVideoGUI is resized ; ConsoleWrite("VC Resized" & @CRLF) $aPos = WinGetPos($hVideoGUI) If Not IsArray($aPos) Then Return Local $iW, $iX, $iY If $iMaximized + $iFullScreen = 0 Then $iW = $aPos[2] - $iBorderWidth * 2 $iX = $aPos[0] + $iBorderWidth $iY = $aPos[1] + $aPos[3] - $iBorderWidth - $iVCHeight Else Local $aClient = WinGetClientSize($hVideoGUI) $iW = $aClient[0] $iX = 0 $iY = $aClient[1] If $iMaximized = 1 And $iFullScreen = 0 Then $iY += $iMaximizedTitleHeight EndIf $iY -= $iVCHeight EndIf $iSliderLength2 = $iW - $iProgBarWidth * 1.5 WinMove($hVCGui, "", $iX, $iY, $iW, $iVCHeight) Local $aPos1 = WinGetPos($hVCGui) $iVCLeft = $aPos1[0] $iVCRight = $aPos1[0] + $aPos1[2] $iVCBottom = $aPos1[1] + $aPos1[3] - 2 EndFunc ; _VCResize Func _VCShow() ; Adlib function to show video controls when mouse hovers the bottom area of $hVidoGUI, 250 ms If $bTransition Then Return If WinGetState($hVideoGUI) < 7 Then Return ; $iVCLeft, $iVCRight and $iVCBottom are defined in _VCResize() Local $iX = MouseGetPos(0), $iY = MouseGetPos(1), $iTransColor, $iAlpha _WinAPI_GetLayeredWindowAttributes($hVCGui, $iTransColor, $iAlpha) If $iAlpha <> 0 And ($iX <= $iVCLeft Or $iX >= $iVCRight Or $iY <= $iVCBottom - 200 Or $iY > $iVCBottom) Then WinSetTrans($hVCGui, "", 0) ; Fully transparent (invisible) ElseIf $iAlpha <> 200 And $iX > $iVCLeft And $iX < $iVCRight And $iY > $iVCBottom - 200 And $iY < $iVCBottom Then WinSetTrans($hVCGui, "", 200) ; Partly transparent (200/255) EndIf EndFunc ; _VCShow Func _VideoClicked() ; Called by GUIGetMsg() $GUI_EVENT_PRIMARYDOWN in the main loop If MouseGetPos(1) > $iVCBottom + 70 Then Return ; $iVCBottom is defined in _VCResize() Local $tPoint = _WinAPI_GetMousePos() If WinGetHandle(_WinAPI_WindowFromPoint($tPoint)) <> $hVideoGUI Then Return Local $hTimer = TimerInit(), $iCount While TimerDiff($hTimer) <= $doubleclickTime If _IsPressed("01", $hUser32DLL) Then $iCount += 1 While _IsPressed("01", $hUser32DLL) Sleep(50) WEnd EndIf Sleep(10) WEnd If $iCount > 1 Then _FullScreen() ElseIf $iCount = 1 Then _PlayPause() EndIf While _IsPressed("01", $hUser32DLL) Sleep(10) WEnd EndFunc ; _VideoClicked Func _VideoRefresh() ; Adlib to give a heartbeat to the video renderer every 5 minutes ; Check if the center of the video window is visible on the screen ; Position of video window ($aPos) is updated by WM_WINDOWPOSCHANGED in real time If $bTransition Then Return Local $tPoint = _WinAPI_CreatePoint($aPos[0]+$aPos[2]/2, $aPos[1]+$aPos[3]/2) Local $hTopWnd = _WinAPI_WindowFromPoint($tPoint) If $hTopWnd = $hVideoGUI Then Return ; Return if visible _mpv_command($pHandle, "seek", 0.05, "relative") _mpv_command($pHandle, "seek", -0.05, "relative") ; Please let me know if anyone knows of a less intrusive way to keep the video renderer alive while in background EndFunc ; _VideoRefresh Func _VideoResize() ; Resize $hVideoGUI to fit aspect ratio If $sKeepAspect = "no" Then Return WinSetTrans($hVCGui, "", 0) Local $w, $h, $x, $y Local $aPos1 = WinGetPos($hVideoGUI) $w = $aPos1[2] - $iBorderWidth*2 If $w < 370 Then $w = 370 $h = Round($w/$iAspect) If $h > $iClientHeight-$iTitleHeight Then $h = $iClientHeight-$iTitleHeight $w = Round($h*$iAspect) EndIf $w += $iBorderWidth*2 $h += $iTitleHeight+$iBorderWidth $x = ($iClientWidth-$w)/2 $y = ($iClientHeight-$h)/2 WinMove($hVideoGUI, "", $x, $y, $w, $h) EndFunc ;==>_VideoResize Func _VolumeDown() ; Decrease application volume by 5/100 (click "▼" or pres Ctrl+Alt+Down) $iVolume -= 5 If $iVolume < 0 Then $iVolume = 0 _mpv_command($pHandle, "set", "ao-volume", $iVolume) _mpv_command($pHandle, "show-text", "Volume: " & $iVolume, "2000") GUICtrlSetTip($idDown2, $iVolume) GUICtrlSetTip($idUp2, $iVolume) EndFunc ; _VolumeDown Func _VolumeSync() ; Adlib function to sync volume and mute state Windows volume mixer, 1000ms If $bTransition Then Return Local $mixerVolume = Round(_Audio_Action("GetVolume", "")*100/5)*5 If $iVolume <> $mixerVolume Then $iVolume = $mixerVolume _mpv_command($pHandle, "set", "ao-volume", $iVolume) GUICtrlSetTip($idUp2, $iVolume) GUICtrlSetTip($idDown2, $iVolume) EndIf Local $muteState = _Audio_Action("GetMute", True) ; $muteState is 0 if unmuted, 1 if muted by click on Mixer mute icon, -1 if muted by click on zPlayer mute icon(SetMute) Local $muteStateMaster = _Audio_MasterVolume("GetMute") ; 1 - muted, 0 - unmuted If ($muteState = 1 Or $muteStateMaster = 1) And $iMute = 0 Then _mpv_command($pHandle, "cycle", "mute") $iMute = 1 GUICtrlSetData($idSpeaker2, "🔇") ElseIf ($muteState = 0 And $muteStateMaster = 0) And $iMute = 1 Then _mpv_command($pHandle, "cycle", "mute") $iMute = 0 GUICtrlSetData($idSpeaker2, "🔊") EndIf EndFunc ;_VolumeSync Func _VolumeUp() ; Increase application volume by 5/100 (click "▲" or press Ctrl+Alt+Up) $iVolume += 5 If $iVolume > 100 Then $iVolume = 100 _mpv_command($pHandle, "set", "ao-volume", $iVolume) _mpv_command($pHandle, "show-text", "Volume: " & $iVolume, "2000") GUICtrlSetTip($idUp2, $iVolume) GUICtrlSetTip($idDown2, $iVolume) EndFunc ; _VolumeUp Func _mpv_wait_event($pHandle, $nTimeout = 0) Local $aResult = DllCall($hMPV_DLL, "ptr", "mpv_wait_event", "ptr", $pHandle, "double", $nTimeout) If @error Then Return SetError(1, 0, 0) Return $aResult[0] ; return a memory address (pointer) pointing to the event structure EndFunc Func _mpv_command($ptr, $p1, $p2 = "", $p3 = "", $p4 = "") ; Call mpv_command with variable number of parameters Local $aParams = [$p1, $p2, $p3, $p4] Local $iCount = 0 For $i = 0 To 3 If $aParams[$i] <> "" Then $iCount += 1 Next ; Create pointer array (number of parameters + NULL end pointer) Local $tPtrArray = DllStructCreate("ptr[" & ($iCount + 1) & "]") ; Convert strings to UTF-8 binary strings and assign to memory Local $aStrStructs[$iCount] For $i = 0 To $iCount - 1 Local $bUTF8 = StringToBinary($aParams[$i], 4) ; UTF-8 Local $iLen = BinaryLen($bUTF8) ; Create "byte" structure instead of "char" to prevent converting to ANSI $aStrStructs[$i] = DllStructCreate("byte[" & ($iLen + 1) & "]") DllStructSetData($aStrStructs[$i], 1, $bUTF8) DllStructSetData($tPtrArray, 1, DllStructGetPtr($aStrStructs[$i]), $i + 1) Next ; The ending pointer must be NULL DllStructSetData($tPtrArray, 1, 0, $iCount + 1) Local $aRet = DllCall($hMPV_DLL, "int:cdecl", "mpv_command", "ptr", $ptr, "ptr", DllStructGetPtr($tPtrArray)) Return $aRet EndFunc ; _mpv_command Func _mpv_free($pAddr) ; Prevent memory leak ; Omitting :cdecl in an AutoIt DllCall leads to stack corruption, which can cause ignored commands or program termination DllCall($hMPV_DLL, "void:cdecl", "mpv_free", "ptr", $pAddr) EndFunc ; _mpv_free Func _mpv_get_property($hMpv, $sProperty, $sType = "string") ; Get MPV properties, string or double Local $vResult = "" Switch StringLower($sType) Case "string", "str" Local $aRet = DllCall($hMPV_DLL, "ptr:cdecl", "mpv_get_property_string", "ptr", $hMpv, "str", $sProperty) If Not @error And $aRet[0] <> 0 Then Local $iLen = _mpv_get_strlen($aRet[0]) $vResult = DllStructGetData(DllStructCreate("char[" & $iLen & "]", $aRet[0]), 1) DllCall($hMPV_DLL, "none:cdecl", "mpv_free", "ptr", $aRet[0]) EndIf Case "double", "num", "number" Local $tDouble = DllStructCreate("double") Local $aRet = DllCall($hMPV_DLL, "int:cdecl", "mpv_get_property", "ptr", $hMpv, "str", $sProperty, "int", 5, "ptr", DllStructGetPtr($tDouble)) If $aRet[0] < 0 Then Return 0 ; Error Return DllStructGetData($tDouble, 1) Case Else Return SetError(1, 0, "Unknown Type") EndSwitch Return $vResult EndFunc ; mpv_get_property Func _mpv_get_strlen($pPtr) ; get string length, called by _mpv_get_property() Local $aRet = DllCall("kernel32.dll", "int", "lstrlenA", "ptr", $pPtr) Return $aRet[0] EndFunc ; _mpv_get_strlen Func _mpv_observe_property($pHandle, $iReplyId, $sName, $iFormat) ; DllCall for mpv_observe_property function in libmpv-2.dll ; $pHandle: mpv handle ; $iReplyId: arbitrary number to identify an event (e.g. 100) ; $sName: name of property to observe (e.g. "ao-volume", "time-pos") ; $iFormat: data format (e.g. "double", "flag") Local $aResult = DllCall($hMPV_DLL, "int", "mpv_observe_property", "ptr", $pHandle, "uint64", $iReplyId, "str", $sName, "int", $iFormat) If @error Then Return SetError(1, 0, 0) Return $aResult[0] ; return 0 or a positive number when successful EndFunc Func _mpv_set_options() ; set initial options for smooth operation ; Set hardware acceleration options (Based on Media Foundation) Local $sSpec = _GetVideoCardSpec() If $sSpec = "low" Then _mpv_set_option_string($pHandle, "profile", "fast") _mpv_set_option_string($pHandle, "vo", "direct3d") _mpv_set_option_string($pHandle, "dither", "no") _mpv_set_option_string($pHandle, "framedrop", "vo") Else _mpv_set_option_string($pHandle, "profile", "gpu-hq") _mpv_set_option_string($pHandle, "vo", "gpu") EndIf _mpv_set_option_string($pHandle, "gpu-api", "d3d11") _mpv_set_option_string($pHandle, "hwdec", "d3d11va") _mpv_set_option_string($pHandle, "scale", "bilinear") _mpv_set_option_string($pHandle, "cscale", "bilinear") _mpv_set_option_string($pHandle, "dscale", "bilinear") ; Additional options available for higher spec computers to improve video quality ; _mpv_set_option_string($pHandle, "video-sync", "display-resample") ; _mpv_set_option_string($pHandle, "interpolation", "yes") ; _mpv_set_option_string($pHandle, "tscale", "oversample") ; _mpv_set_option_string($pHandle, "scale", "extir-lanczos") ; or "spline36" ; _mpv_set_option_string($pHandle, "cscale", "lanczos") ; _mpv_set_option_string($pHandle, "dscale", "mitchell") ; Set maximum volume _mpv_set_property($pHandle, "volume-max", 100.0, "double") ; Connet GUI handle (Display video in an AutoIt GUI) _mpv_set_option_string($pHandle, "wid", String(Ptr($hVideoGUI))) _mpv_set_option_string($pHandle, "idle", "yes") ; if necesary to improve "seek" accuracy, especially in audio files ;_mpv_set_option_string($pHandle, "hr-seek", "always") ; Options to prevent the system from initialization errors ; 1. Specify Audio Output driver (Prevents delays/crashes during auto-detection) _mpv_set_option_string($pHandle, "ao", "wasapi") ; 2. Pre-allocate audio buffer (Crucial for preventing stuttering on first load) ; This ensures a buffer is filled before playback starts to handle initial CPU spikes. _mpv_set_option_string($pHandle, "audio-buffer", "0.5") ; Buffers 0.5 seconds of audio ; 3. Prevent program exit on initialization errors ; Ensures the player doesn't close if the audio device takes too long to respond. _mpv_set_option_string($pHandle, "stop-playback-on-init-failure", "no") ; 4. Set a timeout for the audio device to open (Wait for the device to be ready) ; Gives the OS more time (in milliseconds) to initialize the hardware. _mpv_set_option_string($pHandle, "audio-wait-open", "2000") ; Set to 2 seconds for reliability ; 5. Fill gaps with silence instead of crashing (Prevents underrun exits) _mpv_set_option_string($pHandle, "audio-stream-silence", "yes") EndFunc ; mpv_set_options Func _mpv_set_option_string($ptr, $name, $value) ; get mpv propertiess in string format DllCall($hMPV_DLL, "int:cdecl", "mpv_set_option_string", "ptr", $ptr, "str", $name, "str", $value) EndFunc ; _mpv_set_option_string Func _mpv_set_property($hMpv, $sProperty, $vValue, $sType = "string") ; 0 = MPV_FORMAT_STRING Local $aRet Switch $sType Case "string", "str" $aRet = DllCall($hMPV_DLL, "int:cdecl", "mpv_set_property_string", "ptr", $hMpv, "str", $sProperty, "str", String($vValue)) Case "double", "num", "number" Local $tDouble = DllStructCreate("double") DllStructSetData($tDouble, 1, Number($vValue)) $aRet = DllCall($hMPV_DLL, "int:cdecl", "mpv_set_property", "ptr", $hMpv, "str", $sProperty, "int", 5, "ptr", DllStructGetPtr($tDouble)) Case Else Return SetError(1, 0, -1) EndSwitch Return $aRet[0] EndFunc Func WM_WINDOWPOSCHANGED($hWnd, $MsgID, $wParam, $lParam) ; Sync movement of $hVideoGUI and $hVCGui #forceref $hWnd, $MsgID, $wParam, $lParam Local Static $bLock = False If $hWnd <> $hVideoGUI Or $bLock Or Not BitAND(WinGetState($hWnd), 2) Then Return $GUI_RUNDEFMSG Local $aPos1 = WinGetPos($hWnd) If Not IsArray($aPos) Then Return $GUI_RUNDEFMSG If $aPos1[0] = $aPos[0] And $aPos1[1] = $aPos[1] And $aPos1[2] = $aPos[2] And $aPos1[3] = $aPos[3] Then Return $GUI_RUNDEFMSG EndIf If $iMaximized = 0 And WinGetState($hVideoGUI) > 32 Then $iMaximized = 1 ; Window was dragged upward causing maximization GUISetState(@SW_MAXIMIZE, $hVideoGUI) If $iMaximizedTitleHeight = 0 Then Local $aPos1 = WinGetClientSize($hVideoGUI) $iMaximizedTitleHeight = $iClientHeight-$aPos1[1] EndIf EndIf If $iMaximized = 1 And WinGetState($hVideoGUI) < 32 Then $iMaximized = 0 ; Maximized window was dragged downward causing restoration GUISetState(@SW_RESTORE, $hVideoGUI) EndIf $bLock = True _VCResize() Sleep(20) $bLock = False Return $GUI_RUNDEFMSG EndFunc ; WM_WINDOWPOSCHANGED