📄 vo_directx.c
字号:
if( user32dll ) { myGetMonitorInfo = GetProcAddress(user32dll,"GetMonitorInfoA"); if( !myGetMonitorInfo && vo_adapter_num ) { vo_adapter_num = 0; } } hddraw_dll = LoadLibrary("DDRAW.DLL"); if ( hddraw_dll == NULL ) { av_log(NULL, AV_LOG_ERROR, "vo_directx: failed loading ddraw.dll\n" ); return -1; } last_rect.left = 0xDEADC0DE; // reset window position cache if(vo_adapter_num) //display other than default { OurDirectDrawEnumerateEx = (LPDIRECTDRAWENUMERATEEX) GetProcAddress(hddraw_dll,"DirectDrawEnumerateExA"); if (!OurDirectDrawEnumerateEx) { FreeLibrary( hddraw_dll ); hddraw_dll = NULL; av_log(NULL, AV_LOG_ERROR, "vo_directx: address: DirectDrawEnumerateEx\n"); av_log(NULL, AV_LOG_ERROR, "vo_directx: no directx 7 or higher installed\n"); return -1; } // enumerate all display devices attached to the desktop OurDirectDrawEnumerateEx(EnumCallbackEx, NULL, DDENUM_ATTACHEDSECONDARYDEVICES ); } FreeLibrary(user32dll); OurDirectDrawCreateEx = (void *)GetProcAddress(hddraw_dll, "DirectDrawCreateEx"); if ( OurDirectDrawCreateEx == NULL ) { FreeLibrary( hddraw_dll ); hddraw_dll = NULL; av_log(NULL, AV_LOG_ERROR, "vo_directx: DirectDrawCreateEx not found\n"); return -1; } // initialize DirectDraw and create directx v7 object if(OurDirectDrawCreateEx(selected_guid_ptr, (VOID**)&g_lpdd, &IID_IDirectDraw7, NULL ) != DD_OK ) { FreeLibrary( hddraw_dll ); hddraw_dll = NULL; av_log(NULL, AV_LOG_ERROR, "vo_directx: can't initialize ddraw\n"); return -1; } //get current screen siz for selected monitor ... ddsd.dwSize=sizeof(ddsd); ddsd.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT; g_lpdd->lpVtbl->GetDisplayMode(g_lpdd, &ddsd); vm_height=ddsd.dwHeight; vm_width=ddsd.dwWidth; vm_bpp = ddsd.ddpfPixelFormat.dwRGBBitCount; if (g_lpdd->lpVtbl->SetCooperativeLevel(g_lpdd, hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN) != DD_OK) { av_log(NULL, AV_LOG_ERROR, "vo_directx: can't set cooperativelevel for exclusive mode\n"); return -1; } /*SetDisplayMode(ddobject,width,height,bpp,refreshrate,aditionalflags)*/ if (g_lpdd->lpVtbl->SetDisplayMode(g_lpdd,vm_width, vm_height, vm_bpp,0,0) != DD_OK) { av_log(NULL, AV_LOG_ERROR, "vo_directx: can't set displaymode\n"); return 1; } return 0; if (g_lpdd->lpVtbl->SetCooperativeLevel(g_lpdd, hWnd, DDSCL_NORMAL) != DD_OK) { av_log(NULL, AV_LOG_ERROR, "vo_directx: not set cooperativelevel for hardwarecheck\n"); return 1; } av_log(NULL, AV_LOG_INFO, "DirectDraw Inited OK\n"); return 0;}static void check_events(void){ MSG msg; while (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); }}static uint32_t Directx_ManageDisplay(){ HRESULT ddrval; DDCAPS capsDrv; DDOVERLAYFX ovfx; DWORD dwUpdateFlags=0; int width,height; if( !vo_fs ) { RECT current_rect = {0, 0, 0, 0}; GetWindowRect(hWnd, ¤t_rect); if ((current_rect.left == last_rect.left) && (current_rect.top == last_rect.top) && (current_rect.right == last_rect.right) && (current_rect.bottom == last_rect.bottom)) return 0; last_rect = current_rect; } POINT pt; pt.x = 0; //overlayposition relative to the window pt.y = 0; ClientToScreen(hWnd,&pt); GetClientRect(hWnd, &rd); width=rd.right - rd.left; height=rd.bottom - rd.top; pt.x -= monitor_rect.left; /* move coordinates from global to local monitor space */ pt.y -= monitor_rect.top; rd.right -= monitor_rect.left; rd.bottom -= monitor_rect.top; rd.left = pt.x; rd.top = pt.y; if (!nooverlay && (!width || !height)) { /*window is minimized*/ ddrval = g_lpddsOverlay->lpVtbl->UpdateOverlay(g_lpddsOverlay,NULL, g_lpddsPrimary, NULL, DDOVER_HIDE, NULL); return 0; } rd.right=rd.left+width; rd.bottom=rd.top+height; /*ok, let's workaround some overlay limitations*/ if (!nooverlay) { uint32_t uStretchFactor1000; //minimum stretch uint32_t xstretch1000,ystretch1000; /*get driver capabilities*/ ZeroMemory(&capsDrv, sizeof(capsDrv)); capsDrv.dwSize = sizeof(capsDrv); if (g_lpdd->lpVtbl->GetCaps(g_lpdd,&capsDrv, NULL) != DD_OK)return 1; /*get minimum stretch, depends on display adaptor and mode (refresh rate!) */ uStretchFactor1000 = capsDrv.dwMinOverlayStretch>1000 ? capsDrv.dwMinOverlayStretch : 1000; rd.right = ((width+rd.left)*uStretchFactor1000+999)/1000; rd.bottom = (height+rd.top)*uStretchFactor1000/1000; /*calculate xstretch1000 and ystretch1000*/ xstretch1000 = ((rd.right - rd.left)* 1000)/image_width ; ystretch1000 = ((rd.bottom - rd.top)* 1000)/image_height; rs.left=0; rs.right=image_width; rs.top=0; rs.bottom=image_height; if (rd.left < 0)rs.left=(-rd.left*1000)/xstretch1000; if (rd.top < 0)rs.top=(-rd.top*1000)/ystretch1000; if (rd.right > d_image_width)rs.right=((d_image_width-rd.left)*1000)/xstretch1000; if (rd.bottom > d_image_height)rs.bottom=((d_image_height-rd.top)*1000)/ystretch1000; /*do not allow to zoom or shrink if hardware isn't able to do so*/ if ((width < image_width)&& !(capsDrv.dwFXCaps & DDFXCAPS_OVERLAYSHRINKX)) { rd.right=rd.left+image_width; } else if ((width > image_width)&& !(capsDrv.dwFXCaps & DDFXCAPS_OVERLAYSTRETCHX)) { rd.right = rd.left+image_width; } if ((height < image_height) && !(capsDrv.dwFXCaps & DDFXCAPS_OVERLAYSHRINKY)) { rd.bottom = rd.top + image_height; } else if ((height > image_height ) && !(capsDrv.dwFXCaps & DDFXCAPS_OVERLAYSTRETCHY)) { rd.bottom = rd.top + image_height; } /*the last thing to check are alignment restrictions these expressions (x & -y) just do alignment by dropping low order bits... so to round up, we add first, then truncate*/ if ((capsDrv.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && capsDrv.dwAlignBoundarySrc) rs.left = (rs.left + capsDrv.dwAlignBoundarySrc / 2) & -(signed)(capsDrv.dwAlignBoundarySrc); if ((capsDrv.dwCaps & DDCAPS_ALIGNSIZESRC) && capsDrv.dwAlignSizeSrc) rs.right = rs.left + ((rs.right - rs.left + capsDrv.dwAlignSizeSrc / 2) & -(signed) (capsDrv.dwAlignSizeSrc)); if ((capsDrv.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && capsDrv.dwAlignBoundaryDest) rd.left = (rd.left + capsDrv.dwAlignBoundaryDest / 2) & -(signed)(capsDrv.dwAlignBoundaryDest); if ((capsDrv.dwCaps & DDCAPS_ALIGNSIZEDEST) && capsDrv.dwAlignSizeDest) rd.right = rd.left + ((rd.right - rd.left) & -(signed) (capsDrv.dwAlignSizeDest)); /*create an overlay FX structure to specify a destination color key*/ ZeroMemory(&ovfx, sizeof(ovfx)); ovfx.dwSize = sizeof(ovfx); if (vo_fs) { ovfx.dckDestColorkey.dwColorSpaceLowValue = 0; ovfx.dckDestColorkey.dwColorSpaceHighValue = 0; } else { ovfx.dckDestColorkey.dwColorSpaceLowValue = destcolorkey; ovfx.dckDestColorkey.dwColorSpaceHighValue = destcolorkey; } // set the flags we'll send to UpdateOverlay //DDOVER_AUTOFLIP|DDOVERFX_MIRRORLEFTRIGHT|DDOVERFX_MIRRORUPDOWN could be useful?; dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX; /*if hardware can't do colorkeying set the window on top*/ if (capsDrv.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) dwUpdateFlags |= DDOVER_KEYDESTOVERRIDE; } else { g_lpddclipper->lpVtbl->SetHWnd(g_lpddclipper, 0,(vo_fs)?hWndFS: hWnd); } RECT rdw=rd; // printf("window: %i %i %ix%i\n",rdw.left,rdw.top,rdw.right - rdw.left,rdw.bottom - rdw.top); rdw.left += monitor_rect.left; /* move to global coordinate space */ rdw.top += monitor_rect.top; rdw.right += monitor_rect.left; rdw.bottom += monitor_rect.top; SetWindowPos(hWnd,HWND_TOPMOST,rdw.left,rdw.top,rdw.right-rdw.left,rdw.bottom-rdw.top,SWP_NOOWNERZORDER); /*make sure the overlay is inside the screen*/ if (rd.left<0)rd.left=0; if (rd.right>d_image_width)rd.right=d_image_width; if (rd.top<0)rd.top=0; if (rd.bottom>d_image_height)rd.bottom=d_image_height; /*for nonoverlay mode we are finished, for overlay mode we have to display the overlay first*/ if (nooverlay)return 0; // printf("overlay: %i %i %ix%i\n",rd.left,rd.top,rd.right - rd.left,rd.bottom - rd.top); ddrval = g_lpddsOverlay->lpVtbl->UpdateOverlay(g_lpddsOverlay,&rs, g_lpddsPrimary, &rd, dwUpdateFlags, &ovfx); if (FAILED(ddrval)) { // one cause might be the driver lied about minimum stretch // we should try upping the destination size a bit, or // perhaps shrinking the source size switch (ddrval) { case DDERR_NOSTRETCHHW: { av_log(NULL, AV_LOG_ERROR, "hardware can't stretch: try to size the window back\n"); break; } case DDERR_INVALIDRECT: { av_log(NULL, AV_LOG_ERROR, "invalid rectangle\n"); break; } case DDERR_INVALIDPARAMS: { av_log(NULL, AV_LOG_ERROR, "invalid parameters\n"); break; } case DDERR_HEIGHTALIGN: { av_log(NULL, AV_LOG_ERROR, "height align\n"); break; } case DDERR_XALIGN: { av_log(NULL, AV_LOG_ERROR, "x align\n"); break; } case DDERR_UNSUPPORTED: { av_log(NULL, AV_LOG_ERROR, "unsupported\n"); break; } case DDERR_INVALIDSURFACETYPE: { av_log(NULL, AV_LOG_ERROR, "invalid surfacetype\n"); break; } case DDERR_INVALIDOBJECT: { av_log(NULL, AV_LOG_ERROR, "invalid object\n"); break; } case DDERR_SURFACELOST: { av_log(NULL, AV_LOG_ERROR, "surfaces lost\n"); g_lpddsOverlay->lpVtbl->Restore( g_lpddsOverlay ); //restore and try again g_lpddsPrimary->lpVtbl->Restore( g_lpddsPrimary ); ddrval = g_lpddsOverlay->lpVtbl->UpdateOverlay(g_lpddsOverlay,&rs, g_lpddsPrimary, &rd, dwUpdateFlags, &ovfx); break; } default: av_log(NULL, AV_LOG_ERROR, " 0x%x\n",ddrval); } /*ok we can't do anything about it -> hide overlay*/ if (ddrval != DD_OK) { ddrval = g_lpddsOverlay->lpVtbl->UpdateOverlay(g_lpddsOverlay,NULL, g_lpddsPrimary, NULL, DDOVER_HIDE, NULL); return 1; } } return 0;}//find out supported overlay pixelformatsstatic uint32_t Directx_CheckOverlayPixelformats(){ DDCAPS capsDrv; HRESULT ddrval; DDSURFACEDESC2 ddsdOverlay; uint32_t i; uint32_t formatcount = 0; //get driver caps to determine overlay support ZeroMemory(&capsDrv, sizeof(capsDrv)); capsDrv.dwSize = sizeof(capsDrv); ddrval = g_lpdd->lpVtbl->GetCaps(g_lpdd,&capsDrv, NULL); if(FAILED(ddrval)) { av_log(NULL, AV_LOG_ERROR,"vo_directx: failed getting ddrawcaps\n"); return -1; } if (!(capsDrv.dwCaps & DDCAPS_OVERLAY)) { av_log(NULL, AV_LOG_ERROR,"vo_directx: Your card doesn't support overlay\n"); return 1; } //it is not possible to query for pixel formats supported by the //overlay hardware: try out various formats till one works ZeroMemory(&ddsdOverlay, sizeof(ddsdOverlay)); ddsdOverlay.dwSize = sizeof(ddsdOverlay); ddsdOverlay.ddsCaps.dwCaps=DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY; ddsdOverlay.dwFlags= DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH| DDSD_PIXELFORMAT; ddsdOverlay.dwWidth=300; ddsdOverlay.dwHeight=280; ddsdOverlay.dwBackBufferCount=0; //try to create an overlay surface using one of the pixel formats in our global list i=0; do { ddsdOverlay.ddpfPixelFormat=g_ddpf[i].g_ddpfOverlay; ddrval = g_lpdd->lpVtbl->CreateSurface(g_lpdd,&ddsdOverlay, &g_lpddsOverlay, NULL); if (ddrval == DD_OK) { av_log(NULL, AV_LOG_ERROR,"vo_directx: %i %s supported\n",i,g_ddpf[i].img_format_name); formatcount++; } else av_log(NULL, AV_LOG_ERROR,"vo_directx: %i %s not supported\n",i,g_ddpf[i].img_format_name); if (g_lpddsOverlay != NULL) { g_lpddsOverlay->lpVtbl->Release(g_lpddsOverlay); g_lpddsOverlay = NULL; } } while ( ++i < NUM_FORMATS ); if (formatcount == 0) { return -1; } return 0;}//find out the Pixelformat of the Primary Surfacestatic uint32_t Directx_CheckPrimaryPixelformat(){ uint32_t i=0; uint32_t formatcount = 0; DDPIXELFORMAT ddpf; DDSURFACEDESC2 ddsd; HDC hdc; HRESULT hres; COLORREF rgbT=RGB(0,0,0); memset( &ddpf, 0, sizeof( DDPIXELFORMAT )); ddpf.dwSize = sizeof( DDPIXELFORMAT ); //we have to create a primary surface first if ( Directx_CreatePrimarySurface() != 0 ) return -1; if (g_lpddsPrimary->lpVtbl->GetPixelFormat( g_lpddsPrimary, &ddpf ) != DD_OK ) { av_log(NULL, AV_LOG_ERROR,"vo_directx: can't get pixelformat\n"); return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -