winamp/Src/Winamp/VideoOutput.cpp

1040 lines
24 KiB
C++
Raw Normal View History

2024-09-24 13:54:57 +01:00
#include <windowsx.h>
#include "main.h"
#include "VideoOutput.h"
#include "VideoOutputChild.h"
#include "vid_none.h"
#include "vid_ddraw.h"
#include "vid_overlay.h"
#include "vid_d3d.h"
#include <cassert>
#include "directdraw.h"
#include "video.h"
#include "api.h"
#include "WinampAttributes.h"
#include "resource.h"
#include "../nu/AutoWide.h"
#include "stats.h"
#include "IVideoD3DOSD.h"
extern "C" int is_fullscreen_video;
#define WM_VIDEO_UPDATE_STATUS_TEXT WM_USER+0x874
#define WM_VIDEO_OPEN WM_USER+0x875
#define WM_VIDEO_CLOSE WM_USER+0x876
#define WM_VIDEO_RESIZE WM_USER+0x877
#define WM_VIDEO_OSDCHANGE WM_USER+0x888
#define WM_VIDEO_CREATE WM_USER+0x900
int g_bitmap_id = IDB_VIDEOLOGO;
int VideoOutput::class_refcnt = 0;
wchar_t vidoutbuf_save[1024] = {0};
static bool input_plugin_thread_safe = false;
//#define USE_GDIPLUS_VIDEO_RENDERER
IVideoOSD *posd = new IVideoD3DOSD;
HRESULT(WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter) = 0;
void OpenDirectDraw()
{
static int a = 0;
if (!_DirectDrawCreate && !a)
{
a++;
HINSTANCE h = LoadLibraryW(L"ddraw.dll");
if (h)
{
*(void**)&_DirectDrawCreate = (void*)GetProcAddress(h, "DirectDrawCreate");
}
}
}
HMENU BuildPopupMenu()
{
HMENU menu = GetSubMenu(GetSubMenu(top_menu, 3), 13);
{
static int menuset = 0;
if (!menuset)
{
InsertMenu(menu, (UINT)-1, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
InsertMenuA(menu, (UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(top_menu, 0), "Winamp");
menuset = 1;
}
}
updateTrackSubmenu();
return menu;
}
void VideoOutput::mainthread_Create()
{
if (!video_created)
{
m_video_output = new Direct3DVideoOutput(video_hwnd, this);
video_created=true;
}
}
VideoOutput::VideoOutput(HWND parent_hwnd, int initxpos, int initypos)
: m_logo(0),
m_logo_w(0),
m_logo_h(0),
userVideo(false)
{
video_palette = 0;
video_created = false;
AutoLock autoLock(guard LOCKNAME("VideoOutput::VideoOutput"));
WNDCLASSW wc = {0, };
wc.style = CS_DBLCLKS;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"WinampVideoChild";
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
if (!class_refcnt) RegisterClassW(&wc);
class_refcnt++;
m_tracksel = NULL;
fs_reparented_rgn = 0;
fs_reparented = 0;
m_ignore_change = false;
fs_has_resized = false;
m_opened = 0;
last_fullscreen_exit_time = 0;
curSubtitle = NULL;
m_statusmsg = 0;
m_bufferstate = -1;
m_msgcallback = 0;
m_msgcallback_tok = 0;
video_hwnd = 0;
aspect = 1.0;
m_need_change = false;
is_fs = 0;
memset(&oldfsrect, 0, sizeof(oldfsrect));
memset(&lastfsrect, 0, sizeof(lastfsrect));
m_video_output = NULL;
resetSubtitle();
m_lastbufinvalid = NULL;
CreateWindowExW(0, wc.lpszClassName, L"WinampVideoChildWindow",
parent_hwnd ? WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS :
(WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)),
0, 0, 1, 1,
parent_hwnd, NULL, wc.hInstance, (void*)this);
posd->SetParent(video_hwnd);
}
VideoOutput::~VideoOutput()
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::~VideoOutput"));
free(m_statusmsg);
posd->Hide();
if (m_video_output) m_video_output->close();
m_video_output = 0;
DestroyWindow(video_hwnd);
if (m_logo)
DeleteObject(m_logo);
m_logo = 0;
if (posd)
{
delete posd;
posd = NULL;
}
}
void VideoOutput::LoadLogo()
{
static wchar_t logo_tmp[MAX_PATH];
if(!logo_tmp[0]) StringCchPrintfW(logo_tmp,MAX_PATH,L"%s\\videologo.bmp",CONFIGDIR);
if(PathFileExistsW(logo_tmp)) m_logo = (HBITMAP)LoadImageW(0,logo_tmp,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(!m_logo) m_logo = (HBITMAP)LoadImage(hMainInstance, MAKEINTRESOURCE(g_bitmap_id), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
BITMAP bm;
GetObject(m_logo, sizeof(BITMAP), &bm);
m_logo_w = bm.bmWidth;
m_logo_h = bm.bmHeight;
if (m_logo_h < 0)
m_logo_h = -m_logo_h;
}
void VideoOutput::UpdateText(const wchar_t *videoInfo)
{
{
//AutoLock lock(textGuard);
StringCchCopyW(vidoutbuf_save, 1023, (wchar_t*)videoInfo); // 1023 so that we can guarantee that this will be null terminated even in the middle of a strcpy
}
PostMessageW(hVideoWindow, WM_VIDEO_UPDATE_STATUS_TEXT, (WPARAM)vidoutbuf_save, 0);
PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VIDEOINFO, IPC_CB_MISC);
}
INT_PTR VideoOutput::extended(INT_PTR param1, INT_PTR param2, INT_PTR param3)
{
switch (param1) // nonlocking commands
{
case VIDUSER_GET_VIDEOHWND:
return (INT_PTR)video_hwnd;
case VIDUSER_SET_INFOSTRING:
if (param2)
UpdateText(AutoWide((const char *)param2));
return 0;
case VIDUSER_SET_INFOSTRINGW:
if (param2)
UpdateText((const wchar_t *)param2);
return 0;
}
AutoLock autoLock(guard LOCKNAME("VideoOutput::extended"));
switch (param1)
{
case VIDUSER_SET_PALETTE:
{
RGBQUAD *palette = (RGBQUAD *)param2;
if (m_video_output)
m_video_output->setPalette(palette);
else
video_palette = palette;
return 0;
}
case VIDUSER_SET_VFLIP:
{
if (m_video_output)
m_video_output->setVFlip(param2);
return 0;
}
case VIDUSER_SET_TRACKSELINTERFACE:
m_tracksel = (ITrackSelector *)param2;
return 0;
case VIDUSER_OPENVIDEORENDERER:
{/*
userVideo = true;
m_video_output = (VideoRenderer *)param2;
VideoOpenStruct *openStruct = (VideoOpenStruct *)param3;
int x = openUser(openStruct->w, openStruct->h, openStruct->vflip, openStruct->aspectratio, openStruct->fmt);
if (x)
{
m_video_output = 0;
userVideo = false;
return 0;
}
else*/
return 1;
}
case VIDUSER_CLOSEVIDEORENDERER:
close();
userVideo = false;
return 1;
case VIDUSER_GETPOPUPMENU:
return (INT_PTR)BuildPopupMenu();
case VIDUSER_SET_THREAD_SAFE:
input_plugin_thread_safe = !!param2;
break;
}
return 0;
}
int VideoOutput::get_latency()
{
return config_video_vsync2 ? 15 : 0;
}
void VideoOutput::adjustAspect(RECT &rd)
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::adjustAspect"));
if (posd->Showing() /*&& config_video_osd*/)
{
rd.top += posd->GetBarHeight();
rd.bottom -= posd->GetBarHeight();
}
if (config_video_aspectadj)
{
int outh = rd.bottom - rd.top;
int outw = rd.right - rd.left;
double outputaspect = aspect;
if (config_video_useratio && config_video_ratio1 && config_video_ratio2)
{
RECT r;
getViewport(&r, hVideoWindow, 1, NULL);
int screenx = r.right - r.left;
int screeny = r.bottom - r.top;
if (screenx && screeny)
{
outputaspect *= config_video_ratio1 * screeny / ((double)screenx * (double)config_video_ratio2);
}
}
int newh = (int)((outputaspect * height * outw) / (double)width);
int neww = (int)((width * outh) / (height * outputaspect));
if (outh > newh) // black bars on top and bottom
{
int d = outh - newh;
rd.top += d / 2;
rd.bottom -= d - d / 2;
}
else if (outw > neww) // black bars on left and right
{
int d = outw - neww;
rd.left += d / 2;
rd.right -= d - d / 2;
}
}
}
LRESULT CALLBACK VideoOutput::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == g_scrollMsg) // can't check against variables in case statements
{
wParam <<= 16;
uMsg = WM_MOUSEWHEEL;
}
if (FALSE != IsDirectMouseWheelMessage(uMsg))
{
SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
return TRUE;
}
switch (uMsg)
{
case WM_MOUSEWHEEL:
return SendMessageW(hMainWindow, uMsg, wParam, lParam);
case WM_CREATE:
{
VideoOutput *vid = (VideoOutput *)((CREATESTRUCT *)lParam)->lpCreateParams;
vid->video_hwnd = hwnd;
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)vid);
}
return 0;
default: /// pass it on to the other window procedure
VideoOutput *_This = (VideoOutput*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
if (_This)
return _This->WindowProc(hwnd, uMsg, wParam, lParam);
else
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
void VideoOutput::notifyBufferState(int bufferstate) /* 0-255*/
{
m_bufferstate = bufferstate;
if (bufferstate == -1 || bufferstate == 255 || (GetTickCount() - m_lastbufinvalid > 500)) // don't want to do this too often
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::notifyBufferState"));
if (!m_video_output || !m_video_output->onPaint(video_hwnd))
InvalidateRect(video_hwnd, 0, TRUE);
m_lastbufinvalid = GetTickCount();
}
}
void VideoOutput::DrawLogo(HDC out, RECT *canvas_size)
{
int bufferState = m_bufferstate;
if (m_logo && config_video_logo)
{
HDC dc = CreateCompatibleDC(NULL);
SelectObject(dc, m_logo);
int xp = (canvas_size->right - canvas_size->left - m_logo_w) / 2;
int yp = (canvas_size->bottom - canvas_size->top - m_logo_h) / 2;
BitBlt(out, xp, yp, m_logo_w, m_logo_h, dc, 0, 0, SRCCOPY);
if (bufferState != -1)
{
if (bufferState < 16) bufferState = 16;
HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(0, 0, 0)));
HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(0, 0, 0)));
Rectangle(out, canvas_size->left, canvas_size->top, canvas_size->right, yp);
if (m_statusmsg)
Rectangle(out, canvas_size->left, yp + m_logo_h, canvas_size->right, canvas_size->bottom);
else
{
Rectangle(out, canvas_size->left, yp + m_logo_h + 2 + 9, canvas_size->right, canvas_size->bottom);
Rectangle(out, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + m_logo_h + 2, canvas_size->right, yp + 9 + m_logo_h + 2);
}
Rectangle(out, canvas_size->left, yp, xp - 1, yp + m_logo_h + 9 + 2);
Rectangle(out, xp + m_logo_w + 1, yp, canvas_size->right, yp + m_logo_h + 2);
DeleteObject(SelectObject(out, oldobj2));
DeleteObject(SelectObject(out, oldobj1));
}
if (m_statusmsg)
{
RECT subr = {0, yp + m_logo_h + 2, canvas_size->right, canvas_size->bottom};
SetTextColor(out, RGB(255, 255, 255));
SetBkMode(out, TRANSPARENT);
DrawTextA(out, m_statusmsg, -1, &subr, DT_TOP | DT_CENTER | DT_NOCLIP | DT_NOPREFIX);
}
else
{
yp += m_logo_h + 2;
if (bufferState)
{
HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(128, 128, 128)));
HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(255, 255, 255)));
Rectangle(out, xp - 1, yp, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + 9);
DeleteObject(SelectObject(out, oldobj2));
DeleteObject(SelectObject(out, oldobj1));
}
}
DeleteDC(dc);
}
}
void VideoOutput::PaintLogo(int bufferState)
{
// TODO: ask renderer to draw this shiz
AutoLock autoLock(guard LOCKNAME("VideoOutput::PaintLogo"));
PAINTSTRUCT p;
BeginPaint(video_hwnd, &p);
RECT r;
GetClientRect(video_hwnd, &r);
HDC out = p.hdc;
HRGN hrgn = CreateRectRgnIndirect(&r);
HBRUSH b = (HBRUSH)GetStockObject(BLACK_BRUSH);
FillRgn(out, hrgn, b);
DeleteObject(b);
DeleteObject(hrgn);
DrawLogo(out, &r);
EndPaint(video_hwnd, &p);
}
// the big window procedure
LRESULT VideoOutput::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// the follow messages are handled w/o a lock
switch (uMsg)
{
case WM_USER + 0x1:
m_need_change = true;
break;
case WM_USER + 0x2:
m_ignore_change = !!lParam;
break;
case WM_ERASEBKGND:
return 1;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_VIDEOWND_VIDEOOPTIONS:
prefs_last_page = 24;
prefs_dialog(1);
break;
case ID_VID_AUDIO0:
case ID_VID_AUDIO1:
case ID_VID_AUDIO2:
case ID_VID_AUDIO3:
case ID_VID_AUDIO4:
case ID_VID_AUDIO5:
case ID_VID_AUDIO6:
case ID_VID_AUDIO7:
case ID_VID_AUDIO8:
case ID_VID_AUDIO9:
case ID_VID_AUDIO10:
case ID_VID_AUDIO11:
case ID_VID_AUDIO12:
case ID_VID_AUDIO13:
case ID_VID_AUDIO14:
case ID_VID_AUDIO15:
{
VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
if (!out)
break;
out->getTrackSelector()->setAudioTrack(LOWORD(wParam) - ID_VID_AUDIO0);
break;
}
case ID_VID_VIDEO0:
case ID_VID_VIDEO1:
case ID_VID_VIDEO2:
case ID_VID_VIDEO3:
case ID_VID_VIDEO4:
case ID_VID_VIDEO5:
case ID_VID_VIDEO6:
case ID_VID_VIDEO7:
case ID_VID_VIDEO8:
case ID_VID_VIDEO9:
case ID_VID_VIDEO10:
case ID_VID_VIDEO11:
case ID_VID_VIDEO12:
case ID_VID_VIDEO13:
case ID_VID_VIDEO14:
case ID_VID_VIDEO15:
{
VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
if (!out) break;
out->getTrackSelector()->setVideoTrack(LOWORD(wParam) - ID_VID_VIDEO0);
break;
}
}
break;
case WM_RBUTTONUP:
if (!is_fs)
{
POINT p;
GetCursorPos(&p);
DoTrackPopup(BuildPopupMenu(), TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, hwnd);
}
break;
case WM_LBUTTONDOWN: // putting this here prevents a deadlock, but allows a race condition over video drawing =(
{
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (is_fs && config_video_osd)
{
if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
{
if (posd->MouseDown(x, y, wParam))
videoToggleFullscreen();
}
}
else
{
SetCapture(video_hwnd);
clickx = x;
clicky = y;
SetFocus(video_hwnd);
}
}
break;
case WM_MOUSEMOVE:
{
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (is_fs && config_video_osd)
{
if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
{
posd->MouseMove(x, y, wParam);
}
}
else if (GetCapture() == video_hwnd && config_easymove)
{
POINT p = { x, y};
ClientToScreen(hVideoWindow, &p);
p.x -= clickx;
p.y -= clicky;
SendMessageW(hVideoWindow, WM_USER + 0x100, 1, (LPARAM)&p);
}
}
break;
case WM_LBUTTONUP:
{
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (GetCapture() == video_hwnd)
ReleaseCapture();
if (is_fs && config_video_osd)
{
if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
if (posd->MouseUp(x, y, wParam))
videoToggleFullscreen();
}
SetFocus(hVideoWindow);
}
break;
}
switch (uMsg)
{
case WM_VIDEO_OSDCHANGE:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_VIDEO_OSDCHANGE"));
if (m_video_output)
{
m_video_output->Refresh();
m_video_output->timerCallback();
}
}
break;
case WM_SHOWWINDOW:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SHOWWINDOW"));
if (wParam == TRUE // being shown
&& !m_logo) // logo hasn't been loaded yet
LoadLogo();
}
break;
case WM_INITMENUPOPUP:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_INITMENUPOPUP"));
return SendMessageW(hMainWindow, uMsg, wParam, lParam); // for popup menus
}
case WM_WINDOWPOSCHANGED:
case WM_SIZE:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SIZE"));
if (m_video_output)
{
m_video_output->OnWindowSize();
if (is_fs)
if ( ((IVideoD3DOSD *)posd)->isOSDInited() )
((IVideoD3DOSD *)posd)->UpdateOSD(hwnd, this);
}
}
break;
case WM_TIMER:
case WM_WINDOWPOSCHANGING:
case WM_MOVE:
case WM_MOVING:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_TIMER, etc"));
if (m_video_output && !m_ignore_change)
m_video_output->timerCallback();
if (uMsg == WM_TIMER)
return 0;
}
break;
case WM_LBUTTONDBLCLK:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_LBUTTONDBLCLK"));
videoToggleFullscreen();
}
break;
case WM_PAINT:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
if (m_video_output && m_video_output->onPaint(hwnd))
return 0;
PaintLogo(m_bufferstate);
}
return 0;
break;
case WM_PRINTCLIENT:
{
//AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
//if (m_video_output && m_video_output->onPaint(hwnd))
// return 0;
RECT r;
GetClientRect(video_hwnd, &r);
DrawLogo((HDC)wParam, &r);
}
return 0;
break;
case WM_KEYDOWN:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_KEYDOWN"));
if (wParam == VK_ESCAPE && is_fs)
{
videoToggleFullscreen();
//remove_fullscreen();
return 1;
}
if (!is_fs)
{
if (wParam == '3' || LOWORD(wParam) == 192 /* ` */)
{
SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM50, 0); return 0;
}
if (wParam == '1')
{
SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM100, 0); return 0;
}
if (wParam == '2')
{
SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM200, 0); return 0;
}
}
if (wParam == ' ')
{
SendMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0); return 0;
}
if(wParam == 'F' && (GetAsyncKeyState(VK_SHIFT)&0x8000) && !(GetAsyncKeyState(VK_CONTROL)&0x8000))
{
SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_VERTICALLYFLIP, 0); return 0;
}
}
break;
case WM_COMMAND:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_COMMAND"));
switch (LOWORD(wParam))
{
case ID_VIDEOWND_VERTICALLYFLIP:
{
int new_fliprgb = !config_video_fliprgb;//IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_FLIPRGB)?1:0;
config_video_fliprgb = 0;
videoSetFlip(new_fliprgb);
config_video_fliprgb = new_fliprgb;
break;
}
case ID_VIDEOWND_ZOOMFULLSCREEN:
videoGoFullscreen();
break;
case ID_VIDEOWND_ZOOM200:
case ID_VIDEOWND_ZOOM100:
case ID_VIDEOWND_ZOOM50:
if (m_video_output)
UpdateVideoSize(width, height, aspect, LOWORD(wParam));
else
UpdateVideoSize(320, 240, 1.0, LOWORD(wParam));
break;
default:
SendMessageW(hMainWindow, WM_COMMAND, wParam, lParam);
break;
}
}
break;
case WM_SETCURSOR:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SETCURSOR"));
if (is_fs)
{
SetCursor(posd->Showing() ? LoadCursor(NULL, IDC_ARROW) : NULL);
return TRUE;
}
else
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
break;
case WM_SYSCOMMAND:
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SYSCOMMAND"));
// eat screen saver message when fullscreen
if (((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER) && config_video_noss &&
video_isVideoPlaying())
{
return -1;
}
}
break;
}
if (m_msgcallback)
{
return m_msgcallback(m_msgcallback_tok, hwnd, uMsg, wParam, lParam);
}
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
void VideoOutput::fullscreen()
{
AutoLock autoLock(guard LOCKNAME("VideoOutput::fullscreen"));
if (!m_video_output || !m_opened)
return ;
if (is_fs)
return ;
// TODO: let the video renderer handle fullscreen itself, if it can.
/*if (last_fullscreen_exit_time + 250 > GetTickCount()) // gay hack
return ; // dont let you go back and forth too quickly
*/
GetWindowRect(hVideoWindow, &oldfsrect); // save the old coordinates
getViewport(&lastfsrect, video_hwnd, 1, NULL);
if (GetParent(hVideoWindow))
{
fs_reparented_rgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hVideoWindow, fs_reparented_rgn);
fs_reparented = SetParent(hVideoWindow, NULL);
SetWindowRgn(hVideoWindow, NULL, FALSE);
ScreenToClient(fs_reparented, (LPPOINT)&oldfsrect);
ScreenToClient(fs_reparented, ((LPPOINT)&oldfsrect) + 1);
}
is_fullscreen_video = true;
is_fs = true;
//m_video_output->Fullscreen(true);
SetWindowPos(hVideoWindow, HWND_TOPMOST, lastfsrect.left, lastfsrect.top, lastfsrect.right - lastfsrect.left, lastfsrect.bottom - lastfsrect.top, SWP_DRAWFRAME | SWP_NOACTIVATE);
SetFocus(hVideoWindow);
resetSubtitle();
}
extern "C" HWND hExternalVisWindow;
int VideoOutput::openUser(int w, int h, int vflip, double aspectratio, unsigned int fmt)
{
// TODO
return 1;
}
int VideoOutput::open(int w, int h, int vflip, double aspectratio, unsigned int fmt)
{
if (!video_created)
SendMessageW(hVideoWindow, WM_VIDEO_CREATE, 0, 0);
if (!h || !w || !fmt) // check this after creating the video window. some plugins use this call to open the video output early
return 0;
AutoLock autoLock(guard LOCKNAME("VideoOutput::open"));
if (!m_need_change)
stats.IncrementStat(Stats::VIDEOS_PLAYED);
if (hExternalVisWindow)
PostMessageW(hExternalVisWindow, WM_USER + 1666, 1, 15);
m_opened = false;
userVideo = false;
width = w;
height = h;
type = fmt;
aspect = aspectratio;
if (m_video_output)
{
if (type == VIDEO_MAKETYPE('N','O','N','E'))
{
m_opened = true;
PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
OpenVideoSize(width, height, aspect);
fs_has_resized = is_fs;
return 0;
}
else if (m_video_output->OpenVideo(w, h, type, vflip, aspect))
{
if (video_palette)
m_video_output->setPalette(video_palette);
video_palette = 0;
DoTheVistaVideoDance();
InvalidateRect(video_hwnd, NULL, TRUE);
m_opened = true;
PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
if (!m_need_change) //don't update size when renegotiating video output
{
OpenVideoSize(width, height, aspect);
fs_has_resized = is_fs;
}
return 0;
}
}
return 1;
}
void VideoOutput::draw(void *frame)
{
if (!frame)
return ;
AutoLock autoLock(guard LOCKNAME("VideoOutput::draw"));
if (m_video_output)
{
m_video_output->displayFrame((const char *)frame, 0, 0);
}
}
extern wchar_t draw_vw_info_lastb[512];
void VideoOutput::close()
{
UpdateText(L"");
AutoLock autoLock(guard);
if (!m_opened)
return ;
m_opened = false;
if (m_video_output)
{
m_video_output->drawSubtitle(0);
m_video_output->close();
}
m_bufferstate = -1;
draw_vw_info_lastb[0] = 0;
input_plugin_thread_safe = false; // reset this
InvalidateRect(video_hwnd, NULL, true);
PostMessageW(hVideoWindow, WM_VIDEO_CLOSE, 0, 0);
}
int VideoOutput::is_fullscreen()
{
return is_fs;
}
void VideoOutput::showStatusMsg(const char *text)
{
AutoLock autoLock(guard);
m_statusmsg = _strdup(text);
PaintLogo(m_bufferstate);
//InvalidateRect(video_hwnd, NULL, TRUE);
}
void VideoOutput::drawSubtitle(SubsItem *item)
{
AutoLock autoLock(guard);
if (item == curSubtitle)
return ;
curSubtitle = item;
if (m_video_output)
m_video_output->drawSubtitle(item);
}
void VideoOutput::resetSubtitle()
{
AutoLock autoLock(guard);
curSubtitle = NULL;
if (m_video_output)
m_video_output->resetSubtitle();
// InvalidateRect(this->getHwnd(), 0, TRUE);
}
void VideoOutput::remove_fullscreen()
{
AutoLock autoLock(guard);
if (!is_fs)
{
is_fullscreen_video = false;
return ;
}
posd->Hide();
posd->ctrlrects_ready = 0; //tofix
if (m_video_output)
{
// m_video_output->Fullscreen(false);
}
resetSubtitle();
is_fs = 0;
if (fs_reparented)
{
SetParent(hVideoWindow, fs_reparented);
SetWindowRgn(hVideoWindow, fs_reparented_rgn, FALSE);
fs_reparented = 0;
SetWindowPos(hVideoWindow, HWND_TOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE | SWP_NOZORDER);
}
else
SetWindowPos(hVideoWindow, config_aot ? HWND_TOPMOST : HWND_NOTOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE);
last_fullscreen_exit_time = GetTickCount();
posd->Hide();
if (!m_opened && m_video_output)
{
m_video_output->close();
}
is_fullscreen_video = false;
if (fs_has_resized)
{
fs_has_resized = false;
if (config_video_updsize)
UpdateVideoSize(width, height, aspect);
}
}
void VideoOutput::UpdateVideoSize(int newWidth, int newHeight, double newAspect, int zoom)
{
if (!m_opened)
return;
// fill in default values if we have 0s
if (!newWidth)
newWidth = 320;
if (!newHeight)
newHeight = 240;
switch (zoom)
{
case ID_VIDEOWND_ZOOM200:
newWidth *= 2;
newHeight *= 2;
break;
case ID_VIDEOWND_ZOOM50:
newWidth /= 2;
newHeight /= 2;
break;
}
// establish a minimum window size
if (newWidth < 256)
newWidth = 256;
if (newHeight < 64)
newHeight = 64;
if (newAspect > 0.001) // floating point can be weird about checking == 0
{
if (newAspect < 1.0)
newWidth = (int)((double)newWidth / newAspect);
else
newHeight = (int)((double)newHeight * newAspect);
}
//SendNotifyMessage(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
PostMessageW(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
}
void VideoOutput::OpenVideoSize(int newWidth, int newHeight, double newAspect)
{
// fill in default values if we have 0s
if (!newWidth)
newWidth = 320;
if (!newHeight)
newHeight = 240;
// establish a minimum window size
if (newWidth < 256)
newWidth = 256;
if (newHeight < 64)
newHeight = 64;
if (newAspect > 0.001) // floating point can be weird about checking == 0
{
if (newAspect < 1.0)
newWidth = (int)((double)newWidth / newAspect);
else
newHeight = (int)((double)newHeight * newAspect);
}
PostMessageW(hVideoWindow, WM_VIDEO_OPEN, newWidth, newHeight);
}
void VideoOutput::SetVideoPosition(int x, int y, int width, int height)
{
AutoLock autoLock(guard);
SetWindowPos(getHwnd(), 0, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
}