~ubuntu-branches/ubuntu/lucid/mythtv/lucid

« back to all changes in this revision

Viewing changes to libs/libmythtv/videoout_dx.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2009-09-08 23:08:37 UTC
  • mfrom: (1.1.32 upstream)
  • Revision ID: james.westby@ubuntu.com-20090908230837-zrm2j6wutp76hwso
Tags: 0.22.0~trunk21742-0ubuntu1
* New upstream checkout (21742)
  - Fixes FTBFS on PPC. See changeset 21571 for more details.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <map>
2
 
#include <iostream>
3
 
#include <algorithm>
4
 
using namespace std;
5
 
 
6
 
#define _WIN32_WINNT 0x500
7
 
#include "mythcontext.h"
8
 
#include "videoout_dx.h"
9
 
#include "filtermanager.h"
10
 
#include "fourcc.h"
11
 
#include "videodisplayprofile.h"
12
 
#include "myth_imgconvert.h"
13
 
 
14
 
#include "mmsystem.h"
15
 
#include "tv.h"
16
 
 
17
 
#undef UNICODE
18
 
 
19
 
extern "C" {
20
 
#include "avcodec.h"
21
 
}
22
 
 
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;
28
 
 
29
 
/*****************************************************************************
30
 
 * DirectDraw GUIDs.
31
 
 * Defining them here allows us to get rid of the dxguid library during
32
 
 * the linking stage.
33
 
 *****************************************************************************/
34
 
#include <initguid.h>
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 );
38
 
 
39
 
 
40
 
VideoOutputDX::VideoOutputDX(void)
41
 
    : VideoOutput(), XJ_width(0), XJ_height(0)
42
 
{
43
 
    HMODULE user32;
44
 
 
45
 
    XJ_started = 0; 
46
 
 
47
 
    pauseFrame.buf = NULL;
48
 
    
49
 
    ddobject = NULL;
50
 
    display = NULL;
51
 
    display_driver = NULL;
52
 
//    current_surface = NULL;
53
 
    clipper = NULL;
54
 
    ccontrol = NULL;
55
 
    wnd = NULL;
56
 
    
57
 
//    hw_yuv = true;
58
 
    using_overlay = true;
59
 
    overlay_3buf = true;
60
 
    use_sysmem = false;
61
 
    
62
 
    front_surface = NULL;
63
 
    back_surface = NULL;
64
 
 
65
 
    /* Multimonitor stuff */
66
 
    monitor = NULL;
67
 
    display_driver = NULL;
68
 
    MonitorFromWindow = NULL;
69
 
    GetMonitorInfo = NULL;
70
 
    if ((user32 = GetModuleHandle("USER32")))
71
 
    {
72
 
        MonitorFromWindow = (HMONITOR (WINAPI*)(HWND, DWORD))
73
 
            GetProcAddress(user32, "MonitorFromWindow");
74
 
        GetMonitorInfo = (BOOL (WINAPI*)(HMONITOR, LPMONITORINFO))
75
 
            GetProcAddress(user32, "GetMonitorInfoA");
76
 
    }
77
 
}
78
 
 
79
 
VideoOutputDX::~VideoOutputDX()
80
 
{
81
 
    if (pauseFrame.buf)
82
 
        delete [] pauseFrame.buf;
83
 
 
84
 
    DirectXCloseSurface();
85
 
    DirectXCloseDisplay();
86
 
    DirectXCloseDDraw();
87
 
 
88
 
    Exit();
89
 
}
90
 
 
91
 
// this is documented in videooutbase.cpp
92
 
void VideoOutputDX::Zoom(ZoomDirection direction)
93
 
{
94
 
    VideoOutput::Zoom(direction);
95
 
    MoveResize();
96
 
}
97
 
 
98
 
void VideoOutputDX::MoveResize()
99
 
{
100
 
    VideoOutput::MoveResize();
101
 
    
102
 
    DirectXUpdateOverlay();
103
 
}
104
 
 
105
 
bool VideoOutputDX::InputChanged(const QSize &input_size,
106
 
                                 float        aspect,
107
 
                                 MythCodecID  av_codec_id,
108
 
                                 void        *codec_private)
109
 
{
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)));
113
 
 
114
 
    VideoOutput::InputChanged(input_size, aspect, av_codec_id, codec_private);
115
 
 
116
 
    db_vdisp_profile->SetVideoRenderer("directx");
117
 
 
118
 
    const QSize video_dim = windows[0].GetVideoDim();
119
 
    XJ_width  = video_dim.width();
120
 
    XJ_height = video_dim.height();
121
 
 
122
 
    vbuffers.DeleteBuffers();
123
 
    
124
 
    DirectXCloseSurface();
125
 
    MakeSurface();
126
 
    
127
 
    bool ok = vbuffers.CreateBuffers(XJ_width, XJ_height);
128
 
    if (!ok)
129
 
    {
130
 
        VERBOSE(VB_IMPORTANT, "InputChanged(): Failed to recreate buffers");
131
 
        errorState = kError_Unknown;
132
 
    }
133
 
 
134
 
    if (pauseFrame.buf)
135
 
        delete [] pauseFrame.buf;
136
 
 
137
 
    if (ok)
138
 
    {
139
 
        MoveResize();
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;
146
 
    }
147
 
    return ok;
148
 
}
149
 
 
150
 
DisplayInfo VideoOutputDX::GetDisplayInfo(void)
151
 
{
152
 
    if (ddobject)
153
 
    {
154
 
        DWORD rate;
155
 
        IDirectDraw_GetMonitorFrequency(ddobject, &rate);
156
 
        return DisplayInfo(1000000 / rate);
157
 
    }
158
 
    return DisplayInfo();
159
 
}
160
 
 
161
 
void VideoOutputDX::WaitForVSync(void)
162
 
{
163
 
    if (!ddobject)
164
 
        return;
165
 
        
166
 
    IDirectDraw_WaitForVerticalBlank(ddobject, DDWAITVB_BLOCKBEGIN, NULL);
167
 
}
168
 
 
169
 
bool VideoOutputDX::Init(int width, int height, float aspect,
170
 
                           WId winid, int winx, int winy, int winw, 
171
 
                           int winh, WId embedid)
172
 
