00001
00002
00003 #include <map>
00004 #include <iostream>
00005 #include <algorithm>
00006 using namespace std;
00007
00008 #define _WIN32_WINNT 0x500
00009 #include "mythcontext.h"
00010 #include "videoout_d3d.h"
00011 #include "filtermanager.h"
00012 #include "fourcc.h"
00013 #include "videodisplayprofile.h"
00014 #include "libmythui/mythmainwindow.h"
00015
00016 #include "mmsystem.h"
00017 #include "tv.h"
00018
00019 #include <qapplication.h>
00020
00021 #undef UNICODE
00022
00023 extern "C" {
00024 #include "../libavcodec/avcodec.h"
00025 }
00026
00027 typedef struct
00028 {
00029 FLOAT x;
00030 FLOAT y;
00031 FLOAT z;
00032 FLOAT rhw;
00033 D3DCOLOR diffuse;
00034 FLOAT tu;
00035 FLOAT tv;
00036 } CUSTOMVERTEX;
00037
00038 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
00039
00040 const int kNumBuffers = 31;
00041 const int kNeedFreeFrames = 1;
00042 const int kPrebufferFramesNormal = 10;
00043 const int kPrebufferFramesSmall = 4;
00044 const int kKeepPrebuffer = 2;
00045
00046 #define LOC QString("VideoOutputD3D: ")
00047 #define LOC_WARN QString("VideoOutputD3D Warning: ")
00048 #define LOC_ERR QString("VideoOutputD3D Error: ")
00049
00050 VideoOutputD3D::VideoOutputD3D(void)
00051 : VideoOutput(), m_InputCX(0), m_InputCY(0),
00052 m_lock(true), m_RefreshRate(60),
00053 m_hWnd(NULL), m_hEmbedWnd(NULL),
00054 m_ddFormat(D3DFMT_UNKNOWN), m_pD3D(NULL), m_pd3dDevice(NULL),
00055 m_pSurface(NULL), m_pTexture(NULL), m_pVertexBuffer(NULL)
00056 {
00057 VERBOSE(VB_PLAYBACK, LOC + "ctor");
00058 m_pauseFrame.buf = NULL;
00059 }
00060
00061 VideoOutputD3D::~VideoOutputD3D()
00062 {
00063 Exit();
00064 }
00065
00066 void VideoOutputD3D::Exit(void)
00067 {
00068 VERBOSE(VB_PLAYBACK, LOC + "Exit()");
00069 QMutexLocker locker(&m_lock);
00070 vbuffers.DeleteBuffers();
00071 if (m_pauseFrame.buf)
00072 {
00073 delete [] m_pauseFrame.buf;
00074 m_pauseFrame.buf = NULL;
00075 }
00076 UnInitD3D();
00077 }
00078
00079 void VideoOutputD3D::UnInitD3D(void)
00080 {
00081 QMutexLocker locker(&m_lock);
00082
00083 if (m_pVertexBuffer)
00084 {
00085 m_pVertexBuffer->Release();
00086 m_pVertexBuffer = NULL;
00087 }
00088
00089 if (m_pTexture)
00090 {
00091 m_pTexture->Release();
00092 m_pTexture = NULL;
00093 }
00094
00095 if (m_pSurface)
00096 {
00097 m_pSurface->Release();
00098 m_pSurface = NULL;
00099 }
00100
00101 if (m_pd3dDevice)
00102 {
00103 m_pd3dDevice->Release();
00104 m_pd3dDevice = NULL;
00105 }
00106
00107 if (m_pD3D)
00108 {
00109 m_pD3D->Release();
00110 m_pD3D = NULL;
00111 }
00112 }
00113
00114 bool VideoOutputD3D::InputChanged(const QSize &input_size,
00115 float aspect,
00116 MythCodecID av_codec_id,
00117 void *codec_private)
00118 {
00119 QMutexLocker locker(&m_lock);
00120 VideoOutput::InputChanged(input_size, aspect, av_codec_id, codec_private);
00121 db_vdisp_profile->SetVideoRenderer("direct3d");
00122
00123 if (video_dim.width() == m_InputCX && video_dim.height() == m_InputCY)
00124 {
00125 MoveResize();
00126 return true;
00127 }
00128
00129 m_InputCX = video_dim.width();
00130 m_InputCY = video_dim.height();
00131 VERBOSE(VB_PLAYBACK, LOC + "InputChanged, x="<< m_InputCX
00132 << ", y=" << m_InputCY);
00133
00134 vbuffers.DeleteBuffers();
00135
00136 MoveResize();
00137
00138 if (!vbuffers.CreateBuffers(m_InputCX, m_InputCY))
00139 {
00140 VERBOSE(VB_IMPORTANT, LOC + "InputChanged(): "
00141 "Failed to recreate buffers");
00142 errored = true;
00143 }
00144
00145 if (!InitD3D())
00146 UnInitD3D();
00147
00148 if (m_pauseFrame.buf)
00149 {
00150 delete [] m_pauseFrame.buf;
00151 m_pauseFrame.buf = NULL;
00152 }
00153
00154 m_pauseFrame.height = vbuffers.GetScratchFrame()->height;
00155 m_pauseFrame.width = vbuffers.GetScratchFrame()->width;
00156 m_pauseFrame.bpp = vbuffers.GetScratchFrame()->bpp;
00157 m_pauseFrame.size = vbuffers.GetScratchFrame()->size;
00158 m_pauseFrame.buf = new unsigned char[m_pauseFrame.size + 128];
00159 m_pauseFrame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
00160
00161 return true;
00162 }
00163
00164 bool VideoOutputD3D::InitD3D()
00165 {
00166 VERBOSE(VB_PLAYBACK, LOC + QString("InitD3D start (x=%1, y=%2)")
00167 .arg(m_InputCX).arg(m_InputCY));
00168
00169 QMutexLocker locker(&m_lock);
00170 D3DCAPS9 d3dCaps;
00171
00172 typedef LPDIRECT3D9 (WINAPI *LPFND3DC)(UINT SDKVersion);
00173 static LPFND3DC OurDirect3DCreate9 = NULL;
00174 static HINSTANCE hD3DLib = NULL;
00175
00176 if (!hD3DLib)
00177 {
00178 hD3DLib = LoadLibrary(TEXT("D3D9.DLL"));
00179 if (!hD3DLib)
00180 {
00181 VERBOSE(VB_IMPORTANT, LOC_ERR + "Cannot load d3d9.dll (Direct3D)");
00182 return false;
00183 }
00184 }
00185
00186 if (!OurDirect3DCreate9)
00187 {
00188 OurDirect3DCreate9 = (LPFND3DC) GetProcAddress(
00189 hD3DLib, TEXT("Direct3DCreate9"));
00190
00191 if (!OurDirect3DCreate9)
00192 {
00193 VERBOSE(VB_IMPORTANT, LOC_ERR + "Cannot locate reference to "
00194 "Direct3DCreate9 ABI in DLL");
00195
00196 return false;
00197 }
00198 }
00199
00200
00201 m_pD3D = OurDirect3DCreate9(D3D_SDK_VERSION);
00202 if (!m_pD3D)
00203 {
00204 VERBOSE(VB_IMPORTANT, LOC_ERR +
00205 "Could not create Direct3D9 instance.");
00206
00207 return false;
00208 }
00209
00210
00211 ZeroMemory(&d3dCaps, sizeof(d3dCaps));
00212
00213 if (D3D_OK != m_pD3D->GetDeviceCaps(
00214 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))
00215 {
00216 VERBOSE(VB_IMPORTANT, LOC_ERR +
00217 "Could not read adapter capabilities.");
00218
00219 return false;
00220 }
00221
00222 D3DDISPLAYMODE d3ddm;
00223
00224
00225 if (D3D_OK != m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))
00226 {
00227 VERBOSE(VB_IMPORTANT, LOC_ERR +
00228 "Could not read adapter display mode.");
00229
00230 return false;
00231 }
00232 m_RefreshRate = d3ddm.RefreshRate;
00233
00234 m_ddFormat = d3ddm.Format;
00235 D3DPRESENT_PARAMETERS d3dpp;
00236
00237
00238 ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
00239 d3dpp.hDeviceWindow = m_hWnd;
00240 d3dpp.Windowed = TRUE;
00241 d3dpp.BackBufferWidth = m_InputCX;
00242 d3dpp.BackBufferHeight = m_InputCX;
00243 d3dpp.BackBufferCount = 1;
00244 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
00245 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
00246 d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
00247 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
00248
00249
00250 if (D3D_OK != m_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
00251 D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
00252 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
00253 &d3dpp, &m_pd3dDevice))
00254 {
00255 VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not create the D3D device!");
00256 return false;
00257 }
00258
00259
00260
00261
00262
00263 D3DFORMAT format = D3DFMT_X8R8G8B8;
00264
00265 HRESULT hr = m_pD3D->CheckDeviceFormat(
00266 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_ddFormat, 0,
00267 D3DRTYPE_SURFACE, format);
00268
00269 if (SUCCEEDED(hr))
00270 {
00271
00272
00273
00274 hr = m_pD3D->CheckDeviceFormatConversion(
00275 D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
00276 format, m_ddFormat);
00277
00278 if (FAILED(hr))
00279 {
00280 VERBOSE(VB_IMPORTANT, LOC_ERR +
00281 "Device does not support conversion to RGB format");
00282
00283 return false;
00284 }
00285 }
00286 else
00287 {
00288 VERBOSE(VB_IMPORTANT, LOC_ERR +
00289 "Device does not support surfaces in RGB format");
00290
00291 return false;
00292 }
00293
00294 hr = m_pd3dDevice->CreateOffscreenPlainSurface(
00295 m_InputCX,
00296 m_InputCY,
00297 format,
00298 D3DPOOL_DEFAULT,
00299 &m_pSurface,
00300 NULL);
00301
00302 if (FAILED(hr))
00303 {
00304 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create picture surface");
00305 return false;
00306 }
00307
00308
00309 m_pd3dDevice->ColorFill(m_pSurface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
00310
00311
00312
00313
00314
00315
00316 hr = m_pd3dDevice->CreateTexture(
00317 m_InputCX,
00318 m_InputCY,
00319 1,
00320 D3DUSAGE_RENDERTARGET,
00321 m_ddFormat,
00322 D3DPOOL_DEFAULT,
00323 &m_pTexture,
00324 NULL);
00325
00326 if (FAILED(hr))
00327 {
00328 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create texture");
00329 return false;
00330 }
00331
00332
00333
00334
00335 hr = m_pd3dDevice->CreateVertexBuffer(
00336 sizeof(CUSTOMVERTEX)*4,
00337 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
00338 D3DFVF_CUSTOMVERTEX,
00339 D3DPOOL_DEFAULT,
00340 &m_pVertexBuffer,
00341 NULL);
00342 if (FAILED(hr))
00343 {
00344 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create vertex buffer");
00345 return false;
00346 }
00347
00348
00349 CUSTOMVERTEX *p_vertices;
00350 hr = m_pVertexBuffer->Lock(0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD);
00351
00352 if (FAILED(hr))
00353 {
00354 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to lock vertex buffer");
00355 return false;
00356 }
00357
00358
00359 p_vertices[0].x = 0.0f;
00360 p_vertices[0].y = 0.0f;
00361 p_vertices[0].z = 0.0f;
00362 p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
00363 p_vertices[0].rhw = 1.0f;
00364 p_vertices[0].tu = 0.0f;
00365 p_vertices[0].tv = 0.0f;
00366
00367 p_vertices[1].x = (float)m_InputCX;
00368 p_vertices[1].y = 0.0f;
00369 p_vertices[1].z = 0.0f;
00370 p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
00371 p_vertices[1].rhw = 1.0f;
00372 p_vertices[1].tu = 1.0f;
00373 p_vertices[1].tv = 0.0f;
00374
00375 p_vertices[2].x = (float)m_InputCX;
00376 p_vertices[2].y = (float)m_InputCY;
00377 p_vertices[2].z = 0.0f;
00378 p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
00379 p_vertices[2].rhw = 1.0f;
00380 p_vertices[2].tu = 1.0f;
00381 p_vertices[2].tv = 1.0f;
00382
00383 p_vertices[3].x = 0.0f;
00384 p_vertices[3].y = (float)m_InputCY;
00385 p_vertices[3].z = 0.0f;
00386 p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255);
00387 p_vertices[3].rhw = 1.0f;
00388 p_vertices[3].tu = 0.0f;
00389 p_vertices[3].tv = 1.0f;
00390
00391 hr = m_pVertexBuffer->Unlock();
00392 if (FAILED(hr))
00393 {
00394 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to unlock vertex buffer");
00395 return false;
00396 }
00397
00398
00399
00400 m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
00401 m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
00402
00403
00404 m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
00405 m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
00406
00407
00408 m_pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
00409
00410
00411 m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
00412
00413
00414 m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
00415
00416
00417 m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
00418
00419
00420 m_pd3dDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
00421
00422
00423 m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
00424
00425
00426 m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
00427 m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
00428 m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
00429 m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
00430 m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x10);
00431 m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC,D3DCMP_GREATER);
00432
00433
00434 m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,D3DTOP_MODULATE);
00435 m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
00436 m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
00437
00438
00439 m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
00440
00441 VERBOSE(VB_GENERAL, LOC +
00442 "Direct3D device adapter successfully initialized");
00443
00444 return true;
00445 }
00446
00447 int VideoOutputD3D::GetRefreshRate(void)
00448 {
00449 return 1000000 / m_RefreshRate;
00450 }
00451
00452 bool VideoOutputD3D::Init(int width, int height, float aspect,
00453 WId winid, int winx, int winy, int winw,
00454 int winh, WId embedid)
00455 {
00456 VERBOSE(VB_PLAYBACK, LOC +
00457 "Init w=" << width << " h=" << height);
00458
00459 db_vdisp_profile->SetVideoRenderer("direct3d");
00460
00461 vbuffers.Init(kNumBuffers, true, kNeedFreeFrames,
00462 kPrebufferFramesNormal, kPrebufferFramesSmall,
00463 kKeepPrebuffer);
00464
00465 VideoOutput::Init(width, height, aspect, winid,
00466 winx, winy, winw, winh, embedid);
00467
00468 m_hWnd = winid;
00469
00470 m_InputCX = video_dim.width();
00471 m_InputCY = video_dim.height();
00472
00473 if (!vbuffers.CreateBuffers(video_dim.width(), video_dim.height()))
00474 return false;
00475
00476 if (!InitD3D())
00477 {
00478 UnInitD3D();
00479 return false;
00480 }
00481
00482 m_pauseFrame.height = vbuffers.GetScratchFrame()->height;
00483 m_pauseFrame.width = vbuffers.GetScratchFrame()->width;
00484 m_pauseFrame.bpp = vbuffers.GetScratchFrame()->bpp;
00485 m_pauseFrame.size = vbuffers.GetScratchFrame()->size;
00486 m_pauseFrame.buf = new unsigned char[m_pauseFrame.size + 128];
00487 m_pauseFrame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
00488
00489 MoveResize();
00490
00491 return true;
00492 }
00493
00494 void VideoOutputD3D::PrepareFrame(VideoFrame *buffer, FrameScanType t)
00495 {
00496 if (IsErrored())
00497 {
00498 VERBOSE(VB_IMPORTANT, LOC_ERR +
00499 "PrepareFrame() called while IsErrored is true.");
00500 return;
00501 }
00502
00503 if (!buffer)
00504 buffer = vbuffers.GetScratchFrame();
00505
00506 framesPlayed = buffer->frameNumber + 1;
00507 AVPicture image_in, image_out;
00508
00509 D3DLOCKED_RECT d3drect;
00510
00511 HRESULT hr = m_pSurface->LockRect(&d3drect, NULL, 0);
00512 if (FAILED(hr))
00513 {
00514 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to lock picture surface");
00515 return;
00516 }
00517
00518 avpicture_fill(&image_out, (uint8_t*) d3drect.pBits,
00519 PIX_FMT_RGBA32, m_InputCX, m_InputCY);
00520 image_out.linesize[0] = d3drect.Pitch;
00521 avpicture_fill(&image_in, buffer->buf,
00522 PIX_FMT_YUV420P, m_InputCX, m_InputCY);
00523 img_convert(&image_out, PIX_FMT_RGBA32, &image_in,
00524 PIX_FMT_YUV420P, m_InputCX, m_InputCY);
00525
00526 hr = m_pSurface->UnlockRect();
00527 if (FAILED(hr))
00528 {
00529 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to unlock picture surface");
00530 return;
00531 }
00532 }
00533
00534 void VideoOutputD3D::Show(FrameScanType )
00535 {
00536 if (IsErrored())
00537 {
00538 VERBOSE(VB_IMPORTANT, LOC_ERR +
00539 "Show() called while IsErrored is true.");
00540
00541 return;
00542 }
00543
00544 if (needrepaint)
00545 DrawUnusedRects(false);
00546
00547 if (m_pd3dDevice)
00548 {
00549
00550 HRESULT hr = m_pd3dDevice->TestCooperativeLevel();
00551 if (FAILED(hr))
00552 {
00553 switch (hr)
00554 {
00555 case D3DERR_DEVICENOTRESET:
00556 VERBOSE(VB_IMPORTANT, LOC_ERR +
00557 "The device has been lost but can be reset "
00558 "at this time. TODO: implement device reset");
00559
00560
00561 goto RenderError;
00562 case D3DERR_DEVICELOST:
00563 VERBOSE(VB_IMPORTANT, LOC_ERR +
00564 "The device has been lost and cannot be reset "
00565 "at this time.");
00566 goto RenderError;
00567 case D3DERR_DRIVERINTERNALERROR:
00568 VERBOSE(VB_IMPORTANT, LOC_ERR +
00569 "Internal driver error. "
00570 "Please shut down the application.");
00571 goto RenderError;
00572 default:
00573 VERBOSE(VB_IMPORTANT, LOC_ERR +
00574 "TestCooperativeLevel() failed.");
00575 goto RenderError;
00576 }
00577 }
00578
00579
00580 hr = m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET,
00581 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
00582 if (FAILED(hr))
00583 {
00584 VERBOSE(VB_IMPORTANT, LOC_ERR + "Clear() failed.");
00585 goto RenderError;
00586 }
00587
00588
00589 LPDIRECT3DSURFACE9 p_d3ddest;
00590 hr = m_pTexture->GetSurfaceLevel(0, &p_d3ddest);
00591 if (FAILED(hr))
00592 {
00593 VERBOSE(VB_IMPORTANT, LOC_ERR + "GetSurfaceLevel() failed");
00594 goto RenderError;
00595 }
00596
00597
00598
00599 hr = m_pd3dDevice->StretchRect(m_pSurface, NULL, p_d3ddest,
00600 NULL, D3DTEXF_LINEAR);
00601 p_d3ddest->Release();
00602 if (FAILED(hr))
00603 {
00604 VERBOSE(VB_IMPORTANT, LOC_ERR + "StretchRect() failed");
00605 goto RenderError;
00606 }
00607
00608
00609 hr = m_pd3dDevice->BeginScene();
00610 if (FAILED(hr))
00611 {
00612 VERBOSE(VB_IMPORTANT, LOC_ERR + "BeginScene() failed");
00613 goto RenderError;
00614 }
00615
00616
00617
00618
00619
00620
00621 hr = m_pd3dDevice->SetTexture(0, (LPDIRECT3DBASETEXTURE9)m_pTexture);
00622 if (FAILED(hr))
00623 {
00624 m_pd3dDevice->EndScene();
00625
00626 VERBOSE(VB_IMPORTANT, LOC_ERR + "SetTexture() failed");
00627 goto RenderError;
00628 }
00629
00630
00631 hr = m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer,
00632 0, sizeof(CUSTOMVERTEX));
00633 if (FAILED(hr))
00634 {
00635 m_pd3dDevice->EndScene();
00636
00637 VERBOSE(VB_IMPORTANT, LOC_ERR + "SetStreamSource() failed");
00638 goto RenderError;
00639 }
00640
00641
00642 hr = m_pd3dDevice->SetVertexShader(NULL);
00643
00644
00645 hr = m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
00646 if (FAILED(hr))
00647 {
00648 m_pd3dDevice->EndScene();
00649
00650 VERBOSE(VB_IMPORTANT, LOC_ERR + "SetFVF() failed");
00651 goto RenderError;
00652 }
00653
00654
00655 hr = m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
00656 if (FAILED(hr))
00657 {
00658 m_pd3dDevice->EndScene();
00659
00660 VERBOSE(VB_IMPORTANT, LOC_ERR + "DrawPrimitive() failed");
00661 goto RenderError;
00662 }
00663
00664
00665 hr = m_pd3dDevice->EndScene();
00666 if (FAILED(hr))
00667 {
00668
00669 VERBOSE(VB_IMPORTANT, LOC_ERR + "EndScene() failed");
00670 goto RenderError;
00671 }
00672
00673 {
00674 RECT rc_src =
00675 {
00676 video_rect.left(), video_rect.top(),
00677 video_rect.right(), video_rect.bottom(),
00678 };
00679
00680 RECT rc_dest =
00681 {
00682 display_video_rect.left(), display_video_rect.top(),
00683 display_video_rect.right(), display_video_rect.bottom(),
00684 };
00685
00686 hr = m_pd3dDevice->Present(
00687 &rc_src, &rc_dest,
00688 (embedding) ? m_hEmbedWnd : NULL, NULL);
00689 }
00690
00691 if (FAILED(hr))
00692 VERBOSE(VB_IMPORTANT, LOC_ERR + "Present() failed)");
00693
00694 RenderError:
00695
00696 qApp->wakeUpGuiThread();
00697
00698
00699 SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
00700 }
00701 else
00702 {
00703 VERBOSE(VB_IMPORTANT, LOC_ERR + "Direct3D device not initialized");
00704 }
00705 }
00706
00707 void VideoOutputD3D::DrawUnusedRects(bool sync)
00708 {
00709 if (embedding)
00710 return;
00711
00712 needrepaint = false;
00713 HDC hdc = GetDC(m_hWnd);
00714 if (hdc)
00715 {
00716 RECT rc;
00717 if (GetClientRect(m_hWnd, &rc))
00718 {
00719 FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
00720 }
00721 ReleaseDC(m_hWnd, hdc);
00722 }
00723 }
00724
00725 void VideoOutputD3D::EmbedInWidget(WId wid, int x, int y, int w, int h)
00726 {
00727 if (embedding)
00728 return;
00729
00730 VideoOutput::EmbedInWidget(wid, x, y, w, h);
00731 m_hEmbedWnd = wid;
00732 }
00733
00734 void VideoOutputD3D::StopEmbedding(void)
00735 {
00736 if (!embedding)
00737 return;
00738
00739 VideoOutput::StopEmbedding();
00740 }
00741
00742 void VideoOutputD3D::Zoom(ZoomDirection direction)
00743 {
00744 RECT rc;
00745 ::GetClientRect(m_hWnd, &rc);
00746
00747 HDC hdc = ::GetDC(m_hWnd);
00748 if (hdc)
00749 {
00750 ::FillRect(hdc, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
00751 ::ReleaseDC(m_hWnd, hdc);
00752 }
00753 }
00754
00755 void VideoOutputD3D::UpdatePauseFrame(void)
00756 {
00757 QMutexLocker locker(&m_lock);
00758 VideoFrame *used_frame = vbuffers.head(kVideoBuffer_used);
00759 if (!used_frame)
00760 used_frame = vbuffers.GetScratchFrame();
00761
00762 CopyFrame(&m_pauseFrame, used_frame);
00763 }
00764
00765 void VideoOutputD3D::ProcessFrame(VideoFrame *frame, OSD *osd,
00766 FilterChain *filterList,
00767 NuppelVideoPlayer *pipPlayer)
00768 {
00769 QMutexLocker locker(&m_lock);
00770 if (IsErrored())
00771 {
00772 VERBOSE(VB_IMPORTANT, LOC_ERR +
00773 "ProcessFrame() called while IsErrored is true.");
00774 return;
00775 }
00776
00777 if (!frame)
00778 {
00779 frame = vbuffers.GetScratchFrame();
00780 CopyFrame(vbuffers.GetScratchFrame(), &m_pauseFrame);
00781 }
00782
00783 if (m_deinterlacing && m_deintFilter != NULL)
00784 m_deintFilter->ProcessFrame(frame);
00785
00786 if (filterList)
00787 filterList->ProcessFrame(frame);
00788
00789 ShowPip(frame, pipPlayer);
00790 DisplayOSD(frame, osd);
00791 }
00792
00793 float VideoOutputD3D::GetDisplayAspect(void) const
00794 {
00795 float width = display_visible_rect.width();
00796 float height = display_visible_rect.height();
00797
00798 if (height <= 0.0001f)
00799 return 16.0f / 9.0f;
00800
00801 return width / height;
00802 }
00803
00804 QStringList VideoOutputD3D::GetAllowedRenderers(
00805 MythCodecID myth_codec_id, const QSize &video_dim)
00806 {
00807 QStringList list;
00808 list += "direct3d";
00809 return list;
00810 }