aboutsummaryrefslogtreecommitdiff
path: root/Src/nsv/nsvplay/video.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/nsv/nsvplay/video.cpp')
-rw-r--r--Src/nsv/nsvplay/video.cpp964
1 files changed, 964 insertions, 0 deletions
diff --git a/Src/nsv/nsvplay/video.cpp b/Src/nsv/nsvplay/video.cpp
new file mode 100644
index 00000000..8a6532c7
--- /dev/null
+++ b/Src/nsv/nsvplay/video.cpp
@@ -0,0 +1,964 @@
+#include <windows.h>
+#include <ddraw.h>
+#include "main.h"
+#include "video.h"
+#include "subtitles.h"
+
+#include "resource.h"
+
+#undef GetSystemMetrics
+
+#define OSD_ENABLED 1
+
+#define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
+#define OV_COL_R 16
+#define OV_COL_G 0
+#define OV_COL_B 16
+#define OSD_TEXT_SIZE 28
+#define OSD_TEXT_R 192
+#define OSD_TEXT_G 192
+#define OSD_TEXT_B 192
+#define OSD_TEXT_R_HILITE 255
+#define OSD_TEXT_G_HILITE 255
+#define OSD_TEXT_B_HILITE 255
+#define OSD_VOL_COL_R 0
+#define OSD_VOL_COL_G 0
+#define OSD_VOL_COL_B 192
+#define OSD_VOL_BKCOL_R 0
+#define OSD_VOL_BKCOL_G 0
+#define OSD_VOL_BKCOL_B 64
+
+#define TIMER_OSD_ID 1234
+
+#define CTRLTYPE_SYMBOL 0
+#define CTRLTYPE_TEXT 1
+#define CTRLTYPE_PROGRESS 2
+#define CTRLTYPE_SPACER 3
+
+#define CTRL_PROGRESSTEXT 0
+#define CTRL_PROGRESS 1
+#define CTRL_PROGRESSSPACER 2
+#define CTRL_REW 3
+#define CTRL_PLAY 4
+#define CTRL_PAUSE 5
+#define CTRL_STOP 6
+#define CTRL_FFWD 7
+#define CTRL_VOLSPACER 8
+#define CTRL_VOLTEXT 9
+#define CTRL_VOL 10
+
+int g_ctrl_type[NUM_WIDGETS] = {
+ CTRLTYPE_TEXT,
+ CTRLTYPE_PROGRESS,
+ CTRLTYPE_SPACER,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SYMBOL,
+ CTRLTYPE_SPACER,
+ CTRLTYPE_TEXT,
+ CTRLTYPE_PROGRESS
+};
+
+const char *g_ctrl_text[NUM_WIDGETS] = {
+ "Progress ",
+ "",
+ "",
+ "7", // rew
+ "4", // play
+ ";", // pause
+ "<", // stop
+ "8", // ffwd
+ "",
+ "Volume ",
+ ""
+};
+
+int g_ctrl_force_width[NUM_WIDGETS] = {
+ 0,
+ 96, // progress bar width
+ 32, // spacer width
+ 0, // rew
+ 0, // play
+ 0, // pause
+ 0, // stop
+ 0, // ffwd
+ 32, // spacer width
+ 0,
+ 64 // volume bar width
+};
+
+extern HINSTANCE g_hInstance;
+extern int g_bitmap_id;
+
+static BOOL WINAPI DDEnumCallbackEx(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm) {
+ VideoOutputChild *ovo=(VideoOutputChild *)lpContext;
+ if(ovo->m_found_devguid) return 1;
+ if(hm==ovo->m_monitor_to_find) {
+ ovo->m_devguid=*lpGUID;
+ ovo->m_found_devguid=1;
+ }
+ return 1;
+}
+
+void VideoOutputChild::update_monitor_coords(VideoOutput *parent)
+{
+ //find the correct monitor if multiple monitor support is present
+ HWND hwnd=parent->getHwnd();
+ m_found_devguid=0;
+ m_mon_x=0;
+ m_mon_y=0;
+
+ HINSTANCE h=LoadLibrary("user32.dll");
+ if (h) {
+ HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT,DWORD)) GetProcAddress(h,"MonitorFromPoint");
+ HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(h, "MonitorFromRect");
+ HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags)=(HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(h, "MonitorFromWindow");
+ BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = (BOOL (WINAPI *)(HMONITOR,LPMONITORINFO)) GetProcAddress(h,"GetMonitorInfoA");
+ if (Mfp && Mfr && Mfw && Gmi) {
+ RECT r;
+ GetWindowRect(hwnd,&r);
+ HMONITOR hm=Mfr(&r,NULL);
+ if(hm) {
+ HINSTANCE hdd = LoadLibrary("ddraw.dll");
+ if(hdd) {
+ typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKEXA)(GUID FAR *, LPSTR, LPSTR, LPVOID, HMONITOR);
+ typedef HRESULT (WINAPI * LPDIRECTDRAWENUMERATEEX)( LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags);
+ LPDIRECTDRAWENUMERATEEX lpDDEnumEx;
+ lpDDEnumEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hdd,"DirectDrawEnumerateExA");
+ if (lpDDEnumEx) {
+ m_monitor_to_find=hm;
+ lpDDEnumEx(&DDEnumCallbackEx, this, DDENUM_ATTACHEDSECONDARYDEVICES|DDENUM_NONDISPLAYDEVICES);
+ if(m_found_devguid) {
+ MONITORINFOEX mi;
+ memset(&mi,0,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ if (Gmi(hm,&mi)) {
+ m_mon_x=mi.rcMonitor.left;
+ m_mon_y=mi.rcMonitor.top;
+ }
+ }
+ }
+ FreeLibrary(hdd);
+ }
+ }
+ }
+ FreeLibrary(h);
+ }
+}
+
+int VideoOutput::get_latency()
+{
+ return vid_vsync?15:0;
+}
+
+#undef GetSystemMetrics
+int VideoOutput::class_refcnt=0;
+
+void VideoOutput::adjustAspect(RECT &rd)
+{
+ if (vid_aspectadj)
+ {
+ int outh=rd.bottom-rd.top;
+ int outw=rd.right-rd.left;
+
+ int newh=(int)((aspect*height*outw)/(double)width);
+ int neww=(int)((width*outh)/(height*aspect));
+
+ 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 == WM_CREATE)
+ {
+ SetWindowLong(hwnd,GWL_USERDATA,(long)((CREATESTRUCT *)lParam)->lpCreateParams);
+ ShowWindow(hwnd,SW_SHOW);
+ if (GetParent(hwnd))
+ {
+ RECT r;
+ GetClientRect(GetParent(hwnd),&r);
+ SetWindowPos(hwnd,NULL,0,0,
+ r.right,
+ r.bottom,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+ return 0;
+ }
+
+ VideoOutput *_This=(VideoOutput*)GetWindowLong(hwnd,GWL_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;
+#ifdef ACTIVEX_CONTROL
+ PostMessage( video_hwnd, STATUS_MSG, STATUS_PREBUFFER, bufferstate );
+#endif
+ if (!m_video_output) {
+ if(GetTickCount()-m_lastbufinvalid>500) {
+ InvalidateRect(video_hwnd,NULL,FALSE);
+ m_lastbufinvalid=GetTickCount();
+ }
+ }
+}
+
+LRESULT VideoOutput::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_TIMER:
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ case WM_SIZE:
+ case WM_MOVE:
+ case WM_MOVING:
+ if (uMsg == WM_TIMER && wParam == TIMER_OSD_ID) {
+ hideOSD();
+ return 0;
+ }
+ EnterCriticalSection(&m_cs);
+ if(m_video_output) m_video_output->timerCallback();
+ LeaveCriticalSection(&m_cs);
+ if (uMsg == WM_TIMER) return 0;
+ break;
+
+ case WM_LBUTTONDOWN:
+ if(is_fs)
+ osdHitTest(LOWORD(lParam),HIWORD(lParam),0);
+#ifdef ACTIVEX_CONTROL
+ SendMessage( video_hwnd, STATUS_MSG, STATUS_MOUSEPRESS, 1 );
+#endif
+ break;
+
+ case WM_PAINT:
+ {
+ if (m_video_output && m_video_output->onPaint(hwnd,(HDC)wParam)) return 0;
+ if (m_logo && !m_video_output)
+ {
+ PAINTSTRUCT p;
+ BeginPaint(hwnd,&p);
+
+ RECT r;
+ GetClientRect(hwnd,&r);
+
+ HDC out=p.hdc;
+
+ HDC dc=CreateCompatibleDC(NULL);
+ SelectObject(dc,m_logo);
+ int xp=(r.right-r.left-m_logo_w)/2;
+ int yp=(r.bottom-r.top-m_logo_h)/2;
+ BitBlt(out,xp,yp,m_logo_w,m_logo_h,dc,0,0,SRCCOPY);
+
+ int bs=m_bufferstate;
+ if (bs < 16) bs=16;
+
+
+ HGDIOBJ oldobj1=SelectObject(out,CreateSolidBrush(RGB(0,0,0)));
+ HGDIOBJ oldobj2=SelectObject(out,CreatePen(PS_SOLID,0,RGB(0,0,0)));
+ Rectangle(out,r.left,r.top,r.right,yp);
+ if (m_statusmsg)
+ Rectangle(out,r.left,yp+m_logo_h,r.right,r.bottom);
+ else
+ {
+ Rectangle(out,r.left,yp+m_logo_h+2+9,r.right,r.bottom);
+ Rectangle(out,xp + ((bs * (m_logo_w+2))>>8),yp+m_logo_h+2,r.right, yp+9+m_logo_h+2);
+ }
+ Rectangle(out,r.left,yp,xp-1,yp+m_logo_h+9+2);
+ Rectangle(out,xp+m_logo_w+1,yp,r.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,r.right,r.bottom};
+ SetTextColor(out,RGB(255,255,255));
+ SetBkMode(out,TRANSPARENT);
+ DrawText(out,m_statusmsg,-1,&subr,DT_TOP|DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
+ }
+ else
+ {
+ yp+=m_logo_h+2;
+ if (bs)
+ {
+ 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 + ((bs * (m_logo_w+2))>>8), yp+9);
+ DeleteObject(SelectObject(out,oldobj2));
+ DeleteObject(SelectObject(out,oldobj1));
+ }
+ }
+ DeleteDC(dc);
+ EndPaint(hwnd,&p);
+ return 0;
+ }
+ }
+ break;
+
+ case WM_USER+0x1:
+ m_need_change=1;
+ break;
+
+#ifdef ACTIVEX_CONTROL
+ case STATUS_MSG:
+ SendStatus( wParam, lParam );
+ break;
+#endif
+
+ case WM_KEYDOWN:
+ if(wParam==27 && is_fs) remove_fullscreen();
+ break;
+
+ case WM_MOUSEMOVE:
+ if(is_fs) {
+ if (ignore_mousemove_count>0) {
+ ignore_mousemove_count--;
+ }
+ else if (abs(osdLastMouseX - LOWORD(lParam)) + abs(osdLastMouseY - HIWORD(lParam)) > 1) {
+ KillTimer(hwnd, TIMER_OSD_ID);
+ showOSD();
+ SetTimer(hwnd, TIMER_OSD_ID, 2000, NULL);
+
+ if (wParam & MK_LBUTTON)
+ osdHitTest(LOWORD(lParam),HIWORD(lParam),1);
+ else
+ osdHitTest(LOWORD(lParam),HIWORD(lParam),-1);
+ }
+ osdLastMouseX = LOWORD(lParam);
+ osdLastMouseY = HIWORD(lParam);
+ }
+ break;
+ }
+ if (m_msgcallback)
+ {
+ return m_msgcallback(m_msgcallback_tok,hwnd, uMsg, wParam, lParam);
+ }
+
+ return (DefWindowProc(hwnd, uMsg, wParam, lParam));
+}
+
+VideoOutput::VideoOutput(HWND parent_hwnd, int initxpos, int initypos)
+{
+ curSubtitle=NULL;
+ m_statusmsg=0;
+ m_bufferstate=0;
+ m_msgcallback=0;
+ m_msgcallback_tok=0;
+ video_hwnd=video_parent_hwnd=0;
+ decoder=0;
+
+ vid_aspectadj=true;
+ vid_overlays=true;
+ vid_ddraw=true;
+ vid_vsync=true;
+ aspect=1.0;
+ m_need_change=false;
+
+ width=height=flip=uyvy_output=yuy2_output=is_fs=ignore_mousemove_count=show_osd=0;
+ oldfsparent=0;
+ memset(&oldfsrect,0,sizeof(oldfsrect));
+ memset(&lastfsrect,0,sizeof(lastfsrect));
+ oldfsstyle=0;
+
+ m_video_output=NULL;
+
+ osdFontText=NULL;
+ osdFontSymbol=NULL;
+ osdProgressBrushBg=NULL;
+ osdProgressBrushFg=NULL;
+ osdProgressPenBg=NULL;
+ osdProgressPenFg=NULL;
+ osdProgressPenBgHilite=NULL;
+ osdBlackBrush=NULL;
+ osdMemDC=NULL;
+ osdMemBM=NULL;
+ osdOldBM=NULL;
+ osdMemBMW=0;
+ osdMemBMH=0;
+ osdLastMouseX=-1;
+ osdLastMouseY=-1;
+
+ for (int i=0; i<NUM_WIDGETS; i++)
+ SetRect(&ctrlrect[i], 0, 0, 0, 0);
+ ctrlrects_ready = 0;
+
+ resetSubtitle();
+
+ WNDCLASS wc={0,};
+
+ wc.hCursor=LoadCursor(NULL,IDC_ARROW);
+ wc.lpfnWndProc = WndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.lpszClassName = "NSVplay";
+ LOGBRUSH lb={BS_SOLID,RGB(OV_COL_R,OV_COL_G,OV_COL_B),};
+ wc.hbrBackground=CreateBrushIndirect(&lb);
+ if (!class_refcnt) RegisterClass(&wc);
+ class_refcnt++;
+
+ m_logo=(HBITMAP)LoadImage(g_hInstance,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;
+
+ InitializeCriticalSection(&m_cs);
+
+ video_hwnd=CreateWindowEx(0,wc.lpszClassName, "NSV Player",parent_hwnd?WS_CHILD:(WS_OVERLAPPEDWINDOW&(~WS_MAXIMIZEBOX)),
+ initxpos,initypos,320,200,
+ parent_hwnd, NULL,wc.hInstance,(void*)this);
+
+ video_parent_hwnd=parent_hwnd;
+
+ m_lastbufinvalid=0;
+
+#ifdef ACTIVEX_CONTROL
+ m_firstframe = 1;
+#endif
+}
+
+VideoOutputChild *VideoOutput::createVideoOutput(int n) {
+ if(!vid_overlays && !vid_ddraw) vid_overlays=true;
+
+ if(!vid_overlays) n++;
+ if(n==0) return new OverlayVideoOutput();
+ if(!vid_ddraw) n++;
+ if(n==1) return new DDrawVideoOutput();
+
+ return 0;
+}
+
+int VideoOutput::open(int w, int h, int vflip, double aspectratio, unsigned int fmt)
+{
+ EnterCriticalSection(&m_cs);
+ delete(m_video_output);
+ m_video_output=NULL;
+
+ if (!w) w=320;
+ if (!h) h=240;
+ width=w;
+ height=h;
+ flip=vflip;
+ type=fmt;
+ is_fs=0;
+ ignore_mousemove_count=0;
+ show_osd=0;
+ aspect=aspectratio;
+
+ for(int i=0;m_video_output=createVideoOutput(i);i++) {
+ if(m_video_output->create(this,w,h,fmt,vflip,aspectratio)) {
+ LeaveCriticalSection(&m_cs);
+ if (!GetParent(video_hwnd)) {
+ RECT r,r2;
+ int ow=width,oh=height;
+ if (aspect > 0.001)
+ {
+ if (aspect < 1.0) ow=(int)(ow/aspect);
+ else oh=(int)(oh*aspect);
+ }
+ GetWindowRect(video_hwnd,&r);
+ GetClientRect(video_hwnd,&r2);
+ SetWindowPos(video_hwnd,NULL,0,0,
+ ow+(r.right-r.left)-(r2.right-r2.left),
+ oh+(r.bottom-r.top)-(r2.bottom-r2.top),
+ SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+ return 0;
+ }
+ delete(m_video_output);
+ }
+ LeaveCriticalSection(&m_cs);
+ return 1;
+}
+
+void VideoOutput::draw(void *frame)
+{
+ if (!m_video_output || !frame) return;
+ if ((m_video_output && m_video_output->needChange()) || m_need_change) {
+ open(width,height,flip,aspect,type);
+ m_need_change=0;
+ }
+#ifdef ACTIVEX_CONTROL
+ if ( m_firstframe ) {
+ m_firstframe = 0;
+ PostMessage( video_hwnd, STATUS_MSG, STATUS_FIRSTFRAME, 1 );
+ }
+#endif
+ if (m_video_output) m_video_output->displayFrame((const char *)frame,0,0);
+}
+
+VideoOutput::~VideoOutput()
+{
+ free(m_statusmsg);
+ delete(m_video_output);
+ DestroyWindow(video_hwnd);
+ if (!--class_refcnt) UnregisterClass("NSVplay",GetModuleHandle(NULL));
+ if(osdFontText) DeleteObject(osdFontText);
+ if(osdFontSymbol) DeleteObject(osdFontSymbol);
+ if(osdProgressBrushBg) DeleteObject(osdProgressBrushBg);
+ if(osdProgressBrushFg) DeleteObject(osdProgressBrushFg);
+ if(osdBlackBrush ) DeleteObject(osdBlackBrush );
+ if(osdProgressPenBg ) DeleteObject(osdProgressPenBg );
+ if(osdProgressPenFg ) DeleteObject(osdProgressPenFg );
+ if(osdProgressPenBgHilite) DeleteObject(osdProgressPenBgHilite);
+ if(osdMemDC) {
+ SelectObject(osdMemDC,osdOldBM); // delete our doublebuffer
+ DeleteDC(osdMemDC);
+ }
+ if(osdMemBM) DeleteObject(osdMemBM);
+
+
+ DeleteCriticalSection(&m_cs);
+}
+
+void VideoOutput::close()
+{
+ delete(m_video_output);
+ m_video_output=NULL;
+}
+
+void VideoOutput::getViewport(RECT *r, HWND wnd, int full) {
+ POINT *p=NULL;
+ RECT *sr=NULL;
+ if (p || sr || wnd) {
+ HINSTANCE h=LoadLibrary("user32.dll");
+ if (h) {
+ HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT,DWORD)) GetProcAddress(h,"MonitorFromPoint");
+ HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(h, "MonitorFromRect");
+ HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags)=(HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(h, "MonitorFromWindow");
+ BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = (BOOL (WINAPI *)(HMONITOR,LPMONITORINFO)) GetProcAddress(h,"GetMonitorInfoA");
+ if (Mfp && Mfr && Mfw && Gmi) {
+ HMONITOR hm = NULL;
+ if (p)
+ hm=Mfp(*p,MONITOR_DEFAULTTONULL);
+ else if (sr)
+ hm=Mfr(sr,MONITOR_DEFAULTTONULL);
+ else if (wnd)
+ hm=Mfw(wnd,MONITOR_DEFAULTTONULL);
+ if (hm) {
+ MONITORINFOEX mi;
+ memset(&mi,0,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+
+ if (Gmi(hm,&mi)) {
+ if(!full) *r=mi.rcWork;
+ else *r=mi.rcMonitor;
+ FreeLibrary(h);
+ return;
+ }
+ }
+ }
+ FreeLibrary(h);
+ }
+ }
+ if (full)
+ { // this might be borked =)
+ r->top=r->left=0;
+ r->right=::GetSystemMetrics(SM_CXSCREEN);
+ r->bottom=::GetSystemMetrics(SM_CYSCREEN);
+ }
+ else
+ {
+ SystemParametersInfo(SPI_GETWORKAREA,0,r,0);
+ }
+}
+
+void VideoOutput::fullscreen()
+{
+ if (is_fs) return;
+ if(!m_video_output) return;
+ is_fs=1;
+ ignore_mousemove_count=2;
+
+ oldfsparent=GetParent(video_hwnd);
+ oldfsstyle=GetWindowLong(video_hwnd,GWL_STYLE);
+ if (!oldfsparent) GetWindowRect(video_hwnd,&oldfsrect);
+ else GetClientRect(video_hwnd,&oldfsrect);
+ getViewport(&lastfsrect,video_hwnd,1);
+
+ SetParent(video_hwnd,NULL);
+ SetWindowLong(video_hwnd,GWL_STYLE,WS_POPUP|WS_VISIBLE);
+ SetWindowPos(video_hwnd, HWND_TOPMOST, lastfsrect.left, lastfsrect.top, lastfsrect.right-lastfsrect.left, lastfsrect.bottom-lastfsrect.top, SWP_DRAWFRAME);
+ SetFocus(video_hwnd);
+
+ resetSubtitle();
+
+ //showOSD();
+
+ //SetCursor(NULL);
+}
+
+void VideoOutput::getOutputSize(int *w, int *h)
+{
+ RECT r2;
+ GetClientRect(video_hwnd,&r2);
+ *w=r2.right-r2.left;
+ *h=r2.bottom-r2.top;
+}
+
+void VideoOutput::setOutputSize(int w, int h)
+{
+ RECT r,r2;
+ GetWindowRect(video_hwnd,&r);
+ GetClientRect(video_hwnd,&r2);
+ SetWindowPos(video_hwnd, 0, 0,0,
+ w+(r.right-r.left)-(r2.right-r2.left),
+ h+(r.bottom-r.top)-(r2.bottom-r2.top),
+ SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+}
+
+void VideoOutput::remove_fullscreen()
+{
+ if(!is_fs) return;
+
+ SetParent(video_hwnd,oldfsparent);
+ SetWindowLong(video_hwnd,GWL_STYLE,oldfsstyle);
+ // note: when returning from fullscreen *on a secondary monitor*,
+ // be careful how you set the new window Z order.
+ // nsvplay.exe: only HWND_NOTOPMOST works
+ // nsvplayX.exe: only HWND_TOP works
+ SetWindowPos(video_hwnd, oldfsparent ? HWND_TOP : HWND_NOTOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right-oldfsrect.left, oldfsrect.bottom-oldfsrect.top, SWP_FRAMECHANGED);
+ SetFocus(oldfsparent ? oldfsparent : video_hwnd);
+
+ is_fs=0;
+ show_osd=0;
+ ctrlrects_ready=0;
+ resetSubtitle();
+
+ hideOSD();
+}
+
+int VideoOutput::is_fullscreen()
+{
+ return is_fs;
+}
+
+void VideoOutput::showStatusMsg(const char *text)
+{
+ m_statusmsg=_strdup(text);
+ InvalidateRect(video_hwnd,NULL,TRUE);
+}
+
+void VideoOutput::drawSubtitle(SubsItem *item)
+{
+ if(!item) {
+ if(curSubtitle) {
+ m_video_output->drawSubtitle(NULL);
+ curSubtitle=NULL;
+ }
+ return;
+ }
+
+ if(curSubtitle==item) return;
+
+ curSubtitle=item;
+
+ m_video_output->drawSubtitle(curSubtitle);
+}
+
+void VideoOutput::resetSubtitle()
+{
+ curSubtitle=NULL;
+ if(m_video_output) m_video_output->resetSubtitle();
+}
+
+void VideoOutput::showOSD() {
+ if(OSD_ENABLED && m_video_output) {
+ KillTimer(video_hwnd, TIMER_OSD_ID);
+ if (!show_osd)
+ m_video_output->showOSD();
+ SetTimer(video_hwnd, TIMER_OSD_ID, 2000, NULL);
+ show_osd = 1;
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ }
+}
+
+void VideoOutput::hideOSD() {
+ if(OSD_ENABLED && m_video_output) {
+ KillTimer(video_hwnd, TIMER_OSD_ID);
+ m_video_output->hideOSD();
+ show_osd = 0;
+ SetCursor(NULL);
+ }
+}
+
+void VideoOutput::drawOSD(HDC hdc, RECT *rg) {
+ if(m_video_output && show_osd) {
+
+ if (!osdMemDC ) osdMemDC = CreateCompatibleDC(hdc);
+ if (!osdFontText) osdFontText=CreateFont(OSD_TEXT_SIZE,0,0,0,FW_SEMIBOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"Arial");
+ if (!osdFontSymbol) osdFontSymbol=CreateFont(OSD_TEXT_SIZE,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,SYMBOL_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH,"Webdings");
+ if (!osdProgressBrushBg) osdProgressBrushBg = CreateSolidBrush(RGB(OSD_VOL_BKCOL_R,OSD_VOL_BKCOL_G,OSD_VOL_BKCOL_B));
+ if (!osdProgressBrushFg) osdProgressBrushFg = CreateSolidBrush(RGB(OSD_VOL_COL_R,OSD_VOL_COL_G,OSD_VOL_COL_B));
+ if (!osdBlackBrush ) osdBlackBrush = CreateSolidBrush(RGB(0,0,0));//OV_COL_R,OV_COL_G,OV_COL_B));
+ if (!osdProgressPenBg ) osdProgressPenBg = CreatePen(PS_SOLID,0,RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
+ if (!osdProgressPenFg ) osdProgressPenFg = CreatePen(PS_NULL,0,RGB(0,0,0));
+ if (!osdProgressPenBgHilite) osdProgressPenBgHilite = CreatePen(PS_SOLID,0,RGB(OSD_TEXT_R_HILITE,OSD_TEXT_G_HILITE,OSD_TEXT_B_HILITE));
+
+ COLORREF fg = GetTextColor(osdMemDC);
+ COLORREF bg = GetBkColor(osdMemDC);
+ SetTextColor(osdMemDC, RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
+ SetBkColor(osdMemDC, RGB(0,0,0));//OV_COL_R,OV_COL_G,OV_COL_B));
+
+ HGDIOBJ oldfont = SelectObject(osdMemDC, osdFontText);
+ HGDIOBJ oldbrush = SelectObject(osdMemDC, osdProgressBrushBg);
+ HGDIOBJ oldpen = SelectObject(osdMemDC, osdProgressPenBg);
+
+ RECT fullr;
+ GetClientRect(video_hwnd,&fullr);
+ ClientToScreen(video_hwnd,(LPPOINT)&fullr);
+ ClientToScreen(video_hwnd,((LPPOINT)&fullr) + 1);
+ // transform coords from windows desktop coords (where 0,0==upper-left corner of the primary monitor)
+ // to the coords for the monitor we're displaying on:
+ fullr.top -= m_video_output->m_mon_y;
+ fullr.left -= m_video_output->m_mon_x;
+ fullr.right -= m_video_output->m_mon_x;
+ fullr.bottom -= m_video_output->m_mon_y;
+
+ if (!ctrlrects_ready) {
+ ctrlrects_ready = 1;
+
+ int net_width = 0;
+ int max_height = 0;
+ int streaming = (decoder && decoder->getlen()==-1) ? 1 : 0;
+
+ for (int i=0; i<NUM_WIDGETS; i++) {
+ if (streaming && (i==CTRL_PROGRESS || i==CTRL_PROGRESSTEXT || i==CTRL_PROGRESSSPACER || i==CTRL_FFWD || i==CTRL_REW)) {
+ // disable progress bar + seek arrows when the NSV is a stream
+ ctrlrect[i].right = -1;
+ continue;
+ }
+ else if (g_ctrl_force_width[i] != 0) {
+ SetRect(&ctrlrect[i], 0, 0, g_ctrl_force_width[i], 0);
+ }
+ else {
+ SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
+ SetRect(&ctrlrect[i], 0, 0, 256, 256);
+ ctrlrect[i].bottom = DrawText(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE|DT_CALCRECT);
+ }
+ net_width += ctrlrect[i].right - ctrlrect[i].left;
+ max_height = max(max_height, ctrlrect[i].bottom - ctrlrect[i].top);
+ }
+
+ // now we know the size of all the controls; now place them.
+ int x = (fullr.right + fullr.left)/2 - net_width/2;
+ SetRect(&ctrlrect_all, 0, 0, 0, 0);
+ for (i=0; i<NUM_WIDGETS; i++)
+ {
+ if (ctrlrect[i].right >= 0) // if control is not disabled...
+ {
+ int this_width = ctrlrect[i].right - ctrlrect[i].left;
+ int this_height = ctrlrect[i].bottom - ctrlrect[i].top ;
+ if (this_height==0) this_height = max_height*2/3;// progress bars
+ ctrlrect[i].top = max_height/2 - this_height/2;
+ ctrlrect[i].bottom = max_height/2 + this_height/2;
+ ctrlrect[i].left = x;
+ ctrlrect[i].right = x + this_width;
+ if (ctrlrect_all.bottom==0) {
+ ctrlrect_all.top = ctrlrect[i].top ;
+ ctrlrect_all.bottom = ctrlrect[i].bottom;
+ }
+ else {
+ ctrlrect_all.top = min(ctrlrect_all.top , ctrlrect[i].top );
+ ctrlrect_all.bottom = max(ctrlrect_all.bottom, ctrlrect[i].bottom);
+ }
+ x += this_width;
+ }
+ }
+ }
+
+ int w = fullr.right - fullr.left;
+ int h = ctrlrect_all.bottom - ctrlrect_all.top;
+ if (!osdMemBM || osdMemBMW != w || osdMemBMH != h) {
+ if (osdMemBM) {
+ SelectObject(osdMemDC,osdOldBM);
+ DeleteObject(osdMemBM);
+ }
+ osdMemBM = CreateCompatibleBitmap(hdc,w,h);
+ osdOldBM = (HBITMAP)SelectObject(osdMemDC, osdMemBM);
+ osdMemBMW = w;
+ osdMemBMH = h;
+ }
+
+ RECT temp;
+ SetRect(&temp, 0, 0, w, h);
+ FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
+
+ for (int i=0; i<NUM_WIDGETS; i++) {
+ if (g_ctrl_type[i] == CTRLTYPE_PROGRESS)
+ {
+ int progress = 0;
+ int max_progress = ctrlrect[i].right - ctrlrect[i].left;
+ switch(i)
+ {
+ case CTRL_VOL:
+ if (decoder)
+ progress = decoder->getvolume()*max_progress/255;
+ break;
+ case CTRL_PROGRESS:
+ if (decoder)
+ {
+ int len = decoder->getlen();
+ if (len>0)
+ progress = decoder->getpos()*max_progress/len;
+ }
+ break;
+ }
+
+ SelectObject(osdMemDC, osdProgressBrushBg);
+ SelectObject(osdMemDC, (i==osdLastClickItem) ? osdProgressPenBgHilite : osdProgressPenBg);
+ RoundRect(osdMemDC, ctrlrect[i].left, ctrlrect[i].top, ctrlrect[i].right, ctrlrect[i].bottom, 3, 3);
+ SelectObject(osdMemDC, osdProgressBrushFg);
+ SelectObject(osdMemDC, osdProgressPenFg);
+ Rectangle(osdMemDC, ctrlrect[i].left+1, ctrlrect[i].top+1, ctrlrect[i].left + progress, ctrlrect[i].bottom);
+ }
+ else if (g_ctrl_type[i] == CTRLTYPE_SYMBOL ||
+ g_ctrl_type[i] == CTRLTYPE_TEXT)
+ {
+ SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
+ SetTextColor(osdMemDC, (i==osdLastClickItem) ? RGB(OSD_TEXT_R_HILITE,OSD_TEXT_G_HILITE,OSD_TEXT_B_HILITE) : RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
+ DrawText(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE);
+ }
+ }
+
+ int x0 = fullr.left;
+ int y0 = fullr.bottom - (ctrlrect_all.bottom - ctrlrect_all.top);
+ BitBlt(hdc,x0,y0,w,h,osdMemDC,0,0,SRCCOPY);
+
+ // display stream title @ the top:
+#if (SHOW_STREAM_TITLE_AT_TOP)
+ if (decoder)
+ {
+ RECT temp;
+ SetRect(&temp, 0, 0, w, h);
+ FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
+
+ SelectObject(osdMemDC, osdFontText);
+ SetTextColor(osdMemDC, RGB(OSD_TEXT_R,OSD_TEXT_G,OSD_TEXT_B));
+ char *t=decoder->getTitle();
+ char *buf=(char*)malloc(32+(t?strlen(t):0));
+
+ wsprintf(buf, "%s (%d kbps)", t?t:"", decoder->getBitrate()/1000);
+ char *p=buf;
+ while (*p)
+ {
+ if (*p == '_') *p=' ';
+ p++;
+ }
+ DrawText(osdMemDC, buf, -1, &temp, DT_SINGLELINE|DT_CENTER);
+ free(buf);
+
+ SelectObject(osdMemDC, osdFontSymbol);
+ DrawText(osdMemDC, "2r", -1, &temp, DT_SINGLELINE|DT_RIGHT);
+
+ int x0 = fullr.left;
+ int y0 = fullr.top;
+ BitBlt(hdc,x0,y0,w,h,osdMemDC,0,0,SRCCOPY);
+ }
+
+ SelectObject(osdMemDC, oldpen);
+ SelectObject(osdMemDC, oldbrush);
+ SelectObject(osdMemDC, oldfont);
+ SetTextColor(osdMemDC, fg);
+ SetBkColor(osdMemDC, bg);
+ }
+#endif
+
+}
+
+void VideoOutput::osdHitTest(int x, int y, int dragging)
+{
+ // dragging == -1: just a mousemove (no clicking)
+ // dragging == 0: user clicked
+ // dragging == 1: user clicked before, and is now dragging/moving mouse
+
+ if (dragging<1)
+ osdLastClickItem = -1;
+
+ // transform (x,y) from screen coords into coords relative to the memDC
+ y = y - ((lastfsrect.bottom - lastfsrect.top) - (ctrlrect_all.bottom - ctrlrect_all.top));
+
+ int i0 = 0;
+ int i1 = NUM_WIDGETS;
+ if (dragging==1) {
+ i0 = osdLastClickItem;
+ i1 = osdLastClickItem+1;
+ }
+
+ for (int i=i0; i<i1; i++)
+ {
+ if (dragging==1 || (x >= ctrlrect[i].left && x <= ctrlrect[i].right && y >= ctrlrect[i].top && y <= ctrlrect[i].bottom))
+ {
+ float t = (x - ctrlrect[i].left) / (float)(ctrlrect[i].right - ctrlrect[i].left);
+ if (t<0) t=0;
+ if (t>1) t=1;
+ if (dragging<1)
+ osdLastClickItem = i;
+
+ switch(i)
+ {
+ case CTRL_VOL:
+ if (decoder && dragging>=0) decoder->setvolume((int)(t*255));
+ return;
+ case CTRL_PROGRESS:
+ if (decoder && dragging>=0)
+ {
+ int len = decoder->getlen();
+ if (len > 0)
+ decoder->seek((int)(t*len));
+ }
+ return;
+ case CTRL_PAUSE:
+ if (decoder && dragging>=0) decoder->pause(1);
+ return;
+ case CTRL_PLAY:
+ if (decoder && dragging>=0) decoder->pause(0);
+ return;
+ case CTRL_STOP:
+ if (decoder && dragging>=0) {
+ decoder->pause(1);
+ remove_fullscreen();
+ }
+ return;
+ case CTRL_REW:
+ case CTRL_FFWD:
+ if (decoder && dragging>=0)
+ {
+ int pos = decoder->getpos();
+ int len = decoder->getlen();
+ if (len > 0)
+ {
+ if (i==CTRL_REW)
+ pos = max(0, pos-15000); // milliseconds to rewind
+ else
+ pos = min(len, pos+30000); // milliseconds to skip ahead
+ decoder->seek(pos);
+ }
+ }
+ return;
+ default:
+ if (dragging<1)
+ osdLastClickItem = -1;
+ break;
+ }
+ }
+ }
+
+ if (dragging==0)
+ remove_fullscreen();
+}