{
173
 
    db_vdisp_profile->SetVideoRenderer("directx");
174
 
 
175
 
    vbuffers.Init(kNumBuffers, true, kNeedFreeFrames, 
176
 
                  kPrebufferFramesNormal, kPrebufferFramesSmall, 
177
 
                  kKeepPrebuffer);
178
 
    VideoOutput::Init(width, height, aspect, winid,
179
 
                      winx, winy, winw, winh, embedid);
180
 
 
181
 
    wnd = winid;
182
 
 
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);
187
 
 
188
 
    vbuffers.CreateBuffers(XJ_width, XJ_height);
189
 
    MoveResize();
190
 
 
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)
195
 
    {
196
 
        VERBOSE(VB_IMPORTANT, "cannot initialize DirectDraw");
197
 
        return false;
198
 
    }
199
 
 
200
 
    /* Create the directx display */
201
 
    if (!display && DirectXCreateDisplay() != 0)
202
 
    {
203
 
        VERBOSE(VB_IMPORTANT, "cannot initialize DirectDraw");
204
 
        return false;
205
 
    }
206
 
 
207
 
    MakeSurface();
208
 
 
209
 
    if (!outputpictures)
210
 
        return false;
211
 
 
212
 
    InitPictureAttributes();
213
 
 
214
 
    MoveResize();
215
 
 
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;
222
 
    
223
 
    XJ_started = true;
224
 
 
225
 
    return true;
226
 
}
227
 
 
228
 
void VideoOutputDX::Exit(void)
229
 
{
230
 
    if (XJ_started) 
231
 
    {
232
 
        XJ_started = false;
233
 
 
234
 
        vbuffers.DeleteBuffers();
235
 
    }
236
 
}
237
 
 
238
 
void VideoOutputDX::EmbedInWidget(WId wid, int x, int y, int w, 
239
 
                                    int h)
240
 
{
241
 
    if (windows[0].IsEmbedding())
242
 
        return;
243
 
 
244
 
    VideoOutput::EmbedInWidget(x, y, w, h);
245
 
}
246
 
 
247
 
void VideoOutputDX::StopEmbedding(void)
248
 
{
249
 
    if (!windows[0].IsEmbedding())
250
 
        return;
251
 
 
252
 
    VideoOutput::StopEmbedding();
253
 
}
254
 
 
255
 
void VideoOutputDX::PrepareFrame(VideoFrame *buffer, FrameScanType t)
256
 
{
257
 
    if (IsErrored())
258
 
    {
259
 
        VERBOSE(VB_IMPORTANT, "VideoOutputDX::PrepareFrame() called while IsErrored is true.");
260
 
        return;
261
 
    }
262
 
 
263
 
    unsigned char *picbuf;
264
 
    int stride;
265
 
    
266
 
    if (!buffer)
267
 
        buffer = vbuffers.GetScratchFrame();
268
 
 
269
 
    framesPlayed = buffer->frameNumber + 1;
270
 
 
271
 
    if (DirectXLockSurface((void**) &picbuf, &stride) == 0)
272
 
    {
273
 
        if (chroma == FOURCC_IYUV || chroma == FOURCC_I420)
274
 
        {
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),
280
 
                        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),
284
 
                        XJ_width / 2);
285
 
        }
286
 
        else if (chroma == FOURCC_YV12)
287
 
        {
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),
293
 
                        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),
297
 
                        XJ_width / 2);
298
 
        } else {
299
 
        
300
 
            AVPicture image_in, image_out;
301
 
            PixelFormat av_format;
302
 
 
303
 
            switch (chroma)
304
 
            {
305
 
                case FOURCC_YUY2:
306
 
                case FOURCC_YUYV:
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;
312
 
                default: 
313
 
                    VERBOSE(VB_IMPORTANT, "VODX: Non Xv mode only supports 16, 24, and 32 bpp displays");
314
 
                    errorState = kError_Unknown;
315
 
                    return;
316
 
            }
317
 
            
318
 
            avpicture_fill(&image_out, picbuf, av_format, XJ_width, XJ_height);
319
 
            image_out.linesize[0] = stride;
320
 
 
321
 
            avpicture_fill(&image_in, buffer->buf, PIX_FMT_YUV420P, XJ_width, XJ_height);
322
 
 
323
 
            myth_sws_img_convert(
324
 
                &image_out, av_format, &image_in, PIX_FMT_YUV420P,
325
 
                XJ_width, XJ_height);
326
 
 
327
 
        }
328
 
    
329
 
        DirectXUnlockSurface();
330
 
    }
331
 
    else
332
 
        VERBOSE(VB_IMPORTANT, "Could not lock surface!");    
333
 
}
334
 
 
335
 
void VideoOutputDX::Show(FrameScanType )
336
 
{
337
 
    HRESULT dxresult;
338
 
 
339
 
    if (IsErrored())
340
 
    {
341
 
        VERBOSE(VB_IMPORTANT, "VideoOutputDX::Show() called while IsErrored istrue.");
342
 
        return;
343
 
    }
344
 
 
345
 
    if ((display == NULL))
346
 
    {
347
 
        VERBOSE(VB_IMPORTANT, "no display!!");
348
 
        return;
349
 
    }
350
 
 
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)
354
 
    {
355
 
        if (IDirectDrawSurface2_Restore(display) == DD_OK && using_overlay)
356
 
            DirectXUpdateOverlay();
357
 
    }
358
 
 
359
 
    if (!using_overlay)
360
 
    {
361
 
        DDBLTFX ddbltfx;
362
 
        RECT rect_src;
363
 
        RECT rect_dest;
364
 
 
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();
368
 
 
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;
373
 
 
374
 
        if (display_video_rect.left()  < display_visible_rect.left() ||
375
 
            display_video_rect.right() > display_visible_rect.right())
376
 
        {
377
 
            rect_dest.left   = display_visible_rect.left();
378
 
            rect_dest.right  = display_visible_rect.right();
379
 
 
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();
384
 
 
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());
388
 
        }
389
 
        else
390
 
        {
391
 
            rect_dest.left  = display_video_rect.left();
392
 
            rect_dest.right = display_video_rect.right();
393
 
        }
394
 
 
395
 
        if (display_video_rect.top()    < display_visible_rect.top() ||
396
 
            display_video_rect.bottom() > display_visible_rect.bottom())
