This source file includes following definitions.
- pixelformat_yuv
- get_win_4CC
- DD_ClearBackBuffer
- CreateBackBuffer
- InitDirectDraw
- DD_LockSurface
- DD_UnlockSurface
- DD_LockBackBuffer
- LockOSContext
- DD_BlitSurface
- DD_GetSurface
- DD_Blit
- is_yuv_supported
- is_yuv_planar
- DD_InitYUV
- DD_SetBackBufferSize
- DD_SetupDDraw
#include "dx_hw.h"
#define DDCONTEXT DDContext *dd = (DDContext *)dr->opaque;
#define DDBACK DDSurface *pBack = (DDSurface *) gf_list_get(dd->surfaces, 0);
static Bool pixelformat_yuv(u32 pixel_format)
{
switch (pixel_format) {
case GF_PIXEL_YUY2:
case GF_PIXEL_YVYU:
case GF_PIXEL_UYVY:
case GF_PIXEL_VYUY:
case GF_PIXEL_Y422:
case GF_PIXEL_UYNV:
case GF_PIXEL_YUNV:
case GF_PIXEL_V422:
case GF_PIXEL_YV12:
case GF_PIXEL_IYUV:
case GF_PIXEL_I420:
case GF_PIXEL_YV12_10:
case GF_PIXEL_YUV444:
case GF_PIXEL_YUV444_10:
case GF_PIXEL_YUV422_10:
case GF_PIXEL_YUV422:
return GF_TRUE;
default:
return GF_FALSE;
}
}
static u32 get_win_4CC(u32 pixel_format)
{
switch (pixel_format) {
case GF_PIXEL_YUY2:
return mmioFOURCC('Y', 'U', 'Y', '2');
case GF_PIXEL_YVYU:
return mmioFOURCC('Y', 'V', 'Y', 'U');
case GF_PIXEL_UYVY:
return mmioFOURCC('U', 'Y', 'V', 'Y');
case GF_PIXEL_VYUY:
return mmioFOURCC('V', 'Y', 'U', 'Y');
case GF_PIXEL_Y422:
return mmioFOURCC('Y', '4', '2', '2');
case GF_PIXEL_UYNV:
return mmioFOURCC('U', 'Y', 'N', 'V');
case GF_PIXEL_YUNV:
return mmioFOURCC('Y', 'U', 'N', 'V');
case GF_PIXEL_V422:
return mmioFOURCC('V', '4', '2', '2');
case GF_PIXEL_YV12:
return mmioFOURCC('Y', 'V', '1', '2');
case GF_PIXEL_IYUV:
return mmioFOURCC('I', 'Y', 'U', 'V');
case GF_PIXEL_I420:
return mmioFOURCC('I', '4', '2', '0');
case GF_PIXEL_YV12_10:
return mmioFOURCC('P', '0', '1', '0');
case GF_PIXEL_YUV444:
return mmioFOURCC('Y', '4', '4', '4');
case GF_PIXEL_YUV444_10:
return mmioFOURCC('Y', '4', '1', '0');
case GF_PIXEL_YUV422_10:
return mmioFOURCC('Y', '2', '1', '0');
case GF_PIXEL_YUV422:
return mmioFOURCC('Y', '4', '4', '2');
default:
return 0;
}
}
static GF_Err DD_ClearBackBuffer(GF_VideoOutput *dr, u32 color)
{
HRESULT hr;
RECT rc;
DDBLTFX ddbltfx;
DDCONTEXT;
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
ddbltfx.dwSize = sizeof(ddbltfx);
switch (dd->pixelFormat) {
case GF_PIXEL_RGB_565:
ddbltfx.dwFillColor = GF_COL_TO_565(color);
break;
case GF_PIXEL_RGB_555:
ddbltfx.dwFillColor = GF_COL_TO_555(color);
break;
default:
ddbltfx.dwFillColor = color;
break;
}
rc.left = rc.top = 0;
rc.right = dd->width;
rc.bottom = dd->height;
hr = dd->pBack->lpVtbl->Blt(dd->pBack, &rc, NULL, NULL, DDBLT_COLORFILL, &ddbltfx);
return FAILED(hr) ? GF_IO_ERR : GF_OK;
}
GF_Err CreateBackBuffer(GF_VideoOutput *dr, u32 Width, u32 Height, Bool use_system_memory)
{
Bool force_reinit;
HRESULT hr;
const char *opt;
DDSURFDESC ddsd;
DDCONTEXT;
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "HardwareMemory");
if (opt) {
if (use_system_memory) {
if (!strcmp(opt, "Always")) use_system_memory = GF_FALSE;
} else {
if (!strcmp(opt, "Never")) use_system_memory = GF_TRUE;
else if (!strcmp(opt, "Auto")) dd->force_video_mem_for_yuv = GF_TRUE;
}
}
force_reinit = GF_FALSE;
if (use_system_memory && !dd->systems_memory) force_reinit = GF_TRUE;
else if (!use_system_memory && dd->systems_memory) force_reinit = GF_TRUE;
if (dd->pBack && !force_reinit&& !dd->fullscreen && (dd->width == Width) && (dd->height == Height) ) {
return GF_OK;
}
SAFE_DD_RELEASE(dd->pBack);
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if (dd->systems_memory==2) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
} else {
if (!use_system_memory) {
dd->systems_memory = GF_FALSE;
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
} else {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
dd->systems_memory = GF_TRUE;
}
}
if (dd->systems_memory) dr->hw_caps &= ~GF_VIDEO_HW_HAS_RGB;
else dr->hw_caps |= GF_VIDEO_HW_HAS_RGB;
ddsd.dwWidth = Width;
ddsd.dwHeight = Height;
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &dd->pBack, NULL );
if (FAILED(hr)) {
if (!dd->systems_memory) {
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
dd->systems_memory = 2;
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[DX Out] Hardware Video not available for backbuffer)\n"));
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &dd->pBack, NULL );
}
if (FAILED(hr)) return GF_IO_ERR;
}
if (!dd->fullscreen) {
dd->width = Width;
dd->height = Height;
}
DD_ClearBackBuffer(dr, 0xFF000000);
if (!dd->yuv_init) DD_InitYUV(dr);
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[DX Out] BackBuffer %d x %d created on %s memory\n", Width, Height, dd->systems_memory ? "System" : "Video"));
return GF_OK;
}
GF_Err InitDirectDraw(GF_VideoOutput *dr, u32 Width, u32 Height)
{
HRESULT hr;
DWORD cooplev;
LPDIRECTDRAW ddraw;
DDSURFDESC ddsd;
DDPIXELFORMAT pixelFmt;
LPDIRECTDRAWCLIPPER pcClipper;
DDCONTEXT;
if (!dd->cur_hwnd || !Width || !Height || !dd->DirectDrawCreate) return GF_BAD_PARAM;
DestroyObjects(dd);
if( FAILED( hr = dd->DirectDrawCreate(NULL, &ddraw, NULL ) ) )
return GF_IO_ERR;
hr = ddraw->lpVtbl->QueryInterface(ddraw, &IID_IDirectDraw7, (LPVOID *)&dd->pDD);
ddraw->lpVtbl->Release(ddraw);
if (FAILED(hr)) return GF_IO_ERR;
dd->switch_res = GF_FALSE;
cooplev = DDSCL_NORMAL;
if (dd->fullscreen) {
if (dd->switch_res) {
#ifdef USE_DX_3
hr = dd->pDD->lpVtbl->SetDisplayMode(dd->pDD, dd->fs_width, dd->fs_height, dd->video_bpp);
#else
hr = dd->pDD->lpVtbl->SetDisplayMode(dd->pDD, dd->fs_width, dd->fs_height, dd->video_bpp, 0, 0 );
#endif
if( FAILED(hr)) return GF_IO_ERR;
}
dd->NeedRestore = 1;
}
hr = dd->pDD->lpVtbl->SetCooperativeLevel(dd->pDD, dd->cur_hwnd, cooplev);
if( FAILED(hr) ) return GF_IO_ERR;
ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &dd->pPrimary, NULL);
if( FAILED(hr) ) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DX Out] Failed creating primary surface: error %08x\n", hr));
return GF_IO_ERR;
}
memset (&pixelFmt, 0, sizeof(pixelFmt));
pixelFmt.dwSize = sizeof(pixelFmt);
hr = dd->pPrimary->lpVtbl->GetPixelFormat(dd->pPrimary, &pixelFmt);
if( FAILED(hr) ) return GF_IO_ERR;
switch(pixelFmt.dwRGBBitCount) {
case 16:
if ((pixelFmt.dwRBitMask == 0xf800) && (pixelFmt.dwGBitMask == 0x07e0) && (pixelFmt.dwBBitMask == 0x001f))
dd->pixelFormat = GF_PIXEL_RGB_565;
else if ((pixelFmt.dwRBitMask == 0x7c00) && (pixelFmt.dwGBitMask == 0x03e0) && (pixelFmt.dwBBitMask == 0x001f))
dd->pixelFormat = GF_PIXEL_RGB_555;
else
return GF_NOT_SUPPORTED;
dd->video_bpp = 16;
break;
case 24:
if ((pixelFmt.dwRBitMask == 0x0000FF) && (pixelFmt.dwGBitMask == 0x00FF00) && (pixelFmt.dwBBitMask == 0xFF0000))
dd->pixelFormat = GF_PIXEL_BGR_24;
else if ((pixelFmt.dwRBitMask == 0xFF0000) && (pixelFmt.dwGBitMask == 0x00FF00) && (pixelFmt.dwBBitMask == 0x0000FF))
dd->pixelFormat = GF_PIXEL_RGB_24;
dd->video_bpp = 24;
break;
case 32:
if ((pixelFmt.dwRBitMask == 0x0000FF) && (pixelFmt.dwGBitMask == 0x00FF00) && (pixelFmt.dwBBitMask == 0xFF0000)) {
dd->pixelFormat = dd->force_alpha ? GF_PIXEL_RGBA : GF_PIXEL_BGR_32;
} else if ((pixelFmt.dwRBitMask == 0xFF0000) && (pixelFmt.dwGBitMask == 0x00FF00) && (pixelFmt.dwBBitMask == 0x0000FF)) {
dd->pixelFormat = dd->force_alpha ? GF_PIXEL_ARGB : GF_PIXEL_RGB_32;
}
dd->video_bpp = 32;
break;
default:
return GF_IO_ERR;
}
hr = dd->pDD->lpVtbl->CreateClipper(dd->pDD, 0, &pcClipper, NULL);
if( FAILED(hr))
return GF_IO_ERR;
hr = pcClipper->lpVtbl->SetHWnd(pcClipper, 0, dd->cur_hwnd);
if( FAILED(hr) ) {
pcClipper->lpVtbl->Release(pcClipper);
return GF_IO_ERR;
}
hr = dd->pPrimary->lpVtbl->SetClipper(dd->pPrimary, pcClipper);
if( FAILED(hr)) {
pcClipper->lpVtbl->Release(pcClipper);
return GF_IO_ERR;
}
pcClipper->lpVtbl->Release(pcClipper);
dd->ddraw_init = GF_TRUE;
return GF_OK;
}
static GF_Err DD_LockSurface(DDContext *dd, GF_VideoSurface *vi, LPDDRAWSURFACE surface)
{
HRESULT hr;
DDSURFDESC desc;
if (!dd || !vi || !surface) return GF_BAD_PARAM;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(DDSURFACEDESC);
hr = surface->lpVtbl->Lock(surface, NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
if (FAILED(hr))
return GF_IO_ERR;
vi->video_buffer = (char*)desc.lpSurface;
vi->width = desc.dwWidth;
vi->height = desc.dwHeight;
vi->pitch_x = 0;
vi->pitch_y = desc.lPitch;
vi->is_hardware_memory = dd->systems_memory ? GF_FALSE : GF_TRUE;
return GF_OK;
}
static GF_Err DD_UnlockSurface(DDContext *dd, LPDDRAWSURFACE surface)
{
HRESULT hr;
if (!dd || !dd->ddraw_init) return GF_IO_ERR;
hr = surface->lpVtbl->Unlock(surface, NULL);
return FAILED(hr) ? GF_IO_ERR : GF_OK;
}
static GF_Err DD_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *vi, Bool do_lock)
{
DDCONTEXT;
if (do_lock) {
memset(vi, 0, sizeof(GF_VideoSurface));
vi->pixel_format = dd->pixelFormat;
return DD_LockSurface(dd, vi, dd->pBack);
}
else return DD_UnlockSurface(dd, dd->pBack);
}
static void *LockOSContext(GF_VideoOutput *dr, Bool do_lock)
{
DDCONTEXT;
if (!dd->pBack) return NULL;
if (do_lock) {
if (!dd->lock_hdc && ! dd->pBack->lpVtbl->IsLost(dd->pBack)) {
if (FAILED(dd->pBack->lpVtbl->GetDC(dd->pBack, &dd->lock_hdc)) )
dd->lock_hdc = NULL;
}
} else if (dd->lock_hdc) {
dd->pBack->lpVtbl->ReleaseDC(dd->pBack, dd->lock_hdc);
dd->lock_hdc = NULL;
}
return (void *)dd->lock_hdc ;
}
static GF_Err DD_BlitSurface(DDContext *dd, DDSurface *src, GF_Window *src_wnd, GF_Window *dst_wnd, GF_ColorKey *key)
{
HRESULT hr;
u32 dst_w, dst_h, src_w, src_h, flags;
RECT r_dst, r_src;
u32 left, top;
src_w = src_wnd ? src_wnd->w : src->width;
src_h = src_wnd ? src_wnd->h : src->height;
dst_w = dst_wnd ? dst_wnd->w : dd->width;
dst_h = dst_wnd ? dst_wnd->h : dd->height;
if (src_wnd != NULL) MAKERECT(r_src, src_wnd);
if (dst_wnd != NULL) MAKERECT(r_dst, dst_wnd);
if (key) {
u32 col;
DDCOLORKEY ck;
col = GF_COL_ARGB(0xFF, key->r, key->g, key->b);
ck.dwColorSpaceHighValue = ck.dwColorSpaceLowValue = col;
hr = src->pSurface->lpVtbl->SetColorKey(src->pSurface, DDCKEY_SRCBLT, &ck);
if (FAILED(hr))
return GF_IO_ERR;
}
if ((dst_w==src_w) && (dst_h==src_h)) {
flags = DDBLTFAST_WAIT;
if (key) flags |= DDBLTFAST_SRCCOLORKEY;
if (dst_wnd) {
left = r_dst.left;
top = r_dst.top;
}
else left = top = 0;
hr = dd->pBack->lpVtbl->BltFast(dd->pBack, left, top, src->pSurface, src_wnd ? &r_src : NULL, flags);
} else {
flags = DDBLT_WAIT;
if (key) flags |= DDBLT_KEYSRC;
hr = dd->pBack->lpVtbl->Blt(dd->pBack, dst_wnd ? &r_dst : NULL, src->pSurface, src_wnd ? &r_src : NULL, flags, NULL);
}
if (src->is_yuv && dd->force_video_mem_for_yuv && dd->systems_memory) return GF_IO_ERR;
#ifndef GPAC_DISABLE_LOG
if (hr) {
GF_LOG(dd->systems_memory ? GF_LOG_INFO : GF_LOG_ERROR, GF_LOG_MMIO, ("[DX Out] Failed blitting %s %s memory: error %08x\n", src->is_yuv ? "YUV" : "RGB", dd->systems_memory ? "systems" : "hardware", hr));
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[DX Out] %s blit %s memory %dx%d -> %dx%d\n", src->is_yuv ? "YUV" : "RGB", dd->systems_memory ? "systems" : "hardware", src_w, src_h, dst_w, dst_h));
}
#endif
return FAILED(hr) ? GF_IO_ERR : GF_OK;
}
static DDSurface *DD_GetSurface(GF_VideoOutput *dr, u32 width, u32 height, u32 pixel_format, Bool check_caps)
{
DDSURFDESC ddsd;
HRESULT hr;
DDCONTEXT;
if (!dd->pDD) return NULL;
if (pixelformat_yuv(pixel_format)) {
while (width%2) width++;
while (height%2) height++;
if (dr->yuv_pixel_format) {
DDSurface *yuvp = &dd->yuv_pool;
if (yuvp->pSurface && (yuvp->width >= width) && (yuvp->height >= height) ) return yuvp;
width = MAX(yuvp->width, width);
height = MAX(yuvp->height, height);
SAFE_DD_RELEASE(yuvp->pSurface);
memset(yuvp, 0, sizeof(DDSurface));
yuvp->is_yuv = GF_TRUE;
memset (&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
if (!dd->offscreen_yuv_to_rgb && (dr->hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY))
ddsd.ddsCaps.dwCaps |= DDSCAPS_OVERLAY;
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddpfPixelFormat.dwFourCC = get_win_4CC(dr->yuv_pixel_format);
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &yuvp->pSurface, NULL);
if (FAILED(hr) ) {
if (!check_caps) return NULL;
if (dd->offscreen_yuv_to_rgb) {
dd->offscreen_yuv_to_rgb = GF_FALSE;
if (dr->hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_OVERLAY;
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &yuvp->pSurface, NULL);
if( FAILED(hr) ) {
return NULL;
}
} else {
return NULL;
}
}
if (dr->hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) {
dr->hw_caps &= ~GF_VIDEO_HW_HAS_YUV_OVERLAY;
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &yuvp->pSurface, NULL);
if( FAILED(hr) ) {
return NULL;
}
}
else {
return NULL;
}
}
yuvp->format = dr->yuv_pixel_format;
yuvp->width = width;
yuvp->height = height;
return yuvp;
}
}
if ((dd->rgb_pool.width >= width) && (dd->rgb_pool.height >= height) ) return &dd->rgb_pool;
width = MAX(dd->rgb_pool.width, width);
height = MAX(dd->rgb_pool.height, height);
SAFE_DD_RELEASE(dd->rgb_pool.pSurface);
memset(&dd->rgb_pool, 0, sizeof(DDSurface));
memset (&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
hr = dd->pDD->lpVtbl->CreateSurface(dd->pDD, &ddsd, &dd->rgb_pool.pSurface, NULL);
if (FAILED(hr))
return NULL;
dd->rgb_pool.width = width;
dd->rgb_pool.height = height;
dd->rgb_pool.format = dd->pixelFormat;
return &dd->rgb_pool;
}
static GF_Err DD_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type)
{
GF_VideoSurface temp_surf;
GF_Err e;
GF_Window src_wnd_2;
u32 w, h;
DDSurface *pool;
DDCONTEXT;
if (!video_src) {
if (overlay_type && dd->yuv_pool.pSurface)
dd->yuv_pool.pSurface->lpVtbl->UpdateOverlay(dd->yuv_pool.pSurface, NULL, dd->pPrimary, NULL, DDOVER_HIDE, NULL);
return GF_OK;
}
if (src_wnd) {
w = src_wnd->w;
h = src_wnd->h;
} else {
w = video_src->width;
h = video_src->height;
}
if (video_src->pixel_format==GF_PIXEL_YUVD) video_src->pixel_format=GF_PIXEL_YV12;
pool = DD_GetSurface(dr, w, h, video_src->pixel_format, GF_FALSE);
if (!pool)
return GF_IO_ERR;
memset(&temp_surf, 0, sizeof(GF_VideoSurface));
temp_surf.pixel_format = pool->format;
e = DD_LockSurface(dd, &temp_surf, pool->pSurface);
if (e) return e;
dx_copy_pixels(&temp_surf, video_src, src_wnd);
e = DD_UnlockSurface(dd, pool->pSurface);
if (e) return e;
if (overlay_type) {
HRESULT hr;
RECT dst_rc, src_rc;
POINT pt;
GF_Window dst = *dst_wnd;
GF_Window src = *src_wnd;
src.x = src.y = 0;
MAKERECT(src_rc, (&src));
pt.x = dst.x;
pt.y = dst.y;
ClientToScreen(dd->cur_hwnd, &pt);
dst.x = pt.x;
dst.y = pt.y;
MAKERECT(dst_rc, (&dst));
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[DX] Blit surface to dest %d x %d - overlay type %s\n", dst.w, dst.h,
(overlay_type==0)? "none" : ((overlay_type==1) ? "Top-Level" : "ColorKey")
));
#if 1
if (overlay_type==1) {
hr = pool->pSurface->lpVtbl->UpdateOverlay(pool->pSurface, &src_rc, dd->pPrimary, &dst_rc, DDOVER_SHOW | DDOVER_AUTOFLIP, NULL);
} else {
DDOVERLAYFX ddofx;
memset(&ddofx, 0, sizeof(DDOVERLAYFX));
ddofx.dwSize = sizeof(DDOVERLAYFX);
ddofx.dckDestColorkey.dwColorSpaceLowValue = dr->overlay_color_key;
ddofx.dckDestColorkey.dwColorSpaceHighValue = dr->overlay_color_key;
hr = pool->pSurface->lpVtbl->UpdateOverlay(pool->pSurface, &src_rc, dd->pPrimary, &dst_rc, DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE | DDOVER_AUTOFLIP, &ddofx);
}
if (FAILED(hr)) {
pool->pSurface->lpVtbl->UpdateOverlay(pool->pSurface, NULL, dd->pPrimary, NULL, DDOVER_HIDE, NULL);
}
#else
if (overlay_type==1) {
hr = dd->pPrimary->lpVtbl->Blt(dd->pPrimary, &dst_rc, pool->pSurface, &src_rc, 0, NULL);
} else {
DDBLTFX ddfx;
memset(&ddfx, 0, sizeof(DDBLTFX));
ddfx.dwSize = sizeof(DDBLTFX);
ddfx.ddckDestColorkey.dwColorSpaceLowValue = dr->overlay_color_key;
ddfx.ddckDestColorkey.dwColorSpaceHighValue = dr->overlay_color_key;
hr = dd->pPrimary->lpVtbl->Blt(dd->pPrimary, &dst_rc, pool->pSurface, &src_rc, DDBLT_WAIT | DDBLT_KEYDESTOVERRIDE, &ddfx);
}
#endif
return FAILED(hr) ? GF_IO_ERR : GF_OK;
}
src_wnd_2.x = src_wnd_2.y = 0;
if (src_wnd) {
src_wnd_2.w = src_wnd->w;
src_wnd_2.h = src_wnd->h;
} else {
src_wnd_2.w = video_src->width;
src_wnd_2.h = video_src->height;
}
return DD_BlitSurface(dd, pool, &src_wnd_2, dst_wnd, NULL);
}
static GFINLINE u32 is_yuv_supported(u32 win_4cc)
{
if (win_4cc==get_win_4CC(GF_PIXEL_YV12)) return GF_PIXEL_YV12;
else if (win_4cc==get_win_4CC(GF_PIXEL_I420)) return GF_PIXEL_I420;
else if (win_4cc==get_win_4CC(GF_PIXEL_IYUV)) return GF_PIXEL_IYUV;
else if (win_4cc==get_win_4CC(GF_PIXEL_UYVY)) return GF_PIXEL_UYVY;
else if (win_4cc==get_win_4CC(GF_PIXEL_Y422)) return GF_PIXEL_Y422;
else if (win_4cc==get_win_4CC(GF_PIXEL_UYNV)) return GF_PIXEL_UYNV;
else if (win_4cc==get_win_4CC(GF_PIXEL_YUY2)) return GF_PIXEL_YUY2;
else if (win_4cc==get_win_4CC(GF_PIXEL_YUNV)) return GF_PIXEL_YUNV;
else if (win_4cc==get_win_4CC(GF_PIXEL_V422)) return GF_PIXEL_V422;
else if (win_4cc==get_win_4CC(GF_PIXEL_YVYU)) return GF_PIXEL_YVYU;
else return 0;
}
static GFINLINE Bool is_yuv_planar(u32 format)
{
switch (format) {
case GF_PIXEL_YV12:
case GF_PIXEL_I420:
case GF_PIXEL_IYUV:
return GF_TRUE;
default:
return GF_FALSE;
}
}
#define YUV_NUM_TEST 20
void DD_InitYUV(GF_VideoOutput *dr)
{
u32 w, h, j, i, num_yuv;
Bool force_yv12 = GF_FALSE;
DWORD numCodes;
DWORD formats[30];
DWORD *codes;
u32 now, min_packed = 0xFFFFFFFF, min_planar = 0xFFFFFFFF;
u32 best_packed = 0, best_planar = 0;
Bool checkPacked = TRUE;
const char *opt;
DDCONTEXT;
w = 720;
h = 576;
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "PreferedYUV4CC");
if (opt) {
char a, b, c, d;
if (sscanf(opt, "%c%c%c%c", &a, &b, &c, &d)==4) {
dr->yuv_pixel_format = GF_4CC(a, b, c, d);
dr->hw_caps |= GF_VIDEO_HW_HAS_YUV;
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "HasOverlay");
if (opt && !strcmp(opt, "yes"))
dr->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY;
dd->yuv_init = GF_TRUE;
num_yuv = 1;
}
}
if (! dd->yuv_init) {
char szOpt[100];
dd->yuv_init = GF_TRUE;
dr->hw_caps |= GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_YUV_OVERLAY;
dd->pDD->lpVtbl->GetFourCCCodes(dd->pDD, &numCodes, NULL);
if (!numCodes) return;
codes = (DWORD *)gf_malloc(numCodes*sizeof(DWORD));
dd->pDD->lpVtbl->GetFourCCCodes(dd->pDD, &numCodes, codes);
num_yuv = 0;
for (i=0; i<numCodes; i++) {
formats[num_yuv] = is_yuv_supported(codes[i]);
if (formats[num_yuv]) num_yuv++;
}
gf_free(codes);
if (!num_yuv) {
dr->hw_caps &= ~(GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_YUV_OVERLAY);
dr->yuv_pixel_format = 0;
return;
}
for (i=0; i<num_yuv; i++) {
if (!checkPacked && !is_yuv_planar(formats[i])) goto go_on;
if (checkPacked && is_yuv_planar(formats[i])) goto go_on;
if (dd->yuv_pool.pSurface) {
SAFE_DD_RELEASE(dd->yuv_pool.pSurface);
memset(&dd->yuv_pool, 0, sizeof(DDSurface));
dd->yuv_pool.is_yuv = GF_TRUE;
}
dr->yuv_pixel_format = formats[i];
if (DD_GetSurface(dr, w, h, dr->yuv_pixel_format, GF_TRUE) == NULL)
goto rem_fmt;
now = gf_sys_clock();
for (j=0; j<YUV_NUM_TEST; j++) {
if (DD_BlitSurface(dd, &dd->yuv_pool, NULL, NULL, NULL) != GF_OK)
goto rem_fmt;
}
now = gf_sys_clock() - now;
if (formats[i]== GF_PIXEL_YV12)
force_yv12 = GF_TRUE;
if (!checkPacked) {
if (now<min_planar) {
min_planar = now;
best_planar = dr->yuv_pixel_format;
}
} else {
if (now<min_packed) {
min_packed = now;
best_packed = dr->yuv_pixel_format;
}
}
go_on:
if (checkPacked && (i+1==num_yuv)) {
i = -1;
checkPacked = FALSE;
}
continue;
rem_fmt:
for (j=i; j<num_yuv-1; j++) {
formats[j] = formats[j+1];
}
i--;
num_yuv--;
}
if (dd->yuv_pool.pSurface) {
SAFE_DD_RELEASE(dd->yuv_pool.pSurface);
memset(&dd->yuv_pool, 0, sizeof(DDSurface));
dd->yuv_pool.is_yuv = GF_TRUE;
}
if (best_planar && (min_planar <= min_packed )) {
dr->yuv_pixel_format = best_planar;
} else {
min_planar = min_packed;
dr->yuv_pixel_format = best_packed;
}
if (force_yv12)
dr->yuv_pixel_format = GF_PIXEL_YV12;
sprintf(szOpt, "%c%c%c%c", (dr->yuv_pixel_format>>24) & 0xFF, (dr->yuv_pixel_format>>16) & 0xFF, (dr->yuv_pixel_format>>8) & 0xFF, (dr->yuv_pixel_format) & 0xFF);
gf_modules_set_option((GF_BaseInterface *)dr, "Video", "PreferedYUV4CC", szOpt);
gf_modules_set_option((GF_BaseInterface *)dr, "Video", "HasOverlay", (dr->hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) ? "yes" : "no");
}
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "HardwareMemory");
if (opt && !strcmp(opt, "Never")) num_yuv = 0;
if (!num_yuv) {
dr->hw_caps &= ~(GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_YUV_OVERLAY);
dr->yuv_pixel_format = 0;
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[DX Out] YUV hardware not available\n"));
return;
}
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[DX Out] Picked YUV format %s - drawn in %d ms\n", gf_4cc_to_str(dr->yuv_pixel_format), min_planar));
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "EnableOffscreenYUV");
if (!opt) {
opt = "yes";
gf_modules_set_option((GF_BaseInterface *)dr, "Video", "EnableOffscreenYUV", "yes");
}
if (opt && strcmp(opt, "yes")) dr->hw_caps &= ~GF_VIDEO_HW_HAS_YUV;
else dd->offscreen_yuv_to_rgb = GF_TRUE;
opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "OverlayColorKey");
if (!opt) {
opt = "0101FE";
gf_modules_set_option((GF_BaseInterface *)dr, "Video", "OverlayColorKey", "0101FE");
}
sscanf(opt, "%06x", &dr->overlay_color_key);
if (dr->overlay_color_key) dr->overlay_color_key |= 0xFF000000;
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[DX Out] YUV->RGB enabled: %s - ColorKey enabled: %s (key %x)\n",
(dr->hw_caps & GF_VIDEO_HW_HAS_YUV) ? "Yes" : "No",
dr->overlay_color_key ? "Yes" : "No", dr->overlay_color_key
));
}
GF_Err DD_SetBackBufferSize(GF_VideoOutput *dr, u32 width, u32 height, Bool use_system_memory)
{
GF_Err e;
DDCONTEXT;
#ifndef GPAC_DISABLE_3D
if (dd->output_3d_type) return GF_BAD_PARAM;
#endif
if (!dd->ddraw_init) {
e = InitDirectDraw(dr, width, height);
if (e) return e;
}
return CreateBackBuffer(dr, width, height, use_system_memory);
}
void DD_SetupDDraw(GF_VideoOutput *driv)
{
driv->hw_caps |= GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_STRETCH;
driv->Blit = DD_Blit;
driv->LockBackBuffer = DD_LockBackBuffer;
driv->LockOSContext = LockOSContext;
}