#include #include #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; icreate(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= 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; igetvolume()*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= 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(); }