397
 
        {
398
 
            rect_dest.top    = display_visible_rect.top();
399
 
            rect_dest.bottom = display_visible_rect.bottom();
400
 
 
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();
405
 
 
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());
409
 
        }
410
 
        else
411
 
        {
412
 
            rect_dest.top    = display_video_rect.top();
413
 
            rect_dest.bottom = display_video_rect.bottom();
414
 
        }
415
 
 
416
 
        /* We ask for the "NOTEARING" option */
417
 
        memset(&ddbltfx, 0, sizeof(DDBLTFX));
418
 
        ddbltfx.dwSize = sizeof(DDBLTFX);
419
 
        ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
420
 
 
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)
425
 
        {
426
 
            VERBOSE(VB_IMPORTANT, "could not blit surface (error " << hex << dxresult << dec << ")");
427
 
            return;
428
 
        }
429
 
 
430
 
    }
431
 
    else /* using overlay */
432
 
    {
433
 
        /* Flip the overlay buffers if we are using back buffers */
434
 
        if (front_surface == back_surface)
435
 
        {
436
 
            return;
437
 
        }
438
 
 
439
 
        dxresult = IDirectDrawSurface2_Flip(front_surface, NULL, DDFLIP_WAIT);
440
 
        if (dxresult != DD_OK)
441
 
        {
442
 
            VERBOSE(VB_IMPORTANT, "could not flip overlay (error " << hex << dxresult << dec << ")");
443
 
        }
444
 
 
445
 
        /* set currently displayed pic */
446
 
        //p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
447
 
 
448
 
    }
449
 
}
450
 
 
451
 
void VideoOutputDX::DrawUnusedRects(bool)
452
 
{
453
 
}
454
 
 
455
 
void VideoOutputDX::UpdatePauseFrame(void)
456
 
{
457
 
    VideoFrame *pauseb = vbuffers.GetScratchFrame();
458
 
    VideoFrame *pauseu = vbuffers.head(kVideoBuffer_used);
459
 
    if (pauseu)
460
 
        memcpy(pauseFrame.buf, pauseu->buf, pauseu->size);
461
 
    else
462
 
        memcpy(pauseFrame.buf, pauseb->buf, pauseb->size);
463
 
}
464
 
 
465
 
void VideoOutputDX::ProcessFrame(VideoFrame *frame, OSD *osd,
466
 
                                 FilterChain *filterList,
467
 
                                 const PIPMap &pipPlayers,
468
 
                                 FrameScanType scan)
469
 
{
470
 
    if (IsErrored())
471
 
    {
472
 
        VERBOSE(VB_IMPORTANT, "VideoOutputDX::ProcessFrame() called while IsErrored is true.");
473
 
        return;
474
 
    }
475
 
 
476
 
    if (!frame)
477
 
    {
478
 
        frame = vbuffers.GetScratchFrame();
479
 
        CopyFrame(vbuffers.GetScratchFrame(), &pauseFrame);
480
 
    }
481
 
 
482
 
    if (m_deinterlacing && m_deintFilter != NULL)
483
 
        m_deintFilter->ProcessFrame(frame, scan);
484
 
    if (filterList)
485
 
        filterList->ProcessFrame(frame);
486
 
 
487
 
    ShowPIPs(frame, pipPlayers);
488
 
    DisplayOSD(frame, osd);
489
 
}
490
 
 
491
 
// this is documented in videooutbase.cpp
492
 
int VideoOutputDX::SetPictureAttribute(
493
 
    PictureAttribute attribute, int newValue)
494
 
{
495
 
    if (ccontrol == NULL)
496
 
        return -1;
497
 
        
498
 
    newValue = min(max(newValue, 0), 100);
499
 
        
500
 
    DDCOLORCONTROL ddcc;
501
 
    memset(&ddcc, 0, sizeof(DDCOLORCONTROL));
502
 
    ddcc.dwSize = sizeof(DDCOLORCONTROL);
503
 
        
504
 
    switch (attribute)
505
 
    {
506
 
        case kPictureAttribute_Brightness:
507
 
            ddcc.dwFlags = DDCOLOR_BRIGHTNESS;
508
 
            ddcc.lBrightness = (newValue * newValue * 17) / 10 - 70 * newValue;
509
 
            break;
510
 
        case kPictureAttribute_Contrast:
511
 
            ddcc.dwFlags = DDCOLOR_CONTRAST;
512
 
            ddcc.lContrast = newValue * 200;
513
 
            break;
514
 
        case kPictureAttribute_Colour:
515
 
            ddcc.dwFlags = DDCOLOR_SATURATION;
516
 
            ddcc.lSaturation = newValue * 200;
517
 
            break;
518
 
        case kPictureAttribute_Hue:
519
 
            ddcc.dwFlags = DDCOLOR_HUE;
520
 
            ddcc.lHue = newValue * 36 / 10;
521
 
            if (ddcc.lHue > 180)
522
 
                ddcc.lHue -= 361;
523
 
            break;
524
 
    }
525
 
    
526
 
    HRESULT dxresult;
527
 
    
528
 
    dxresult = IDirectDrawColorControl_SetColorControls(ccontrol, &ddcc);
529
 
    
530
 
    if (dxresult != DD_OK)
531
 
    {
532
 
        VERBOSE(VB_IMPORTANT, "Could not update colour controls: "
533
 
                << hex << dxresult << dec);
534
 
        return -1;
535
 
    }
536
 
 
537
 
    SetPictureAttributeDBValue(attribute, newValue);
538
 
    
539
 
    return newValue;
540
 
}
541
 
 
542
 
float VideoOutputDX::GetDisplayAspect(void) const
543
 
{
544
 
    const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
545
 
    float width  = display_visible_rect.width();
546
 
    float height = display_visible_rect.height();
547
 
 
548
 
    if (height <= 0.0001f)
549
 
        return 4.0f / 3.0f;
550
 
 
551
 
    return width / height;
552
 
}
553
 
 
554
 
