6
#define _WIN32_WINNT 0x500
7
#include "mythcontext.h"
8
#include "videoout_dx.h"
9
#include "filtermanager.h"
11
#include "videodisplayprofile.h"
12
#include "myth_imgconvert.h"
23
const int kNumBuffers = 31;
24
const int kNeedFreeFrames = 1;
25
const int kPrebufferFramesNormal = 12;
26
const int kPrebufferFramesSmall = 4;
27
const int kKeepPrebuffer = 2;
29
/*****************************************************************************
31
* Defining them here allows us to get rid of the dxguid library during
33
*****************************************************************************/
35
DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
36
DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 );
37
DEFINE_GUID( IID_IDirectDrawColorControl, 0x4B9F0EE0,0x0D7E,0x11D0,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8 );
40
VideoOutputDX::VideoOutputDX(void)
41
: VideoOutput(), XJ_width(0), XJ_height(0)
47
pauseFrame.buf = NULL;
51
display_driver = NULL;
52
// current_surface = NULL;
65
/* Multimonitor stuff */
67
display_driver = NULL;
68
MonitorFromWindow = NULL;
69
GetMonitorInfo = NULL;
70
if ((user32 = GetModuleHandle("USER32")))
72
MonitorFromWindow = (HMONITOR (WINAPI*)(HWND, DWORD))
73
GetProcAddress(user32, "MonitorFromWindow");
74
GetMonitorInfo = (BOOL (WINAPI*)(HMONITOR, LPMONITORINFO))
75
GetProcAddress(user32, "GetMonitorInfoA");
79
VideoOutputDX::~VideoOutputDX()
82
delete [] pauseFrame.buf;
84
DirectXCloseSurface();
85
DirectXCloseDisplay();
91
// this is documented in videooutbase.cpp
92
void VideoOutputDX::Zoom(ZoomDirection direction)
94
VideoOutput::Zoom(direction);
98
void VideoOutputDX::MoveResize()
100
VideoOutput::MoveResize();
102
DirectXUpdateOverlay();
105
bool VideoOutputDX::InputChanged(const QSize &input_size,
107
MythCodecID av_codec_id,
110
VERBOSE(VB_PLAYBACK, QString("InputChanged(%1,%2,%3) %4")
111
.arg(input_size.width()).arg(input_size.height()).arg(aspect)
112
.arg(toString(av_codec_id)));
114
VideoOutput::InputChanged(input_size, aspect, av_codec_id, codec_private);
116
db_vdisp_profile->SetVideoRenderer("directx");
118
const QSize video_dim = windows[0].GetVideoDim();
119
XJ_width = video_dim.width();
120
XJ_height = video_dim.height();
122
vbuffers.DeleteBuffers();
124
DirectXCloseSurface();
127
bool ok = vbuffers.CreateBuffers(XJ_width, XJ_height);
130
VERBOSE(VB_IMPORTANT, "InputChanged(): Failed to recreate buffers");
131
errorState = kError_Unknown;
135
delete [] pauseFrame.buf;
140
pauseFrame.height = vbuffers.GetScratchFrame()->height;
141
pauseFrame.width = vbuffers.GetScratchFrame()->width;
142
pauseFrame.bpp = vbuffers.GetScratchFrame()->bpp;
143
pauseFrame.size = vbuffers.GetScratchFrame()->size;
144
pauseFrame.buf = new unsigned char[pauseFrame.size];
145
pauseFrame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
150
DisplayInfo VideoOutputDX::GetDisplayInfo(void)
155
IDirectDraw_GetMonitorFrequency(ddobject, &rate);
156
return DisplayInfo(1000000 / rate);
158
return DisplayInfo();
161
void VideoOutputDX::WaitForVSync(void)
166
IDirectDraw_WaitForVerticalBlank(ddobject, DDWAITVB_BLOCKBEGIN, NULL);
169
bool VideoOutputDX::Init(int width, int height, float aspect,
170
WId winid, int winx, int winy, int winw,
171
int winh, WId embedid)
173
db_vdisp_profile->SetVideoRenderer("directx");
175
vbuffers.Init(kNumBuffers, true, kNeedFreeFrames,
176
kPrebufferFramesNormal, kPrebufferFramesSmall,
178
VideoOutput::Init(width, height, aspect, winid,
179
winx, winy, winw, winh, embedid);
183
const QSize video_dim = windows[0].GetVideoDim();
184
XJ_width = video_dim.width();
185
XJ_height = video_dim.height();
186
windows[0].SetDisplayAspect((float)winw / winh);
188
vbuffers.CreateBuffers(XJ_width, XJ_height);
191
/* Initialise DirectDraw if not already done.
192
* We do this here because on multi-monitor systems we may have to
193
* re-create the directdraw surfaces. */
194
if (!ddobject && DirectXInitDDraw() != 0)
196
VERBOSE(VB_IMPORTANT, "cannot initialize DirectDraw");
200
/* Create the directx display */
201
if (!display && DirectXCreateDisplay() != 0)
203
VERBOSE(VB_IMPORTANT, "cannot initialize DirectDraw");
212
InitPictureAttributes();
216
pauseFrame.height = vbuffers.GetScratchFrame()->height;
217
pauseFrame.width = vbuffers.GetScratchFrame()->width;
218
pauseFrame.bpp = vbuffers.GetScratchFrame()->bpp;
219
pauseFrame.size = vbuffers.GetScratchFrame()->size;
220
pauseFrame.buf = new unsigned char[pauseFrame.size];
221
pauseFrame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
228
void VideoOutputDX::Exit(void)
234
vbuffers.DeleteBuffers();
238
void VideoOutputDX::EmbedInWidget(WId wid, int x, int y, int w,
241
if (windows[0].IsEmbedding())
244
VideoOutput::EmbedInWidget(x, y, w, h);
247
void VideoOutputDX::StopEmbedding(void)
249
if (!windows[0].IsEmbedding())
252
VideoOutput::StopEmbedding();
255
void VideoOutputDX::PrepareFrame(VideoFrame *buffer, FrameScanType t)
259
VERBOSE(VB_IMPORTANT, "VideoOutputDX::PrepareFrame() called while IsErrored is true.");
263
unsigned char *picbuf;
267
buffer = vbuffers.GetScratchFrame();
269
framesPlayed = buffer->frameNumber + 1;
271
if (DirectXLockSurface((void**) &picbuf, &stride) == 0)
273
if (chroma == FOURCC_IYUV || chroma == FOURCC_I420)
275
for (int i = 0; i < XJ_height; i++)
276
memcpy(picbuf + (i * stride), buffer->buf + (i * XJ_width), XJ_width);
277
for (int i = 0; i < XJ_height / 2; i++)
278
memcpy(picbuf + (XJ_height * stride) + (i * stride / 2),
279
buffer->buf + XJ_height * XJ_width + (i * XJ_width / 2),
281
for (int i = 0; i < XJ_height / 2; i++)
282
memcpy(picbuf + (XJ_height * stride * 5 / 4) + (i * stride / 2),
283
buffer->buf + XJ_height * XJ_width * 5 / 4 + (i * XJ_width / 2),
286
else if (chroma == FOURCC_YV12)
288
for (int i = 0; i < XJ_height; i++)
289
memcpy(picbuf + (i * stride), buffer->buf + (i * XJ_width), XJ_width);
290
for (int i = 0; i < XJ_height / 2; i++)
291
memcpy(picbuf + (XJ_height * stride) + (i * stride / 2),
292
buffer->buf + XJ_height * XJ_width * 5 / 4 + (i * XJ_width / 2),
294
for (int i = 0; i < XJ_height / 2; i++)
295
memcpy(picbuf + (XJ_height * stride * 5 / 4) + (i * stride / 2),
296
buffer->buf + XJ_height * XJ_width + (i * XJ_width / 2),
300
AVPicture image_in, image_out;
301
PixelFormat av_format;
307
case FOURCC_YUNV: av_format = PIX_FMT_YUYV422; break;
308
case FOURCC_RV15: av_format = PIX_FMT_RGB555; break;
309
case FOURCC_RV16: av_format = PIX_FMT_RGB565; break;
310
case FOURCC_RV24: av_format = PIX_FMT_RGB24; break;
311
case FOURCC_RV32: av_format = PIX_FMT_RGB32; break;
313
VERBOSE(VB_IMPORTANT, "VODX: Non Xv mode only supports 16, 24, and 32 bpp displays");
314
errorState = kError_Unknown;
318
avpicture_fill(&image_out, picbuf, av_format, XJ_width, XJ_height);
319
image_out.linesize[0] = stride;
321
avpicture_fill(&image_in, buffer->buf, PIX_FMT_YUV420P, XJ_width, XJ_height);
323
myth_sws_img_convert(
324
&image_out, av_format, &image_in, PIX_FMT_YUV420P,
325
XJ_width, XJ_height);
329
DirectXUnlockSurface();
332
VERBOSE(VB_IMPORTANT, "Could not lock surface!");
335
void VideoOutputDX::Show(FrameScanType )
341
VERBOSE(VB_IMPORTANT, "VideoOutputDX::Show() called while IsErrored istrue.");
345
if ((display == NULL))
347
VERBOSE(VB_IMPORTANT, "no display!!");
351
/* Our surface can be lost so be sure to check this
352
* and restore it if need be */
353
if (IDirectDrawSurface2_IsLost(display) == DDERR_SURFACELOST)
355
if (IDirectDrawSurface2_Restore(display) == DD_OK && using_overlay)
356
DirectXUpdateOverlay();
365
const QRect video_rect = windows[0].GetVideoRect();
366
const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
367
const QRect display_video_rect = windows[0].GetDisplayVideoRect();
369
rect_src.left = video_rect.left();
370
rect_src.right = XJ_width;
371
rect_src.top = video_rect.top();
372
rect_src.bottom = XJ_height;
374
if (display_video_rect.left() < display_visible_rect.left() ||
375
display_video_rect.right() > display_visible_rect.right())
377
rect_dest.left = display_visible_rect.left();
378
rect_dest.right = display_visible_rect.right();
380
int diff_x = display_visible_rect.left();
381
diff_x -= display_video_rect.left();
382
int diff_w = display_video_rect.width();
383
diff_x -= display_visible_rect.width();
385
rect_src.left += (XJ_width * diff_x) / display_video_rect.width();
386
rect_src.right -= ((XJ_width * (diff_w - diff_x)) /
387
display_video_rect.width());
391
rect_dest.left = display_video_rect.left();
392
rect_dest.right = display_video_rect.right();
395
if (display_video_rect.top() < display_visible_rect.top() ||
396
display_video_rect.bottom() > display_visible_rect.bottom())
398
rect_dest.top = display_visible_rect.top();
399
rect_dest.bottom = display_visible_rect.bottom();
401
int diff_y = display_visible_rect.top();
402
diff_y -= display_video_rect.top();
403
int diff_h = display_video_rect.height();
404
diff_h -= display_visible_rect.height();
406
rect_src.top += (XJ_height * diff_y) / display_video_rect.height();
407
rect_src.bottom -= ((XJ_height * (diff_h - diff_y)) /
408
display_video_rect.height());
412
rect_dest.top = display_video_rect.top();
413
rect_dest.bottom = display_video_rect.bottom();
416
/* We ask for the "NOTEARING" option */
417
memset(&ddbltfx, 0, sizeof(DDBLTFX));
418
ddbltfx.dwSize = sizeof(DDBLTFX);
419
ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
421
/* Blit video surface to display */
422
dxresult = IDirectDrawSurface2_Blt(display, &rect_dest, back_surface,
423
&rect_src, DDBLT_ASYNC, &ddbltfx);
424
if (dxresult != DD_OK)
426
VERBOSE(VB_IMPORTANT, "could not blit surface (error " << hex << dxresult << dec << ")");
431
else /* using overlay */
433
/* Flip the overlay buffers if we are using back buffers */
434
if (front_surface == back_surface)
439
dxresult = IDirectDrawSurface2_Flip(front_surface, NULL, DDFLIP_WAIT);
440
if (dxresult != DD_OK)
442
VERBOSE(VB_IMPORTANT, "could not flip overlay (error " << hex << dxresult << dec << ")");
445
/* set currently displayed pic */
446
//p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
451
void VideoOutputDX::DrawUnusedRects(bool)
455
void VideoOutputDX::UpdatePauseFrame(void)
457
VideoFrame *pauseb = vbuffers.GetScratchFrame();
458
VideoFrame *pauseu = vbuffers.head(kVideoBuffer_used);
460
memcpy(pauseFrame.buf, pauseu->buf, pauseu->size);
462
memcpy(pauseFrame.buf, pauseb->buf, pauseb->size);
465
void VideoOutputDX::ProcessFrame(VideoFrame *frame, OSD *osd,
466
FilterChain *filterList,
467
const PIPMap &pipPlayers,
472
VERBOSE(VB_IMPORTANT, "VideoOutputDX::ProcessFrame() called while IsErrored is true.");
478
frame = vbuffers.GetScratchFrame();
479
CopyFrame(vbuffers.GetScratchFrame(), &pauseFrame);
482
if (m_deinterlacing && m_deintFilter != NULL)
483
m_deintFilter->ProcessFrame(frame, scan);
485
filterList->ProcessFrame(frame);
487
ShowPIPs(frame, pipPlayers);
488
DisplayOSD(frame, osd);
491
// this is documented in videooutbase.cpp
492
int VideoOutputDX::SetPictureAttribute(
493
PictureAttribute attribute, int newValue)
495
if (ccontrol == NULL)
498
newValue = min(max(newValue, 0), 100);
501
memset(&ddcc, 0, sizeof(DDCOLORCONTROL));
502
ddcc.dwSize = sizeof(DDCOLORCONTROL);
506
case kPictureAttribute_Brightness:
507
ddcc.dwFlags = DDCOLOR_BRIGHTNESS;
508
ddcc.lBrightness = (newValue * newValue * 17) / 10 - 70 * newValue;
510
case kPictureAttribute_Contrast:
511
ddcc.dwFlags = DDCOLOR_CONTRAST;
512
ddcc.lContrast = newValue * 200;
514
case kPictureAttribute_Colour:
515
ddcc.dwFlags = DDCOLOR_SATURATION;
516
ddcc.lSaturation = newValue * 200;
518
case kPictureAttribute_Hue:
519
ddcc.dwFlags = DDCOLOR_HUE;
520
ddcc.lHue = newValue * 36 / 10;
528
dxresult = IDirectDrawColorControl_SetColorControls(ccontrol, &ddcc);
530
if (dxresult != DD_OK)
532
VERBOSE(VB_IMPORTANT, "Could not update colour controls: "
533
<< hex << dxresult << dec);
537
SetPictureAttributeDBValue(attribute, newValue);
542
float VideoOutputDX::GetDisplayAspect(void) const
544
const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
545
float width = display_visible_rect.width();
546
float height = display_visible_rect.height();
548
if (height <= 0.0001f)
551
return width / height;
554
static const DWORD pref_chromas[] = { FOURCC_IYUV,
567
void VideoOutputDX::MakeSurface()
573
for (int i = 0; !outputpictures && (pref_chromas[i] != 0xFFFFFFFF); i++)
575
chroma = pref_chromas[i];
583
/* If it didn't work then don't try to use an overlay */
584
using_overlay = false;
585
for (int i = 0; !outputpictures && (pref_chromas[i] != 0xFFFFFFFF); i++)
587
chroma = pref_chromas[i];
595
/* If it _still_ didn't work then don't try to use vidmem */
597
for (int i = 0; !outputpictures && (pref_chromas[i] != 0xFFFFFFFF); i++)
599
chroma = pref_chromas[i];
609
typedef HRESULT (WINAPI *LPFNDDC)(GUID *,LPDIRECTDRAW *,IUnknown *);
610
typedef HRESULT (WINAPI *LPFNDDEE)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
613
/*****************************************************************************
614
* DirectXInitDDraw: Takes care of all the DirectDraw initialisations
615
*****************************************************************************
616
* This function initialise and allocate resources for DirectDraw.
617
*****************************************************************************/
618
int VideoOutputDX::DirectXInitDDraw()
621
LPFNDDC OurDirectDrawCreate;
622
LPFNDDEE OurDirectDrawEnumerateEx;
623
LPDIRECTDRAW p_ddobject;
625
VERBOSE(VB_IMPORTANT, "DirectXInitDDraw");
627
/* Load direct draw DLL */
628
ddraw_dll = LoadLibrary("DDRAW.DLL");
629
if (ddraw_dll == NULL)
631
VERBOSE(VB_IMPORTANT, "DirectXInitDDraw failed loading ddraw.dll");
635
OurDirectDrawCreate =
636
(LPFNDDC)GetProcAddress(ddraw_dll, "DirectDrawCreate");
637
if (OurDirectDrawCreate == NULL )
639
VERBOSE(VB_IMPORTANT, "DirectXInitDDraw failed GetProcAddress");
643
OurDirectDrawEnumerateEx =
644
(LPFNDDEE)GetProcAddress(ddraw_dll, "DirectDrawEnumerateExA");
646
if (OurDirectDrawEnumerateEx && MonitorFromWindow )
648
monitor = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);
650
/* Enumerate displays * /
651
OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout,
652
DDENUM_ATTACHEDSECONDARYDEVICES );*/
655
/* Initialize DirectDraw now */
656
dxresult = OurDirectDrawCreate(display_driver, &p_ddobject, NULL);
657
if (dxresult != DD_OK)
659
VERBOSE(VB_IMPORTANT, "DirectXInitDDraw cannot initialize DDraw");
663
/* Get the IDirectDraw2 interface */
664
dxresult = IDirectDraw_QueryInterface(p_ddobject, IID_IDirectDraw2, (LPVOID *) &ddobject);
665
/* Release the unused interface */
666
IDirectDraw_Release(p_ddobject);
667
if (dxresult != DD_OK)
669
VERBOSE(VB_IMPORTANT, "cannot get IDirectDraw2 interface" );
673
/* Set DirectDraw Cooperative level, ie what control we want over Windows
675
dxresult = IDirectDraw2_SetCooperativeLevel(ddobject, wnd, DDSCL_NORMAL);
676
if (dxresult != DD_OK)
678
VERBOSE(VB_IMPORTANT, "cannot set direct draw cooperative level");
682
/* Get the size of the current display device */
683
if (monitor && GetMonitorInfo)
685
MONITORINFO monitor_info;
686
monitor_info.cbSize = sizeof(MONITORINFO);
687
GetMonitorInfo(monitor, &monitor_info);
688
rect_display = monitor_info.rcMonitor;
692
rect_display.left = 0;
693
rect_display.top = 0;
694
rect_display.right = GetSystemMetrics(SM_CXSCREEN);
695
rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
698
VERBOSE(VB_IMPORTANT, "screen dimensions ("
699
<< rect_display.left << "x"
700
<< rect_display.top << ","
701
<< rect_display.right << "x"
702
<< rect_display.bottom << ")");
704
/* Probe the capabilities of the hardware */
705
DirectXGetDDrawCaps();
707
VERBOSE(VB_IMPORTANT, "End DirectXInitDDraw");
712
IDirectDraw2_Release(ddobject);
714
FreeLibrary(ddraw_dll);
720
/*****************************************************************************
721
* DirectXCreateClipper: Create a clipper that will be used when blitting the
722
* RGB surface to the main display.
723
*****************************************************************************
724
* This clipper prevents us to modify by mistake anything on the screen
725
* which doesn't belong to our window. For example when a part of our video
726
* window is hidden by another window.
727
*****************************************************************************/
728
int VideoOutputDX::DirectXCreateClipper()
732
VERBOSE(VB_IMPORTANT, "DirectXCreateClipper");
734
/* Create the clipper */
735
dxresult = IDirectDraw2_CreateClipper(ddobject, 0, &clipper, NULL);
736
if (dxresult != DD_OK)
738
VERBOSE(VB_IMPORTANT, "cannot create clipper (error " << hex << dxresult << dec << ")");
742
/* Associate the clipper to the window */
743
dxresult = IDirectDrawClipper_SetHWnd(clipper, 0, wnd);
744
if (dxresult != DD_OK)
746
VERBOSE(VB_IMPORTANT, "cannot attach clipper to window (error " << hex << dxresult << dec << ")");
750
/* associate the clipper with the surface */
751
dxresult = IDirectDrawSurface_SetClipper(display, clipper);
752
if (dxresult != DD_OK)
754
VERBOSE(VB_IMPORTANT, "cannot attach clipper to surface (error " << hex << dxresult << dec << ")");
763
IDirectDrawClipper_Release(clipper);
769
/*****************************************************************************
770
* DirectXCreateDisplay: create the DirectDraw display.
771
*****************************************************************************
772
* Create and initialize display according to preferences specified in the vout
774
*****************************************************************************/
775
int VideoOutputDX::DirectXCreateDisplay()
779
LPDIRECTDRAWSURFACE p_display;
781
VERBOSE(VB_IMPORTANT, "DirectXCreateDisplay");
783
/* Now get the primary surface. This surface is what you actually see
785
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
786
ddsd.dwSize = sizeof(DDSURFACEDESC);
787
ddsd.dwFlags = DDSD_CAPS;
788
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
790
dxresult = IDirectDraw2_CreateSurface(ddobject, &ddsd, &p_display, NULL );
791
if (dxresult != DD_OK)
793
VERBOSE(VB_IMPORTANT, "cannot get primary surface (error %li)" << dxresult);
797
dxresult = IDirectDrawSurface_QueryInterface(p_display, IID_IDirectDrawSurface2, (LPVOID *) &display);
798
/* Release the old interface */
799
IDirectDrawSurface_Release(p_display);
800
if (dxresult != DD_OK)
802
VERBOSE(VB_IMPORTANT, "cannot query IDirectDrawSurface2 interface " <<
803
"(error %li)" << dxresult);
807
/* The clipper will be used only in non-overlay mode */
808
DirectXCreateClipper();
810
/* Make sure the colorkey will be painted */
812
rgb_colorkey = DirectXFindColorkey(colorkey);
814
VERBOSE(VB_IMPORTANT, "colour key = " << hex << rgb_colorkey << dec);
816
VERBOSE(VB_IMPORTANT, "brushing");
818
/* Create the actual brush */
819
SetClassLong(wnd, GCL_HBRBACKGROUND,
820
(LONG)CreateSolidBrush(rgb_colorkey));
821
InvalidateRect(wnd, NULL, TRUE);
822
//DirectXUpdateRects(true);
824
VERBOSE(VB_IMPORTANT, "display created");
829
/*****************************************************************************
830
* DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
831
*****************************************************************************
832
* The best method of display is with an YUV overlay because the YUV->RGB
833
* conversion is done in hardware.
834
* You can also create a plain RGB surface.
835
* ( Maybe we could also try an RGB overlay surface, which could have hardware
836
* scaling and which would also be faster in window mode because you don't
837
* need to do any blitting to the main display...)
838
*****************************************************************************/
839
int VideoOutputDX::DirectXCreateSurface(LPDIRECTDRAWSURFACE2 *pp_surface_final,
840
DWORD i_chroma, bool b_overlay, int i_backbuffers)
843
LPDIRECTDRAWSURFACE p_surface;
846
/* Create the video surface */
849
/* Now try to create the YUV overlay surface.
850
* This overlay will be displayed on top of the primary surface.
851
* A color key is used to determine whether or not the overlay will be
852
* displayed, ie the overlay will be displayed in place of the primary
853
* surface wherever the primary surface will have this color.
854
* The video window has been created with a background of this color so
855
* the overlay will be only displayed on top of this window */
857
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
858
ddsd.dwSize = sizeof(DDSURFACEDESC);
859
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
860
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
861
ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
862
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
863
ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
864
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
865
ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP : 0);
866
ddsd.dwHeight = XJ_height;
867
ddsd.dwWidth = XJ_width;
868
ddsd.dwBackBufferCount = i_backbuffers;
872
bool b_rgb_surface = (i_chroma == FOURCC_RGB2)
873
|| (i_chroma == FOURCC_RV15) || (i_chroma == FOURCC_RV16)
874
|| (i_chroma == FOURCC_RV24) || (i_chroma == FOURCC_RV32);
876
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
877
ddsd.dwSize = sizeof(DDSURFACEDESC);
878
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
879
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
880
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
881
ddsd.dwHeight = XJ_height;
882
ddsd.dwWidth = XJ_width;
885
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
887
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
891
ddsd.dwFlags |= DDSD_PIXELFORMAT;
892
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
893
ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
897
VERBOSE(VB_IMPORTANT, "VideoOutputDX::DirectXCreateSurface() x: "
898
<< XJ_width << " y: " << XJ_height
899
<< " chrom: " << fourcc_str(i_chroma));
901
dxresult = IDirectDraw2_CreateSurface(ddobject, &ddsd, &p_surface, NULL );
902
if (dxresult != DD_OK )
904
VERBOSE(VB_IMPORTANT, "DD_CreateSurface failed " << hex << dxresult << dec);
905
*pp_surface_final = NULL;
909
/* Now that the surface is created, try to get a newer DirectX interface */
910
dxresult = IDirectDrawSurface_QueryInterface(p_surface, IID_IDirectDrawSurface2, (LPVOID *) pp_surface_final);
911
IDirectDrawSurface_Release(p_surface); /* Release the old interface */
912
if (dxresult != DD_OK)
914
VERBOSE(VB_IMPORTANT, "cannot query IDirectDrawSurface2 interface " <<
915
"(error " << hex << dxresult << dec << ")");
916
*pp_surface_final = NULL;
922
back_surface = *pp_surface_final;
924
/* Reset the front buffer memory */
928
if (DirectXLockSurface((void **) &picbuf, &stride) == DD_OK)
930
memset(picbuf, 127, stride * XJ_height * 3 / 2);
932
DirectXUnlockSurface();
937
/* Check the overlay is useable as some graphics cards allow creating
938
* several overlays but only one can be used at one time. */
939
front_surface = *pp_surface_final;
940
if (DirectXUpdateOverlay() != 0)
942
IDirectDrawSurface2_Release(*pp_surface_final);
943
*pp_surface_final = NULL;
944
front_surface = NULL;
945
VERBOSE(VB_IMPORTANT, "overlay unuseable (might already be in use)" );
950
/* Get the IDirectDraw2 interface */
951
dxresult = IDirectDraw_QueryInterface(*pp_surface_final, IID_IDirectDrawColorControl, (LPVOID *) &ccontrol);
952
if (dxresult != DD_OK)
954
VERBOSE(VB_IMPORTANT, "cannot get colour control interface" );
962
/*****************************************************************************
963
* DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
964
*****************************************************************************
965
* This function returns all resources allocated by DirectXInitDDraw.
966
*****************************************************************************/
967
void VideoOutputDX::DirectXCloseDDraw()
969
VERBOSE(VB_IMPORTANT, "DirectXCloseDDraw");
970
if (ddobject != NULL)
972
IDirectDraw2_Release(ddobject);
976
if (ddraw_dll != NULL)
978
FreeLibrary(ddraw_dll);
982
if (display_driver != NULL)
984
free(display_driver);
985
display_driver = NULL;
991
/*****************************************************************************
992
* DirectXCloseDisplay: close and reset the DirectX display device
993
*****************************************************************************
994
* This function returns all resources allocated by DirectXCreateDisplay.
995
*****************************************************************************/
996
void VideoOutputDX::DirectXCloseDisplay()
998
VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay");
1000
if (clipper != NULL)
1002
VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay clipper");
1003
IDirectDrawClipper_Release(clipper);
1007
if (display != NULL)
1009
VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay display");
1010
IDirectDrawSurface2_Release(display);
1016
/*****************************************************************************
1017
* DirectXCloseSurface: close the YUV overlay or RGB surface.
1018
*****************************************************************************
1019
* This function returns all resources allocated for the surface.
1020
*****************************************************************************/
1021
void VideoOutputDX::DirectXCloseSurface()
1023
VERBOSE(VB_IMPORTANT, "DirectXCloseSurface");
1025
if (ccontrol != NULL)
1027
IDirectDrawColorControl_Release(ccontrol);
1031
if (front_surface != NULL)
1033
IDirectDrawSurface2_Release(front_surface);
1034
front_surface = NULL;
1039
/*****************************************************************************
1040
* NewPictureVec: allocate a vector of identical pictures
1041
*****************************************************************************
1042
* Returns 0 on success, -1 otherwise
1043
*****************************************************************************/
1044
int VideoOutputDX::NewPicture()
1048
LPDIRECTDRAWSURFACE2 p_surface;
1050
VERBOSE(VB_IMPORTANT, "NewPicture overlay");
1054
// using_overlay = true;
1055
overlay_3buf = true;
1057
/* First we try to use an YUV overlay surface.
1058
* The overlay surface that we create won't be used to decode directly
1059
* into it because accessing video memory directly is way to slow (remember
1060
* that pictures are decoded macroblock per macroblock). Instead the video
1061
* will be decoded in picture buffers in system memory which will then be
1062
* memcpy() to the overlay surface. */
1065
/* Triple buffering rocks! it doesn't have any processing overhead
1066
* (you don't have to wait for the vsync) and provides for a very nice
1067
* video quality (no tearing). */
1069
i_ret = DirectXCreateSurface(&p_surface, chroma, using_overlay,
1070
2 /* number of backbuffers */ );
1072
if (!overlay_3buf || i_ret != 0)
1074
/* Try to reduce the number of backbuffers */
1075
i_ret = DirectXCreateSurface(&p_surface, chroma, using_overlay,
1076
0 /* number of backbuffers */ );
1083
/* set front buffer */
1084
front_surface = p_surface;
1086
/* Get the back buffer */
1087
memset(&dds_caps, 0, sizeof( DDSCAPS));
1088
dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
1089
if (DD_OK != IDirectDrawSurface2_GetAttachedSurface(p_surface, &dds_caps, &back_surface))
1091
VERBOSE(VB_IMPORTANT, "NewPicture could not get back buffer");
1092
/* front buffer is the same as back buffer */
1093
back_surface = p_surface;
1096
DirectXUpdateOverlay();
1098
VERBOSE(VB_IMPORTANT, "YUV overlay created successfully");
1102
/* As we can't have an overlay, we'll try to create a plain offscreen
1103
* surface. This surface will reside in video memory because there's a
1104
* better chance then that we'll be able to use some kind of hardware
1105
* acceleration like rescaling, blitting or YUV->RGB conversions.
1106
* We then only need to blit this surface onto the main display when we
1107
* want to display it */
1108
if (!using_overlay )
1110
if (chroma != FOURCC_RGBX)
1114
bool b_result = false;
1116
bool is_rgb = ((chroma & 0xFF) == 'R');
1118
/* Check if the chroma is supported first. This is required
1119
* because a few buggy drivers don't mind creating the surface
1120
* even if they don't know about the chroma. */
1121
if (!is_rgb && IDirectDraw2_GetFourCCCodes(ddobject, &i_codes, NULL) == DD_OK)
1123
pi_codes = (DWORD*) malloc(i_codes * sizeof(DWORD));
1124
if (pi_codes && IDirectDraw2_GetFourCCCodes(ddobject, &i_codes, pi_codes) == DD_OK)
1126
for( i = 0; i < (int)i_codes; i++ )
1128
if (chroma == pi_codes[i])
1137
if (is_rgb || b_result)
1138
i_ret = DirectXCreateSurface(&p_surface, chroma,
1140
0 /* no back buffers */ );
1144
/* Our last choice is to use a plain RGB surface */
1145
DDPIXELFORMAT ddpfPixelFormat;
1147
ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1148
IDirectDrawSurface2_GetPixelFormat(display, &ddpfPixelFormat);
1150
if (ddpfPixelFormat.dwFlags & DDPF_RGB)
1152
switch(ddpfPixelFormat.dwRGBBitCount)
1154
// case 8: /* FIXME: set the palette */
1155
// chroma = FOURCC_RGB2;
1158
chroma = FOURCC_RV15;
1161
chroma = FOURCC_RV16;
1164
chroma = FOURCC_RV24;
1167
chroma = FOURCC_RV32;
1170
VERBOSE(VB_IMPORTANT, "unknown screen depth");
1177
i_ret = DirectXCreateSurface(&p_surface, chroma,
1179
0 /* no back buffers */);
1185
/* Allocate internal structure */
1187
front_surface = back_surface = p_surface;
1191
VERBOSE(VB_IMPORTANT, "created plain surface");
1195
if (outputpictures) {
1196
/* Now that we've got all our direct-buffers, we can finish filling in the
1197
* picture_t structures */
1198
if (DirectXLockSurface(NULL, NULL) != 0)
1202
VERBOSE(VB_IMPORTANT, "cannot lock surface");
1205
DirectXUnlockSurface();
1208
VERBOSE(VB_IMPORTANT, "End NewPictureVec (" <<
1209
(outputpictures ? "succeeded" : "failed") << ")");
1214
/*****************************************************************************
1215
* DirectXGetDDrawCaps: Probe the capabilities of the hardware
1216
*****************************************************************************
1217
* It is nice to know which features are supported by the hardware so we can
1218
* find ways to optimize our rendering.
1219
*****************************************************************************/
1220
void VideoOutputDX::DirectXGetDDrawCaps()
1225
/* This is just an indication of whether or not we'll support overlay,
1226
* but with this test we don't know if we support YUV overlay */
1227
memset(&ddcaps, 0, sizeof(DDCAPS));
1228
ddcaps.dwSize = sizeof(DDCAPS);
1229
dxresult = IDirectDraw2_GetCaps(ddobject, &ddcaps, NULL);
1230
if (dxresult != DD_OK )
1232
VERBOSE(VB_IMPORTANT, "cannot get caps");
1236
BOOL bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
1237
bHasColorKey, bCanStretch, bCanBltFourcc;
1239
/* Determine if the hardware supports overlay surfaces */
1240
bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
1241
DDCAPS_OVERLAY) ? TRUE : FALSE;
1242
/* Determine if the hardware supports overlay surfaces */
1243
bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ==
1244
DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE;
1245
/* Determine if the hardware supports overlay deinterlacing */
1246
bCanDeinterlace = ((ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN) ==
1248
/* Determine if the hardware supports colorkeying */
1249
bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
1250
DDCAPS_COLORKEY) ? TRUE : FALSE;
1251
/* Determine if the hardware supports scaling of the overlay surface */
1252
bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
1253
DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
1254
/* Determine if the hardware supports color conversion during a blit */
1255
bCanBltFourcc = ((ddcaps.dwCaps & DDCAPS_BLTFOURCC ) ==
1256
DDCAPS_BLTFOURCC) ? TRUE : FALSE;
1258
VERBOSE(VB_IMPORTANT, "DirectDraw Capabilities: overlay=" << bHasOverlay
1259
<< " yuvoverlay=" << bHasOverlayFourCC
1260
<< " can_deinterlace_overlay=" << bCanDeinterlace
1261
<< " colorkey=" << bHasColorKey
1262
<< " stretch=" << bCanStretch
1263
<< " bltfourcc=" << bCanBltFourcc);
1265
/* Don't ask for troubles */
1266
// if (!bCanBltFourcc) hw_yuv = true;
1270
/*****************************************************************************
1271
* DirectXFindColorkey: Finds out the 32bits RGB pixel value of the colorkey
1272
*****************************************************************************/
1273
DWORD VideoOutputDX::DirectXFindColorkey(uint32_t i_color)
1278
uint32_t i_pixel_backup;
1281
VERBOSE(VB_IMPORTANT, "determining colour key");
1283
ddsd.dwSize = sizeof(ddsd);
1284
dxresult = IDirectDrawSurface2_Lock(display, NULL, &ddsd, DDLOCK_WAIT, NULL );
1285
if (dxresult != DD_OK)
1287
VERBOSE(VB_IMPORTANT, "surface lock failed: 0x" << hex << dxresult << dec);
1291
VERBOSE(VB_IMPORTANT, "surface locked");
1293
i_pixel_backup = *(uint32_t *)ddsd.lpSurface;
1295
switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
1298
*(uint8_t *)ddsd.lpSurface = i_color;
1301
*(uint8_t *)ddsd.lpSurface = i_color;
1304
*(uint16_t *)ddsd.lpSurface = i_color;
1307
*(uint32_t *)ddsd.lpSurface = i_color;
1311
IDirectDrawSurface2_Unlock(display, NULL);
1313
VERBOSE(VB_IMPORTANT, "surface unlocked");
1315
if (IDirectDrawSurface2_GetDC(display, &hdc) == DD_OK )
1317
i_rgb = GetPixel(hdc, 0, 0);
1318
IDirectDrawSurface2_ReleaseDC(display, hdc);
1321
ddsd.dwSize = sizeof(ddsd);
1322
dxresult = IDirectDrawSurface2_Lock(display, NULL, &ddsd, DDLOCK_WAIT, NULL );
1323
if (dxresult != DD_OK )
1325
VERBOSE(VB_IMPORTANT, "surface lock failed: 0x" << hex << dxresult << dec);
1329
VERBOSE(VB_IMPORTANT, "surface locked");
1331
*(uint32_t *)ddsd.lpSurface = i_pixel_backup;
1333
IDirectDrawSurface2_Unlock(display, NULL);
1335
VERBOSE(VB_IMPORTANT, "surface unlocked");
1340
/*****************************************************************************
1341
* DirectXUpdateOverlay: Move or resize overlay surface on video display.
1342
*****************************************************************************
1343
* This function is used to move or resize an overlay surface on the screen.
1344
* Ususally the overlay is moved by the user and thus, by a move or resize
1345
* event (in Manage).
1346
*****************************************************************************/
1347
int VideoOutputDX::DirectXUpdateOverlay()
1353
/* Coordinates of src and dest images (used when blitting to display) */
1357
if (front_surface == NULL || !using_overlay )
1360
/* The new window dimensions should already have been computed by the
1361
* caller of this function */
1363
const QRect video_rect = windows[0].GetVideoRect();
1364
const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
1365
const QRect display_video_rect = windows[0].GetDisplayVideoRect();
1367
rect_src.left = video_rect.left();
1368
rect_src.right = video_rect.right();
1369
rect_src.top = video_rect.top();
1370
rect_src.bottom = video_rect.bottom();
1372
if (display_video_rect.left() < display_visible_rect.left() ||
1373
display_video_rect.right() > display_visible_rect.right())
1375
rect_dest.left = display_visible_rect.left();
1376
rect_dest.right = display_visible_rect.right();
1378
int diff_x = display_visible_rect.left();
1379
diff_x -= display_video_rect.left();
1380
int diff_w = display_video_rect.width();
1381
diff_x -= display_visible_rect.width();
1383
rect_src.left += (XJ_width * diff_x) / display_video_rect.width();
1384
rect_src.right -= ((XJ_width * (diff_w - diff_x)) /
1385
display_video_rect.width());
1389
rect_dest.left = display_video_rect.left();
1390
rect_dest.right = display_video_rect.right();
1393
if (display_video_rect.top() < display_visible_rect.top() ||
1394
display_video_rect.bottom() > display_visible_rect.bottom())
1396
rect_dest.top = display_visible_rect.top();
1397
rect_dest.bottom = display_visible_rect.bottom();
1399
int diff_y = display_visible_rect.top();
1400
diff_y -= display_video_rect.top();
1401
int diff_h = display_video_rect.height();
1402
diff_h -= display_visible_rect.height();
1404
rect_src.top += ((video_rect.width() * diff_y) /
1405
display_video_rect.height());
1407
rect_src.bottom -= (video_rect.height() * (diff_h - diff_y) /
1408
display_video_rect.height());
1412
rect_dest.top = display_video_rect.top();
1413
rect_dest.bottom = display_video_rect.bottom();
1416
VERBOSE(VB_IMPORTANT, "rect_src ("
1417
<< rect_src.left << "x"
1418
<< rect_src.top << ","
1419
<< rect_src.right << "x"
1420
<< rect_src.bottom << ")");
1422
VERBOSE(VB_IMPORTANT, "rect_dest ("
1423
<< rect_dest.left << "x"
1424
<< rect_dest.top << ","
1425
<< rect_dest.right << "x"
1426
<< rect_dest.bottom << ")");
1429
/* Position and show the overlay */
1430
memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1431
ddofx.dwSize = sizeof(DDOVERLAYFX);
1432
ddofx.dckDestColorkey.dwColorSpaceLowValue = colorkey;
1433
ddofx.dckDestColorkey.dwColorSpaceHighValue = colorkey;
1435
dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
1437
dxresult = IDirectDrawSurface2_UpdateOverlay(front_surface,
1442
if (dxresult != DD_OK)
1444
VERBOSE(VB_IMPORTANT,
1445
"DirectXUpdateOverlay cannot move or resize overlay: " << hex << dxresult << dec);
1452
/*****************************************************************************
1453
* DirectXLockSurface: Lock surface and get picture data pointer
1454
*****************************************************************************
1455
* This function locks a surface and get the surface descriptor which amongst
1456
* other things has the pointer to the picture data.
1457
*****************************************************************************/
1458
int VideoOutputDX::DirectXLockSurface(void **picbuf, int *stride)
1463
/* Lock the surface to get a valid pointer to the picture buffer */
1464
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
1465
ddsd.dwSize = sizeof(DDSURFACEDESC);
1466
dxresult = IDirectDrawSurface2_Lock(back_surface,
1468
DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1470
if (dxresult != DD_OK)
1472
if (dxresult == DDERR_INVALIDPARAMS)
1474
/* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
1475
* in an invalid params error */
1476
dxresult = IDirectDrawSurface2_Lock(back_surface, NULL,
1480
if (dxresult == DDERR_SURFACELOST)
1482
/* Your surface can be lost so be sure
1483
* to check this and restore it if needed */
1485
/* When using overlays with back-buffers, we need to restore
1486
* the front buffer so the back-buffers get restored as well. */
1488
IDirectDrawSurface2_Restore(front_surface);
1490
IDirectDrawSurface2_Restore(back_surface);
1492
dxresult = IDirectDrawSurface2_Lock(back_surface, NULL,
1495
if (dxresult == DDERR_SURFACELOST)
1496
VERBOSE(VB_IMPORTANT, "DirectXLockSurface: DDERR_SURFACELOST");
1498
if (dxresult != DD_OK)
1505
*picbuf = ddsd.lpSurface;
1508
*stride = ddsd.lPitch;
1513
/*****************************************************************************
1514
* DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
1515
*****************************************************************************/
1516
int VideoOutputDX::DirectXUnlockSurface()
1518
/* Unlock the Surface */
1519
if (IDirectDrawSurface2_Unlock(back_surface, NULL) == DD_OK)
1525
QStringList VideoOutputDX::GetAllowedRenderers(
1526
MythCodecID myth_codec_id, const QSize &video_dim)