mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-11-28 04:50:49 +01:00
1040 lines
24 KiB
C++
1040 lines
24 KiB
C++
#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);
|
|
} |