static const DWORD pref_chromas[] = { FOURCC_IYUV,
555
 
                                      FOURCC_I420,
556
 
                                      FOURCC_YV12,
557
 
//                                      FOURCC_UYVY,
558
 
//                                      FOURCC_UYNV,
559
 
//                                      FOURCC_Y422,
560
 
                                      FOURCC_YUY2,
561
 
                                      FOURCC_YUYV,
562
 
                                      FOURCC_YUNV,
563
 
//                                      FOURCC_YVYU,
564
 
                                      FOURCC_RGBX,
565
 
                                        0xFFFFFFFF };
566
 
 
567
 
void VideoOutputDX::MakeSurface()
568
 
{
569
 
    outputpictures = 0;
570
 
    
571
 
    if (using_overlay)
572
 
    {
573
 
        for (int i = 0; !outputpictures && (pref_chromas[i] != 0xFFFFFFFF); i++)
574
 
        {
575
 
            chroma = pref_chromas[i];
576
 
 
577
 
            NewPicture();
578
 
        }
579
 
    }
580
 
 
581
 
    if (!outputpictures)
582
 
    {
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++)
586
 
        {
587
 
            chroma = pref_chromas[i];
588
 
 
589
 
            NewPicture();
590
 
        }
591
 
    }
592
 
    
593
 
    if (!outputpictures)
594
 
    {
595
 
        /* If it _still_ didn't work then don't try to use vidmem */
596
 
        use_sysmem = true;
597
 
        for (int i = 0; !outputpictures && (pref_chromas[i] != 0xFFFFFFFF); i++)
598
 
        {
599
 
            chroma = pref_chromas[i];
600
 
 
601
 
            NewPicture();
602
 
        }
603
 
    }
604
 
}
605
 
 
606
 
 
607
 
 
608
 
 
609
 
typedef HRESULT (WINAPI *LPFNDDC)(GUID *,LPDIRECTDRAW *,IUnknown *);
610
 
typedef HRESULT (WINAPI *LPFNDDEE)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
611
 
 
612
 
 
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()
619
 
{
620
 
    HRESULT dxresult;
621
 
    LPFNDDC OurDirectDrawCreate;
622
 
    LPFNDDEE OurDirectDrawEnumerateEx;
623
 
    LPDIRECTDRAW p_ddobject;
624
 
 
625
 
    VERBOSE(VB_IMPORTANT, "DirectXInitDDraw");
626
 
 
627
 
    /* Load direct draw DLL */
628
 
    ddraw_dll = LoadLibrary("DDRAW.DLL");
629
 
    if (ddraw_dll == NULL)
630
 
    {
631
 
        VERBOSE(VB_IMPORTANT, "DirectXInitDDraw failed loading ddraw.dll");
632
 
        goto error;
633
 
    }
634
 
 
635
 
    OurDirectDrawCreate =
636
 
      (LPFNDDC)GetProcAddress(ddraw_dll, "DirectDrawCreate");
637
 
    if (OurDirectDrawCreate == NULL )
638
 
    {
639
 
        VERBOSE(VB_IMPORTANT, "DirectXInitDDraw failed GetProcAddress");
640
 
        goto error;
641
 
    }
642
 
 
643
 
    OurDirectDrawEnumerateEx =
644
 
      (LPFNDDEE)GetProcAddress(ddraw_dll, "DirectDrawEnumerateExA");
645
 
 
646
 
    if (OurDirectDrawEnumerateEx && MonitorFromWindow )
647
 
    {
648
 
        monitor = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);
649
 
 
650
 
        /* Enumerate displays * /
651
 
        OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout, 
652
 
                                  DDENUM_ATTACHEDSECONDARYDEVICES );*/
653
 
    }
654
 
 
655
 
    /* Initialize DirectDraw now */
656
 
    dxresult = OurDirectDrawCreate(display_driver, &p_ddobject, NULL);
657
 
    if (dxresult != DD_OK)
658
 
    {
659
 
        VERBOSE(VB_IMPORTANT, "DirectXInitDDraw cannot initialize DDraw");
660
 
        goto error;
661
 
    }
662
 
 
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)
668
 
    {
669
 
        VERBOSE(VB_IMPORTANT, "cannot get IDirectDraw2 interface" );
670
 
        goto error;
671
 
    }
672
 
 
673
 
    /* Set DirectDraw Cooperative level, ie what control we want over Windows
674
 
     * display */
675
 
    dxresult = IDirectDraw2_SetCooperativeLevel(ddobject, wnd, DDSCL_NORMAL);
676
 
    if (dxresult != DD_OK)
677
 
    {
678
 
        VERBOSE(VB_IMPORTANT, "cannot set direct draw cooperative level");
679
 
        goto error;
680
 
    }
681
 
 
682
 
    /* Get the size of the current display device */
683
 
    if (monitor && GetMonitorInfo)
684
 
    {
685
 
        MONITORINFO monitor_info;
686
 
        monitor_info.cbSize = sizeof(MONITORINFO);
687
 
        GetMonitorInfo(monitor, &monitor_info);
688
 
        rect_display = monitor_info.rcMonitor;
689
 
    }
690
 
    else
691
 
    {
692
 
        rect_display.left = 0;
693
 
        rect_display.top = 0;
694
 
        rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
695
 
        rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
696
 
    }
697
 
 
698
 
    VERBOSE(VB_IMPORTANT, "screen dimensions ("
699
 
              << rect_display.left << "x"
700
 
              << rect_display.top << ","
701
 
              << rect_display.right << "x"
702
 
              << rect_display.bottom << ")");
703
 
 
704
 
    /* Probe the capabilities of the hardware */
705
 
    DirectXGetDDrawCaps();
706
 
 
707
 
    VERBOSE(VB_IMPORTANT, "End DirectXInitDDraw");
708
 
    return 0;
709
 
 
710
 
 error:
711
 
    if (ddobject)
712
 
        IDirectDraw2_Release(ddobject);
713
 
    if (ddraw_dll)
714
 
        FreeLibrary(ddraw_dll);
715
 
    ddraw_dll = NULL;
716
 
    ddobject = NULL;
717
 
    return -1;
718
 
}
719
 
 
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()
729
 
{
730
 
    HRESULT dxresult;
731
 
 
732
 
    VERBOSE(VB_IMPORTANT, "DirectXCreateClipper");
733
 
 
734
 
    /* Create the clipper */
735
 
    dxresult = IDirectDraw2_CreateClipper(ddobject, 0, &clipper, NULL);
736
 
    if (dxresult != DD_OK)
737
 
    {
738
 
        VERBOSE(VB_IMPORTANT, "cannot create clipper (error " << hex << dxresult << dec << ")");
739
 
        goto error;
740
 
    }
741
 
 
742
 
    /* Associate the clipper to the window */
743
 
    dxresult = IDirectDrawClipper_SetHWnd(clipper, 0, wnd);
744
 
    if (dxresult != DD_OK)
745
 
    {
746
 
        VERBOSE(VB_IMPORTANT, "cannot attach clipper to window (error " << hex << dxresult << dec << ")");
747
 
        goto error;
748
 
    }
749
 
 
750
 
    /* associate the clipper with the surface */
751
 
    dxresult = IDirectDrawSurface_SetClipper(display, clipper);
752
 
    if (dxresult != DD_OK)
753
 
    {
754
 
        VERBOSE(VB_IMPORTANT, "cannot attach clipper to surface (error " << hex << dxresult << dec << ")");
755
 
        goto error;
756
 
    }
757
 
 
758
 
    return 0;
759
 
 
760
 
 error:
761
 
    if (clipper)
762
 
    {
763
 
        IDirectDrawClipper_Release(clipper);
764
 
    }
765
 
    clipper = NULL;
766
 
    return -1;
767
 
}
768
 
 
769
 
/*****************************************************************************
770
 
 * DirectXCreateDisplay: create the DirectDraw display.
771
 
 *****************************************************************************
772
 
 * Create and initialize display according to preferences specified in the vout
773
 
 * thread fields.
774
 
 *****************************************************************************/
775
 
int VideoOutputDX::DirectXCreateDisplay()
776
 
{
777
 
    HRESULT              dxresult;
778
 
    DDSURFACEDESC        ddsd;
779
 
    LPDIRECTDRAWSURFACE  p_display;
780
 
 
781
 
    VERBOSE(VB_IMPORTANT, "DirectXCreateDisplay");
782
 
 
783
 
    /* Now get the primary surface. This surface is what you actually see
784
 
     * on your screen */
785
 
    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
786
 
    ddsd.dwSize = sizeof(DDSURFACEDESC);
787
 
    ddsd.dwFlags = DDSD_CAPS;
788
 
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
789
 
 
790
 
    dxresult = IDirectDraw2_CreateSurface(ddobject, &ddsd, &p_display, NULL );
791
 
    if (dxresult != DD_OK)
792
 
    {
793
 
        VERBOSE(VB_IMPORTANT, "cannot get primary surface (error %li)" << dxresult);
794
 
        return -1;
795
 
    }
796
 
 
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)
801
 
    {
802
 
        VERBOSE(VB_IMPORTANT, "cannot query IDirectDrawSurface2 interface " <<
803
 
                         "(error %li)" << dxresult);
804
 
        return -1;
805
 
    }
806
 
 
807
 
    /* The clipper will be used only in non-overlay mode */
808
 
    DirectXCreateClipper();
809
 
 
810
 
    /* Make sure the colorkey will be painted */
811
 
    colorkey = 0;
812
 
    rgb_colorkey = DirectXFindColorkey(colorkey);
813
 
 
814
 
    VERBOSE(VB_IMPORTANT, "colour key = " << hex << rgb_colorkey << dec);
815
 
 
816
 
    VERBOSE(VB_IMPORTANT, "brushing");
817
 
 
818
 
    /* Create the actual brush */
819
 
    SetClassLong(wnd, GCL_HBRBACKGROUND,
820
 
                  (LONG)CreateSolidBrush(rgb_colorkey));
821
 
    InvalidateRect(wnd, NULL, TRUE);
822
 
    //DirectXUpdateRects(true);
823
 
 
824
 
    VERBOSE(VB_IMPORTANT, "display created");
825
 
 
826
 
    return 0;
827
 
}
828
 
 
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)
841
 
{
842
 
    HRESULT dxresult;
843
 
    LPDIRECTDRAWSURFACE p_surface;
844
 
    DDSURFACEDESC ddsd;
845
 
 
846
 
    /* Create the video surface */
847
 
    if (b_overlay)
848
 
    {
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 */
856
 
 
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;
869
 
    }
870
 
    else  // !b_overlay
871
 
    {
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);
875
 
 
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;
883
 
 
884
 
        if (use_sysmem)
885
 
            ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
886
 
        else
887
 
            ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
888
 
 
889
 
        if (!b_rgb_surface)
890
 
        {
891
 
            ddsd.dwFlags |= DDSD_PIXELFORMAT;
892
 
            ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
893
 
            ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
894
 
        }
895
 
    }
896
 
 
897
 
    VERBOSE(VB_IMPORTANT, "VideoOutputDX::DirectXCreateSurface() x: "
898
 
                          << XJ_width << " y: " << XJ_height
899
 
                          << " chrom: " << fourcc_str(i_chroma));
900
 
 
901
 
    dxresult = IDirectDraw2_CreateSurface(ddobject, &ddsd, &p_surface, NULL );
902
 
    if (dxresult != DD_OK )
903
 
    {
904
 
        VERBOSE(VB_IMPORTANT, "DD_CreateSurface failed " << hex << dxresult << dec);
905
 
        *pp_surface_final = NULL;
906
 
        return -1;
907
 
    }
908
 
 
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)
913
 
    {
914
 
        VERBOSE(VB_IMPORTANT, "cannot query IDirectDrawSurface2 interface " <<
915
 
                         "(error " << hex << dxresult << dec << ")");
916
 
        *pp_surface_final = NULL;
917
 
        return -1;
918
 
    }
919
 
 
920
 
    if (b_overlay)
921
 
    {
922
 
        back_surface = *pp_surface_final;
923
 
 
924
 
        /* Reset the front buffer memory */
925
 
        char *picbuf;
926
 
        int stride;
927
 
        // TODO: fix
928
 
        if (DirectXLockSurface((void **) &picbuf, &stride) == DD_OK)
929
 
        {
930
 
            memset(picbuf, 127, stride * XJ_height * 3 / 2);
931
 
 
932
 
            DirectXUnlockSurface();
933
 
        }
934
 
 
935
 
        back_surface = NULL;
936
 
 
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)
941
 
        {
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)" );
946
 
            return -1;
