From cec556da591b1d77e6c78fc445776151cf70c675 Mon Sep 17 00:00:00 2001 From: Baz Cuda Date: Mon, 22 Apr 2024 12:25:06 +0100 Subject: [PATCH] Fix audio cover art. Auto-centre mouse cursor. For audio and videos files, if auto-centering is on, when a new file is played, the cursor will be automatically positioned in the middle of the progress bar for easy clicking. Fixed the audio window sizing so that cover art is displayed correctly or, if there is no cover art, the minimalist "letterbox" audio window will be displayed. --- MinimalistMediaPlayer.dproj | 4 ++-- MinimalistMediaPlayer.res | Bin 168900 -> 168900 bytes appEvents.pas | 2 ++ consts.pas | 11 ++++++++-- mediaInfo.pas | 41 +++++++++++++++++++++++++----------- mediaPlayer.pas | 21 ++++++++++-------- progressBar.pas | 9 +++++++- uiCtrls.pas | 25 ++++++++++++++-------- 8 files changed, 78 insertions(+), 35 deletions(-) diff --git a/MinimalistMediaPlayer.dproj b/MinimalistMediaPlayer.dproj index 78f974b..9c564ba 100644 --- a/MinimalistMediaPlayer.dproj +++ b/MinimalistMediaPlayer.dproj @@ -106,12 +106,12 @@ .\$(Platform)\$(Config)\ true 1033 - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=2.0.3.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=2.0.2.0;Comments= + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=2.0.3.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=2.0.3.0;Comments= .\$(Platform)\$(Config)\ .\$(Platform)\$(Config) - "B:\MoviesToGo\The Lady In The Van (2015).mkv" + "nofile" 2 3 diff --git a/MinimalistMediaPlayer.res b/MinimalistMediaPlayer.res index 05746a7bcee4872d91ec59ac4babbf4e7ec6e616..37a1064ea665abdbc8e3cafa4309364c5f7059a9 100644 GIT binary patch delta 29 lcmX@Ioa@MPt_gLF%p2?XGBO%B+cLG=GBIwqWnyZd2mqw13Ag|N delta 29 lcmX@Ioa@MPt_gLFOdIR>GBO%9+cLG=GBIwqWnyZd2mqvq3AO+L diff --git a/appEvents.pas b/appEvents.pas index d03563d..fd67bc0 100644 --- a/appEvents.pas +++ b/appEvents.pas @@ -167,6 +167,8 @@ procedure TAppEvents.appEventsMessage(var msg: tagMSG; var handled: boolean); case msgIs(WM_USER_CENTRE_WINDOW) of TRUE: UI.centreWindow(UI.handle); end; case msgIs(WM_PROCESS_MESSAGES) of TRUE: application.processMessages; end; case msgIs(WIN_TWEAK_SIZE) of TRUE: UI.tweakWindow; end; + + case msgIs(WM_CENTRE_CURSOR) of TRUE: PB.centreCursor; end; end; constructor TAppEvents.create; diff --git a/consts.pas b/consts.pas index dea129b..7584802 100644 --- a/consts.pas +++ b/consts.pas @@ -53,6 +53,7 @@ interface WM_PLAY_CURRENT_ITEM = WM_USER + 2109; WM_SHOW_WINDOW = WM_USER + 2110; WM_PROCESS_MESSAGES = WM_USER + 2111; + WM_CENTRE_CURSOR = WM_USER + 2112; POT_PLAYER = 'C:\Program Files\DAUM\PotPlayer\PotPlayerMini64.exe'; LOSSLESS_CUT = 'C:\Program Files\LosslessCut-win-x64\LosslessCut.exe'; @@ -64,7 +65,7 @@ interface UI_DEFAULT_AUDIO_HEIGHT = 56; type - TMediaType = (mtUnk, mtAudio, mtVideo); + TMediaType = (mtUnk, mtAudio, mtVideo, mtImage); TMediaTypeRec = record mimeType: string; mediaType: TMediaType; @@ -73,7 +74,13 @@ TMediaTypeRec = record end; const - mediaTypes: array[0..82] of TMediaTypeRec = ( + mediaTypes: array[0..86] of TMediaTypeRec = ( + +// manually added image formats +(mimeType: 'image/jpeg'; mediaType: mtImage; typeName: 'JPEG image'; fileExts: '.jpg.jpeg'), +(mimeType: 'image/bmp'; mediaType: mtImage; typeName: 'BITMAP image'; fileExts: '.bmp'), +(mimeType: 'image/png'; mediaType: mtImage; typeName: 'PNG image'; fileExts: '.png'), +(mimeType: 'image/webp'; mediaType: mtImage; typeName: 'WEBP image'; fileExts: '.webp'), // DVD/Blu-ray audio formats (mimeType: 'audio/ac3'; mediaType: mtAudio; typeName: 'AC-3 Audio'; fileExts: '.ac3.a52'), diff --git a/mediaInfo.pas b/mediaInfo.pas index 6159d41..023684d 100644 --- a/mediaInfo.pas +++ b/mediaInfo.pas @@ -72,19 +72,22 @@ TMediaChapter = class(TObject) TMediaInfo = class(TObject) private FAudioBitRate: integer; + FAudioCount: integer; FFileSize: int64; FGeneralCount: integer; + FHasCoverArt: string; FHeight: integer; - FStereoMono: string; - FWidth: integer; - FOverallFrameRate: string; + FImageCount: integer; + FImageHeight: integer; + FImageWidth: integer; + FOtherCount: integer; FOverallBitRate: integer; + FOverallFrameRate: string; + FStereoMono: string; + FTextCount: integer; FVideoBitRate: integer; - FAudioCount: integer; FVideoCount: integer; - FTextCount: integer; - FImageCount: integer; - FOtherCount: integer; + FWidth: integer; FChapterCount: integer; FDuration: integer; @@ -95,16 +98,17 @@ TMediaInfo = class(TObject) FURL: string; function getAudioBitRate: string; + function getDuration: integer; function getFileSize: string; + function getHasCoverArt: boolean; + function getSelectedCount: integer; + function getStereoMono: string; + function getStreamCount: integer; function getOverallFrameRate: string; function getOverallBitRate: string; function getVideoBitRate: string; function getXY: string; - function getStereoMono: string; procedure setURL(const aValue: string); - function getStreamCount: integer; - function getSelectedCount: integer; - function getDuration: integer; protected constructor create; destructor destroy; override; @@ -117,7 +121,10 @@ TMediaInfo = class(TObject) property duration: integer read getDuration; property fileSize: string read getFileSize; property generalCount: integer read FGeneralCount; + property hasCoverArt: boolean read getHasCoverArt; property imageCount: integer read FImageCount; + property imageHeight: integer read FImageHeight; + property imageWidth: integer read FImageWidth; property mediaChapters: TObjectList read FMediaChapters; property mediaStreams: TObjectList read FMediaStreams; property otherCount: integer read FOtherCount; @@ -176,6 +183,11 @@ function TMediaInfo.getAudioBitRate: string; result := format('AR: %d Kb/s', [round(FAudioBitRate / 1000)]); end; +function TMediaInfo.getHasCoverArt: boolean; +begin + result := FHasCoverArt = 'Yes'; +end; + function TMediaInfo.getData(const aMemo: TMemo): boolean; begin case FNeedInfo of TRUE: initMediaInfo(FURL); end; @@ -368,7 +380,10 @@ function TMediaInfo.initMediaInfo(const aURL: string = ''): boolean; case tryStrToInt(mediaInfo_Get(handle, Stream_Video, 0, 'Height', Info_Text, Info_Name), FHeight) of FALSE: FHeight := 0; end; case tryStrToInt(mediaInfo_Get(handle, Stream_Video, 0, 'BitRate', Info_Text, Info_Name), FVideoBitRate) of FALSE: FVideoBitRate := 0; end; - FStereoMono := mediaInfo_Get(handle, Stream_Audio, 0, 'Title', Info_Text, Info_Name); + case tryStrToInt(mediaInfo_Get(handle, Stream_Image, 0, 'Width', Info_Text, Info_Name), FImageWidth) of FALSE: FImageWidth := 0; end; + case tryStrToInt(mediaInfo_Get(handle, Stream_Image, 0, 'Height', Info_Text, Info_Name), FImageHeight) of FALSE: FImageHeight := 0; end; + + FStereoMono := mediaInfo_Get(handle, Stream_Audio, 0, 'Title', Info_Text, Info_Name); case tryStrToInt(mediaInfo_Get(handle, Stream_General, 0, 'GeneralCount', Info_Text, Info_Name), FGeneralCount) of FALSE: FGeneralCount := 0; end; case tryStrToInt(mediaInfo_Get(handle, Stream_General, 0, 'VideoCount', Info_Text, Info_Name), FVideoCount) of FALSE: FVideoCount := 0; end; @@ -377,6 +392,8 @@ function TMediaInfo.initMediaInfo(const aURL: string = ''): boolean; case tryStrToInt(mediaInfo_Get(handle, Stream_General, 0, 'OtherCount', Info_Text, Info_Name), FOtherCount) of FALSE: FOtherCount := 0; end; case tryStrToInt(mediaInfo_Get(handle, Stream_General, 0, 'ImageCount', Info_Text, Info_Name), FImageCount) of FALSE: FImageCount := 0; end; + FHasCoverArt := mediaInfo_Get(handle, Stream_General, 0, 'Cover', Info_Text, Info_Name); + for var vStreamIx := 0 to streamCount - 1 do begin case mediaInfo_Get(handle, Stream_Video, vStreamIx, 'StreamKind', Info_Text, Info_Name) <> '' of TRUE: createVideoStream(vStreamIx); end; case mediaInfo_Get(handle, Stream_Audio, vStreamIx, 'StreamKind', Info_Text, Info_Name) <> '' of TRUE: createAudioStream(vStreamIx); end; diff --git a/mediaPlayer.pas b/mediaPlayer.pas index b857fe2..e82e2d6 100644 --- a/mediaPlayer.pas +++ b/mediaPlayer.pas @@ -21,7 +21,7 @@ interface uses - forms, vcl.extCtrls, system.classes, MPVBasePlayer; + forms, vcl.extCtrls, system.classes, MPVBasePlayer, consts; type TTimerEvent = (tePlay, teClose); @@ -36,6 +36,7 @@ TMediaPlayer = class(TObject) FAlwaysPot: boolean; FDontPlayNext: boolean; + FMediaType: TMediaType; FMuted: boolean; FOnBeforeNew: TNotifyEvent; FOnPlayNew: TNotifyEvent; @@ -130,6 +131,7 @@ TMediaPlayer = class(TObject) property formattedTime: string read getFormattedTime; property formattedVol: string read getFormattedVol; property keepOpen: boolean write setKeepOpen; + property mediaType: TMediaType read FMediaType; property onBeforeNew: TNotifyEvent read FOnBeforeNew write FOnBeforeNew; property onPlayNew: TNotifyEvent read FOnPlayNext write FOnPlayNew; property onPlayNext: TNotifyEvent read FOnPlayNext write FOnPlayNext; @@ -146,7 +148,7 @@ implementation uses vcl.controls, vcl.graphics, winAPI.windows, globalVars, formSubtitles, progressBar, keyboard, commonUtils, system.sysUtils, - formCaption, mediaInfo, mpvConst, consts, playlist, UIctrls, sysCommands, configFile, formHelp, mediaType, sendAll, _debugWindow; + formCaption, mediaInfo, mpvConst, playlist, UIctrls, sysCommands, configFile, formHelp, sendAll, mediaType, _debugWindow; var gMP: TMediaPlayer; @@ -411,7 +413,7 @@ procedure TMediaPlayer.onInitMPV(sender: TObject); setPropertyString('screenshot-png-compression', '0'); setPropertyString('screenshot-template', '%F %p %04n'); setPropertyString('sid', '1'); -// setPropertyString('image-display-duration', '10'); +// setPropertyDouble('image-display-duration', 100); // SetPropertyDouble('sub-delay', -00.99); end; end; @@ -548,27 +550,28 @@ function TMediaPlayer.play(const aURL: string): boolean; MI.initMediaInfo(aURL); - var vMediaType := MT.mediaType(lowerCase(extractFileExt(PL.currentItem))); + FMediaType := MT.mediaType(lowerCase(extractFileExt(PL.currentItem))); // reset the window size for an audio file in case the previous file was a video, or the previous audio had an image but this one doesn't - case UI.autoCentre or (vMediaType = mtAudio) of TRUE: UI.setWindowSize(vMediaType); end; + case UI.autoCentre OR (FMediaType = mtAudio) of TRUE: UI.setWindowSize(FMediaType, MI.hasCoverArt); end; + case UI.autoCentre AND (FMediaType <> mtImage) of TRUE: postMessage(GV.appWND, WM_CENTRE_CURSOR, 0, 0); end; openURL(aURL); mpv.volume := FVol; mpv.mute := FMuted; + FDontPlayNext := FMediaType = mtImage; + case ST.showData of TRUE: MI.getData(ST.dataMemo); end; MC.caption := PL.formattedItem; -// postMessage(GV.appWnd, WM_ADJUST_ASPECT_RATIO, 0, 0); application.processMessages; -// UI.smallerWindow(UI.handle); -// UI.tweakWindow; // force update SA.postToAll(WM_PROCESS_MESSAGES); checkPot; - case assigned(FOnPlayNew) of TRUE: FOnPlayNew(SELF); end; + case assigned(FOnPlayNew) of TRUE: FOnPlayNew(SELF); end; + case UI.autoCentre AND (FMediaType <> mtImage) of TRUE: postMessage(GV.appWND, WM_CENTRE_CURSOR, 0, 0); end; result := TRUE; end; diff --git a/progressBar.pas b/progressBar.pas index 10c5117..65c2f6a 100644 --- a/progressBar.pas +++ b/progressBar.pas @@ -44,11 +44,12 @@ TProgressBar = class(TObject) public destructor Destroy; override; function brighter: integer; + function centreCursor: boolean; function darker: integer; function formResize: boolean; function initProgressBar(const aForm: TForm): boolean; function resetColor: integer; - function setNewPosition(const x: integer): integer; + function setNewPosition(const x: integer): integer; property initialized: boolean read FInitialized; property max: integer read getMax write setMax; property position: integer read getPosition write setPosition; @@ -80,6 +81,12 @@ function TProgressBar.brighter: integer; result := FPB.barColor1; end; +function TProgressBar.centreCursor: boolean; +begin + var vPoint := FPB.clientToScreen(point(FPB.width div 2, FPB.height div 2)); + setCursorPos(vPoint.x, vPoint.y); +end; + constructor TProgressBar.create; begin inherited; diff --git a/uiCtrls.pas b/uiCtrls.pas index 655ab48..c6deac2 100644 --- a/uiCtrls.pas +++ b/uiCtrls.pas @@ -76,7 +76,7 @@ TUI = class(TObject) function renameFile(const aFilePath: string): boolean; function resize(const aWnd: HWND; const pt: TPoint; const X: int64; const Y: int64): boolean; function showAboutBox: boolean; - function setWindowSize(const aMediaType: TMediaType): boolean; + function setWindowSize(const aMediaType: TMediaType; coverArt: boolean = FALSE): boolean; function showWindow: boolean; function showXY: boolean; function shutTimeline: boolean; @@ -130,6 +130,8 @@ function TUI.adjustAspectRatio(const aWnd: HWND; const X: int64; const Y: int64) vRatio: double; vWidth, vHeight: integer; begin + case MP.mediaType = mtImage of TRUE: EXIT; end; + case (MP.mediaType = mtAudio) AND (NOT MI.hasCoverArt) of TRUE: EXIT; end; case GV.closeApp of TRUE: EXIT; end; case FMainForm.WindowState = wsMaximized of TRUE: EXIT; end; @@ -143,7 +145,6 @@ function TUI.adjustAspectRatio(const aWnd: HWND; const X: int64; const Y: int64) case (UI.width <> vWidth) or (UI.height <> vHeight) of TRUE: setWindowPos(aWnd, HWND_TOP, 0, 0, vWidth, vHeight, SWP_NOMOVE); end; // don't add SWP_SHOWWINDOW -// debugFormat('%dx%d AR=%f', [vWidth, vHeight, vRatio]); postMessage(GV.appWnd, WM_AUTO_CENTRE_WINDOW, 0, 0); @@ -456,6 +457,7 @@ function TUI.maximize: boolean; begin setWindowSize(mtVideo); end; + function TUI.minimizeWindow: boolean; begin @@ -549,16 +551,21 @@ procedure TUI.setWidth(const Value: integer); FMainForm.width := value; end; -function TUI.setWindowSize(const aMediaType: TMediaType): boolean; +function TUI.setWindowSize(const aMediaType: TMediaType; coverArt: boolean = FALSE): boolean; begin - case aMediaType of mtAudio: begin FMainForm.width := 600; - FMainForm.height := UI_DEFAULT_AUDIO_HEIGHT; end; + case aMediaType of mtAudio: begin case coverArt of TRUE: FMainForm.width := 600; + FALSE: FMainForm.width := 600; end; + case coverArt of FALSE: FMainForm.height := UI_DEFAULT_AUDIO_HEIGHT; + TRUE: FMainForm.height := 400; end;end; mtVideo: begin var vWidth := trunc((CU.getScreenHeight - 50) / CU.getAspectRatio(MI.X, MI.Y)); var VHeight := CU.getScreenHeight - 50; - SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOSIZE); // center window - SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOMOVE); // resize window -// debugFormat('vWidth&vHeight=%dx%d XY=%dx%d AR=%f', [vWidth, vHeight, MI.X, MI.Y, CU.getAspectRatio(MI.X, MI.Y)]); - end;end; + SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOSIZE); // center window + SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOMOVE); end; // resize window + mtImage: begin var vWidth := trunc((CU.getScreenHeight + 500)); // / CU.getAspectRatio(MI.imageWidth, MI.imageHeight)); + var VHeight := CU.getScreenHeight - 50; + SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOSIZE); // center window + SetWindowPos(FMainForm.Handle, HWND_TOP, (CU.getScreenWidth - vWidth) div 2, (CU.getScreenHeight - vHeight) div 2, vWidth, vHeight, SWP_NOMOVE); end; // resize window + end; end; function TUI.setWindowStyle(const aForm: TForm): boolean;