947
 
        }
948
 
    }
949
 
 
950
 
    /* Get the IDirectDraw2 interface */
951
 
    dxresult = IDirectDraw_QueryInterface(*pp_surface_final, IID_IDirectDrawColorControl, (LPVOID *) &ccontrol);
952
 
    if (dxresult != DD_OK)
953
 
    {
954
 
        VERBOSE(VB_IMPORTANT, "cannot get colour control interface" );
955
 
        ccontrol = NULL;
956
 
    }
957
 
 
958
 
    return 0;
959
 
}
960
 
 
961
 
 
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()
968
 
{
969
 
    VERBOSE(VB_IMPORTANT, "DirectXCloseDDraw");
970
 
    if (ddobject != NULL)
971
 
    {
972
 
        IDirectDraw2_Release(ddobject);
973
 
        ddobject = NULL;
974
 
    }
975
 
 
976
 
    if (ddraw_dll != NULL)
977
 
    {
978
 
        FreeLibrary(ddraw_dll);
979
 
        ddraw_dll = NULL;
980
 
    }
981
 
 
982
 
    if (display_driver != NULL)
983
 
    {
984
 
        free(display_driver);
985
 
        display_driver = NULL;
986
 
    }
987
 
 
988
 
    monitor = NULL;
989
 
}
990
 
 
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()
997
 
{
998
 
    VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay");
999
 
 
1000
 
    if (clipper != NULL)
1001
 
    {
1002
 
        VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay clipper");
1003
 
        IDirectDrawClipper_Release(clipper);
1004
 
        clipper = NULL;
1005
 
    }
1006
 
 
1007
 
    if (display != NULL)
1008
 
    {
1009
 
        VERBOSE(VB_IMPORTANT, "DirectXCloseDisplay display");
1010
 
        IDirectDrawSurface2_Release(display);
1011
 
        display = NULL;
1012
 
    }
1013
 
}
1014
 
 
1015
 
 
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()
1022
 
{
1023
 
    VERBOSE(VB_IMPORTANT, "DirectXCloseSurface");
1024
 
    
1025
 
    if (ccontrol != NULL)
1026
 
    {
1027
 
        IDirectDrawColorControl_Release(ccontrol);
1028
 
        ccontrol = NULL;
1029
 
    }
1030
 
    
1031
 
    if (front_surface != NULL)
1032
 
    {
1033
 
        IDirectDrawSurface2_Release(front_surface);
1034
 
        front_surface = NULL;
1035
 
    }
1036
 
}
1037
 
 
1038
 
 
1039
 
/*****************************************************************************
1040
 
 * NewPictureVec: allocate a vector of identical pictures
1041
 
 *****************************************************************************
1042
 
 * Returns 0 on success, -1 otherwise
1043
 
 *****************************************************************************/
1044
 
int VideoOutputDX::NewPicture()
1045
 
{
1046
 
    int i;
1047
 
    int i_ret = -1;
1048
 
    LPDIRECTDRAWSURFACE2 p_surface;
1049
 
 
1050
 
    VERBOSE(VB_IMPORTANT, "NewPicture overlay");
1051
 
 
1052
 
    outputpictures = 0;
1053
 
 
1054
 
//    using_overlay = true;
1055
 
    overlay_3buf = true;
1056
 
 
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. */
1063
 
    if (using_overlay)
1064
 
    {
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). */
1068
 
        if (overlay_3buf)
1069
 
            i_ret = DirectXCreateSurface(&p_surface, chroma, using_overlay,
1070
 
                                          2 /* number of backbuffers */ );
1071
 
 
1072
 
        if (!overlay_3buf || i_ret != 0)
1073
 
        {
1074
 
            /* Try to reduce the number of backbuffers */
1075
 
            i_ret = DirectXCreateSurface(&p_surface, chroma, using_overlay,
1076
 
                                          0 /* number of backbuffers */ );
1077
 
        }
1078
 
 
1079
 
        if (i_ret == 0)
1080
 
        {
1081
 
            DDSCAPS dds_caps;
1082
 
 
1083
 
            /* set front buffer */
1084
 
            front_surface = p_surface;
1085
 
 
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))
1090
 
            {
1091
 
                VERBOSE(VB_IMPORTANT, "NewPicture could not get back buffer");
1092
 
                /* front buffer is the same as back buffer */
1093
 
                back_surface = p_surface;
1094
 
            }
1095
 
 
1096
 
            DirectXUpdateOverlay();
1097
 
            outputpictures = 1;
1098
 
            VERBOSE(VB_IMPORTANT, "YUV overlay created successfully");
1099
 
        }
1100
 
    }
1101
 
 
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 )
1109
 
    {
1110
 
        if (chroma != FOURCC_RGBX)
1111
 
        {
1112
 
            DWORD i_codes;
1113
 
            DWORD *pi_codes;
1114
 
            bool b_result = false;
1115
 
 
1116
 
            bool is_rgb = ((chroma & 0xFF) == 'R');
1117
 
 
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)
1122
 
            {
1123
 
                pi_codes = (DWORD*) malloc(i_codes * sizeof(DWORD));
1124
 
                if (pi_codes && IDirectDraw2_GetFourCCCodes(ddobject, &i_codes, pi_codes) == DD_OK)
1125
 
                {
1126
 
                    for( i = 0; i < (int)i_codes; i++ )
1127
 
                    {
1128
 
                        if (chroma == pi_codes[i])
1129
 
                        {
1130
 
                            b_result = true;
1131
 
                            break;
1132
 
                        }
1133
 
                    }
1134
 
                }
1135
 
            }
1136
 
 
1137
 
            if (is_rgb || b_result)
1138
 
                i_ret = DirectXCreateSurface(&p_surface, chroma,
1139
 
                                              0 /* no overlay */,
1140
 
                                              0 /* no back buffers */ );
1141
 
        }
1142
 
        else
1143
 
        {
1144
 
            /* Our last choice is to use a plain RGB surface */
1145
 
            DDPIXELFORMAT ddpfPixelFormat;
1146
 
 
1147
 
            ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1148
 
            IDirectDrawSurface2_GetPixelFormat(display, &ddpfPixelFormat);
1149
 
 
1150
 
            if (ddpfPixelFormat.dwFlags & DDPF_RGB)
1151
 
            {
1152
 
                switch(ddpfPixelFormat.dwRGBBitCount)
1153
 
                {
1154
 
//                case 8: /* FIXME: set the palette */
1155
 
//                    chroma = FOURCC_RGB2;
1156
 
//                    break;
1157
 
                case 15:
1158
 
                    chroma = FOURCC_RV15;
1159
 
                    break;
1160
 
                case 16:
1161
 
                    chroma = FOURCC_RV16;
1162
 
                    break;
1163
 
                case 24:
1164
 
                    chroma = FOURCC_RV24;
1165
 
                    break;
1166
 
                case 32:
1167
 
                    chroma = FOURCC_RV32;
1168
 
                    break;
1169
 
                default:
1170
 
                    VERBOSE(VB_IMPORTANT, "unknown screen depth");
1171
 
                    return 0;
1172
 
                }
1173
 
            }
1174
 
 
1175
 
//            hw_yuv = false;
1176
 
 
1177
 
            i_ret = DirectXCreateSurface(&p_surface, chroma,
1178
 
                                          0 /* no overlay */,
1179
 
                                          0 /* no back buffers */);
1180
 
 
1181
 
        }
1182
 
 
1183
 
        if (i_ret == 0)
1184
 
        {
1185
 
            /* Allocate internal structure */
1186
 
 
1187
 
            front_surface = back_surface = p_surface;
1188
 
 
1189
 
            outputpictures = 1;
1190
 
 
1191
 
            VERBOSE(VB_IMPORTANT, "created plain surface");
1192
 
        }
1193
 
    }
1194
 
 
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)
1199
 
        {
1200
 
            /* AAARRGG */
1201
 
            outputpictures = 0;
1202
 
            VERBOSE(VB_IMPORTANT, "cannot lock surface");
1203
 
            return -1;
1204
 
        }
1205
 
        DirectXUnlockSurface();
1206
 
    }
1207
 
 
1208
 
    VERBOSE(VB_IMPORTANT, "End NewPictureVec (" <<
1209
 
             (outputpictures ? "succeeded" : "failed") << ")");
1210
 
 
1211
 
    return 0;
1212
 
}
1213
 
 
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()
1221
 
{
1222
 
    DDCAPS ddcaps;
1223
 
    HRESULT dxresult;
1224
 
 
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 )
1231
 
    {
1232
 
        VERBOSE(VB_IMPORTANT, "cannot get caps");
1233
 
    }
1234
 
    else
1235
 
    {
1236
 
        BOOL bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
1237
 
             bHasColorKey, bCanStretch, bCanBltFourcc;
1238
 
 
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) ==
1247
 
                       0 ) ? TRUE : FALSE;
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;
1257
 
 
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);
1264
 
 
1265
 
        /* Don't ask for troubles */
1266
 
//        if (!bCanBltFourcc) hw_yuv = true; 
1267
 
    }
1268
 
}
1269
 
 
1270
 
/*****************************************************************************
1271
 
 * DirectXFindColorkey: Finds out the 32bits RGB pixel value of the colorkey
1272
 
 *****************************************************************************/
1273
 
DWORD VideoOutputDX::DirectXFindColorkey(uint32_t i_color)
1274
 
{
1275
 
    DDSURFACEDESC ddsd;
1276
 
    HRESULT dxresult;
1277
 
    COLORREF i_rgb = 0;
1278
 
    uint32_t i_pixel_backup;
1279
 
    HDC hdc;
1280
 
 
1281
 
    VERBOSE(VB_IMPORTANT, "determining colour key");
1282
 
 
1283
 
    ddsd.dwSize = sizeof(ddsd);
1284
 
    dxresult = IDirectDrawSurface2_Lock(display, NULL, &ddsd, DDLOCK_WAIT, NULL );
1285
 
    if (dxresult != DD_OK)
1286
 
    {
1287
 
        VERBOSE(VB_IMPORTANT, "surface lock failed: 0x" << hex << dxresult << dec);
1288
 
        return 0;
1289
 
    }
1290
 
 
1291
 
    VERBOSE(VB_IMPORTANT, "surface locked");
1292
 
 
1293
 
    i_pixel_backup = *(uint32_t *)ddsd.lpSurface;
1294
 
 
1295
 
    switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
1296
 
    {
1297
 
    case 4:
1298
 
        *(uint8_t *)ddsd.lpSurface = i_color;
1299
 
        break;
1300
 
    case 8:
1301
 
        *(uint8_t *)ddsd.lpSurface = i_color;
1302
 
        break;
1303
 
    case 16:
1304
 
        *(uint16_t *)ddsd.lpSurface = i_color;
1305
 
        break;
1306
 
    default:
1307
 
        *(uint32_t *)ddsd.lpSurface = i_color;
1308
 
        break;
1309
 
    }
1310
 
 
1311
 
    IDirectDrawSurface2_Unlock(display, NULL);
1312
 
 
1313
 
    VERBOSE(VB_IMPORTANT, "surface unlocked");
1314
 
 
1315
 
    if (IDirectDrawSurface2_GetDC(display, &hdc) == DD_OK )
1316
 
    {
1317
 
        i_rgb = GetPixel(hdc, 0, 0);
1318
 
        IDirectDrawSurface2_ReleaseDC(display, hdc);
1319
 
    }
1320
 
 
1321
 
    ddsd.dwSize = sizeof(ddsd);
1322
 
    dxresult = IDirectDrawSurface2_Lock(display, NULL, &ddsd, DDLOCK_WAIT, NULL );
1323
 
    if (dxresult != DD_OK )
1324
 
    {
1325
 
        VERBOSE(VB_IMPORTANT, "surface lock failed: 0x" << hex << dxresult << dec);
1326
 
        return i_rgb;
1327
 
    }
1328
 
 
1329
 
    VERBOSE(VB_IMPORTANT, "surface locked");
1330
 
 
1331
 
    *(uint32_t *)ddsd.lpSurface = i_pixel_backup;
1332
 
 
1333
 
    IDirectDrawSurface2_Unlock(display, NULL);
1334
 
 
1335
 
    VERBOSE(VB_IMPORTANT, "surface unlocked");
1336
 
 
1337
 
    return i_rgb;
1338
 
}
1339
 
 
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()
1348
 
{
1349
 
    DDOVERLAYFX     ddofx;
1350
 
    DWORD           dwFlags;
1351
 
    HRESULT         dxresult;
1352
 
 
1353
 
    /* Coordinates of src and dest images (used when blitting to display) */
1354
 
    RECT         rect_src;
1355
 
    RECT         rect_dest;
1356
 
 
1357
 
    if (front_surface == NULL || !using_overlay )
1358
 
        return -1;
1359
 
 
1360
 
    /* The new window dimensions should already have been computed by the
1361
 
     * caller of this function */
1362
 
 
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();
1366
 
 
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();
1371
 
 
1372
 
    if (display_video_rect.left()  < display_visible_rect.left() ||
1373
 
        display_video_rect.right() > display_visible_rect.right())
1374
 
    {
1375
 
        rect_dest.left  = display_visible_rect.left();
1376
 
        rect_dest.right = display_visible_rect.right();
1377
 
 
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();
1382
 
 
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());
1386
 
    }
1387
 
    else
1388
 
    {
1389
 
        rect_dest.left  = display_video_rect.left();
1390
 
        rect_dest.right = display_video_rect.right();
1391
 
    }
1392
 
    
1393
 
    if (display_video_rect.top()    < display_visible_rect.top() ||
1394
 
        display_video_rect.bottom() > display_visible_rect.bottom())
1395
 
    {
1396
 
        rect_dest.top    = display_visible_rect.top();
1397
 
        rect_dest.bottom = display_visible_rect.bottom();
1398
 
 
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();
1403
 
 
1404
 
        rect_src.top += ((video_rect.width() * diff_y) /
1405
 
                         display_video_rect.height());
1406
 
 
1407
 
        rect_src.bottom -= (video_rect.height() * (diff_h - diff_y) /
1408
 
                            display_video_rect.height());
1409
 
    }
1410
 
    else
1411
 
    {
1412
 
        rect_dest.top    = display_video_rect.top();
1413
 
        rect_dest.bottom = display_video_rect.bottom();
1414
 
    }
1415
 
 
1416
 
    VERBOSE(VB_IMPORTANT, "rect_src ("
1417
 
              << rect_src.left << "x"
1418
 
              << rect_src.top << ","
1419
 
              << rect_src.right << "x"
1420
 
              << rect_src.bottom << ")");
1421
 
    
1422
 
    VERBOSE(VB_IMPORTANT, "rect_dest ("
1423
 
              << rect_dest.left << "x"
1424
 
              << rect_dest.top << ","
1425
 
              << rect_dest.right << "x"
1426
 
              << rect_dest.bottom << ")");
1427
 
 
1428
 
 
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;
1434
 
 
1435
 
    dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
1436
 
 
1437
 
    dxresult = IDirectDrawSurface2_UpdateOverlay(front_surface,
1438
 
                                         &rect_src,
1439
 
                                         display,
1440
 
                                         &rect_dest,
1441
 
                                         dwFlags, &ddofx );
1442
 
    if (dxresult != DD_OK)
1443
 
    {
1444
 
        VERBOSE(VB_IMPORTANT,
1445
 
                  "DirectXUpdateOverlay cannot move or resize overlay: " << hex << dxresult << dec);
1446
 
        return -1;
1447
 
    }
1448
 
 
1449
 
    return 0;
1450
 
}
1451
 
 
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)
1459
 
{
1460
 
    HRESULT dxresult;
1461
 
    DDSURFACEDESC ddsd;
1462
 
 
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,
1467
 
                                         NULL, &ddsd,
1468
 
                                         DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
1469
 
                                         NULL );
1470
 
    if (dxresult != DD_OK)
1471
 
    {
1472
 
        if (dxresult == DDERR_INVALIDPARAMS)
1473
 
        {
1474
 
            /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
1475
 
             * in an invalid params error */
1476
 
            dxresult = IDirectDrawSurface2_Lock(back_surface, NULL,
1477
 
                                             &ddsd,
1478
 
                                             DDLOCK_WAIT, NULL);
1479
 
        }
1480
 
        if (dxresult == DDERR_SURFACELOST)
1481
 
        {
1482
 
            /* Your surface can be lost so be sure
1483
 
             * to check this and restore it if needed */
1484
 
 
1485
 
            /* When using overlays with back-buffers, we need to restore
1486
 
             * the front buffer so the back-buffers get restored as well. */
1487
 
            if (using_overlay )
1488
 
                IDirectDrawSurface2_Restore(front_surface);
1489
 
            else
1490
 
                IDirectDrawSurface2_Restore(back_surface);
1491
 
 
1492
 
            dxresult = IDirectDrawSurface2_Lock(back_surface, NULL,
1493
 
                                                 &ddsd,
1494
 
                                                 DDLOCK_WAIT, NULL);
1495
 
            if (dxresult == DDERR_SURFACELOST)
1496
 
                VERBOSE(VB_IMPORTANT, "DirectXLockSurface: DDERR_SURFACELOST");
1497
 
        }
1498
 
        if (dxresult != DD_OK)
1499
 
        {
1500
 
            return -1;
1501
 
        }
1502
 
    }
1503
 
 
1504
 
    if (picbuf)
1505
 
        *picbuf = ddsd.lpSurface;
1506
 
        
1507
 
       if (stride)
1508
 
           *stride = ddsd.lPitch;
1509
 
        
1510
 
    return 0;
1511
 
}
1512
 
 
1513
 
/*****************************************************************************
1514
 
 * DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
1515
 
 *****************************************************************************/
1516
 
int VideoOutputDX::DirectXUnlockSurface()
1517
 
{
1518
 
    /* Unlock the Surface */
1519
 
    if (IDirectDrawSurface2_Unlock(back_surface, NULL) == DD_OK)
1520
 
        return 0;
1521
 
    else
1522
 
        return -1;
1523
 
}
1524
 
 
1525
 
QStringList VideoOutputDX::GetAllowedRenderers(
1526
 
    MythCodecID myth_codec_id, const QSize &video_dim)
1527
 
{
1528
 
    QStringList list;
1529
 
    list += "directx";
1530
 
    return list;
1531
 
}
1532