vdpau: clear processed pics on flush
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / VDPAU.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #ifdef HAVE_LIBVDPAU
23 #include <dlfcn.h>
24 #include "windowing/WindowingFactory.h"
25 #include "VDPAU.h"
26 #include "guilib/GraphicContext.h"
27 #include "guilib/TextureManager.h"
28 #include "cores/VideoRenderers/RenderManager.h"
29 #include "DVDVideoCodecFFmpeg.h"
30 #include "DVDClock.h"
31 #include "settings/Settings.h"
32 #include "settings/AdvancedSettings.h"
33 #include "settings/MediaSettings.h"
34 #include "Application.h"
35 #include "utils/MathUtils.h"
36 #include "utils/TimeUtils.h"
37 #include "DVDCodecs/DVDCodecUtils.h"
38 #include "cores/VideoRenderers/RenderFlags.h"
39
40 using namespace VDPAU;
41 #define NUM_RENDER_PICS 9
42
43 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
44
45 CDecoder::Desc decoder_profiles[] = {
46 {"MPEG1",        VDP_DECODER_PROFILE_MPEG1},
47 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
48 {"MPEG2_MAIN",   VDP_DECODER_PROFILE_MPEG2_MAIN},
49 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
50 {"H264_MAIN",    VDP_DECODER_PROFILE_H264_MAIN},
51 {"H264_HIGH",    VDP_DECODER_PROFILE_H264_HIGH},
52 {"VC1_SIMPLE",   VDP_DECODER_PROFILE_VC1_SIMPLE},
53 {"VC1_MAIN",     VDP_DECODER_PROFILE_VC1_MAIN},
54 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
55 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
56 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
57 #endif
58 };
59 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
60
61 static struct SInterlaceMapping
62 {
63   const EINTERLACEMETHOD     method;
64   const VdpVideoMixerFeature feature;
65 } g_interlace_mapping[] = 
66 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL             , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
67 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF        , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
68 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL     , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
69 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
70 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE     , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
71 , {VS_INTERLACEMETHOD_NONE                       , (VdpVideoMixerFeature)-1}
72 };
73
74 static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
75 static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
76
77 //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
78 //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
79 //so we just keep a static handle to libvdpau around
80 void* CDecoder::dl_handle;
81
82 //-----------------------------------------------------------------------------
83 // VDPAU Video Surface states
84 //-----------------------------------------------------------------------------
85
86 #define SURFACE_USED_FOR_REFERENCE 0x01
87 #define SURFACE_USED_FOR_RENDER    0x02
88
89 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
90 {
91   CSingleLock lock(m_section);
92   m_state[surf] = SURFACE_USED_FOR_REFERENCE;
93 }
94
95 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
96 {
97   CSingleLock lock(m_section);
98   if (m_state.find(surf) == m_state.end())
99   {
100     CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
101     return;
102   }
103   m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
104   if (m_state[surf] == 0)
105   {
106     m_freeSurfaces.push_back(surf);
107   }
108 }
109
110 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
111 {
112   CSingleLock lock(m_section);
113   if (m_state.find(surf) == m_state.end())
114   {
115     CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
116     return false;
117   }
118   std::list<VdpVideoSurface>::iterator it;
119   it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
120   if (it != m_freeSurfaces.end())
121   {
122     m_freeSurfaces.erase(it);
123   }
124   m_state[surf] |= SURFACE_USED_FOR_RENDER;
125   return true;
126 }
127
128 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
129 {
130   CSingleLock lock(m_section);
131   if (m_state.find(surf) == m_state.end())
132   {
133     CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
134     return;
135   }
136   m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
137   if (m_state[surf] == 0)
138   {
139     m_freeSurfaces.push_back(surf);
140   }
141 }
142
143 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
144 {
145   CSingleLock lock(m_section);
146   if (m_state.find(surf) != m_state.end())
147     return true;
148   else
149     return false;
150 }
151
152 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
153 {
154   CSingleLock lock(m_section);
155   if (m_state.find(surf) != m_state.end())
156   {
157     std::list<VdpVideoSurface>::iterator it;
158     it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
159     if (it == m_freeSurfaces.end())
160     {
161       CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
162     }
163     else
164     {
165       m_freeSurfaces.erase(it);
166       m_state[surf] = SURFACE_USED_FOR_REFERENCE;
167       return surf;
168     }
169   }
170
171   if (!m_freeSurfaces.empty())
172   {
173     VdpVideoSurface freeSurf = m_freeSurfaces.front();
174     m_freeSurfaces.pop_front();
175     m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
176     return freeSurf;
177   }
178
179   return VDP_INVALID_HANDLE;
180 }
181
182 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
183 {
184   if (idx >= m_state.size())
185     return VDP_INVALID_HANDLE;
186
187   std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
188   for(int i = 0; i < idx; i++)
189     ++it;
190   return it->first;
191 }
192
193 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
194 {
195   CSingleLock lock(m_section);
196   VdpVideoSurface surf;
197   std::map<VdpVideoSurface, int>::iterator it;
198   for(it = m_state.begin(); it != m_state.end(); ++it)
199   {
200     if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
201       continue;
202     surf = it->first;
203     m_state.erase(surf);
204
205     std::list<VdpVideoSurface>::iterator it2;
206     it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
207     if (it2 != m_freeSurfaces.end())
208       m_freeSurfaces.erase(it2);
209     return surf;
210   }
211   return VDP_INVALID_HANDLE;
212 }
213
214 void CVideoSurfaces::Reset()
215 {
216   CSingleLock lock(m_section);
217   m_freeSurfaces.clear();
218   m_state.clear();
219 }
220
221 int CVideoSurfaces::Size()
222 {
223   CSingleLock lock(m_section);
224   return m_state.size();
225 }
226
227 //-----------------------------------------------------------------------------
228 // CVDPAU
229 //-----------------------------------------------------------------------------
230
231 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
232 {
233   m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
234   m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
235
236   m_vdpauConfigured = false;
237   m_hwContext.bitstream_buffers_allocated = 0;
238   m_DisplayState = VDPAU_OPEN;
239 }
240
241 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
242 {
243   if(avctx->coded_width  == 0
244   || avctx->coded_height == 0)
245   {
246     CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
247     return false;
248   }
249   m_vdpauConfig.numRenderBuffers = surfaces;
250   m_decoderThread = CThread::GetCurrentThreadId();
251
252   if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
253     return false;
254
255   if (!dl_handle)
256   {
257     dl_handle  = dlopen("libvdpau.so.1", RTLD_LAZY);
258     if (!dl_handle)
259     {
260       const char* error = dlerror();
261       if (!error)
262         error = "dlerror() returned NULL";
263
264       CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
265       return false;
266     }
267   }
268
269   if (!m_dllAvUtil.Load())
270     return false;
271
272   InitVDPAUProcs();
273   m_presentPicture = 0;
274
275   if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE)
276   {
277     SpewHardwareAvailable();
278
279     VdpDecoderProfile profile = 0;
280     if(avctx->codec_id == AV_CODEC_ID_H264)
281       profile = VDP_DECODER_PROFILE_H264_HIGH;
282 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
283     else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
284       profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
285 #endif
286     if(profile)
287     {
288       if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
289         CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
290    
291       /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
292       VdpStatus vdp_st;
293       vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
294
295       if(vdp_st != VDP_STATUS_OK)
296       {
297         CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st);
298         FiniVDPAUProcs();
299         return false;
300       }
301
302       m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
303       CheckStatus(vdp_st, __LINE__);
304     }
305
306     /* finally setup ffmpeg */
307     memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
308     m_hwContext.render = CDecoder::Render;
309     m_hwContext.bitstream_buffers_allocated = 0;
310     avctx->get_buffer      = CDecoder::FFGetBuffer;
311     avctx->reget_buffer    = CDecoder::FFGetBuffer;
312     avctx->release_buffer  = CDecoder::FFReleaseBuffer;
313     avctx->draw_horiz_band = CDecoder::FFDrawSlice;
314     avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
315     avctx->hwaccel_context = &m_hwContext;
316     avctx->thread_count    = 1;
317
318     g_Windowing.Register(this);
319     return true;
320   }
321   return false;
322 }
323
324 CDecoder::~CDecoder()
325 {
326   Close();
327 }
328
329 void CDecoder::Close()
330 {
331   CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
332
333   g_Windowing.Unregister(this);
334
335   CSingleLock lock(m_DecoderSection);
336
337   FiniVDPAUOutput();
338   FiniVDPAUProcs();
339   m_vdpauOutput.Dispose();
340
341   if (m_hwContext.bitstream_buffers_allocated)
342   {
343     m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
344   }
345
346   m_dllAvUtil.Unload();
347 }
348
349 long CDecoder::Release()
350 {
351   // check if we should do some pre-cleanup here
352   // a second decoder might need resources
353   if (m_vdpauConfigured == true)
354   {
355     CSingleLock lock(m_DecoderSection);
356     CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
357
358     Message *reply;
359     if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
360                                                    &reply,
361                                                    2000))
362     {
363       bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
364       reply->Release();
365       if (!success)
366       {
367         CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
368         m_DisplayState = VDPAU_ERROR;
369       }
370     }
371     else
372     {
373       CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
374       m_DisplayState = VDPAU_ERROR;
375     }
376
377     VdpVideoSurface surf;
378     while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
379     {
380       m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(surf);
381     }
382   }
383   return IHardwareDecoder::Release();
384 }
385
386 long CDecoder::ReleasePicReference()
387 {
388   return IHardwareDecoder::Release();
389 }
390
391 void CDecoder::SetWidthHeight(int width, int height)
392 {
393   m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
394
395   //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
396   //this requires the least amount of gpu memory bandwidth
397   if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
398   {
399     //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
400     if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
401     {
402       m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
403       m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
404     }
405     else //scale height to the desktop size if the aspect ratio is smaller than the desktop
406     {
407       m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
408       m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
409     }
410   }
411   else
412   { //let opengl scale
413     m_vdpauConfig.outWidth = width;
414     m_vdpauConfig.outHeight = height;
415   }
416   CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
417 }
418
419 void CDecoder::OnLostDevice()
420 {
421   CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
422
423   int count = g_graphicsContext.exit();
424
425   CSingleLock lock(m_DecoderSection);
426   FiniVDPAUOutput();
427   FiniVDPAUProcs();
428
429   m_DisplayState = VDPAU_LOST;
430   lock.Leave();
431   m_DisplayEvent.Reset();
432
433   g_graphicsContext.restore(count);
434 }
435
436 void CDecoder::OnResetDevice()
437 {
438   CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
439
440   int count = g_graphicsContext.exit();
441
442   CSingleLock lock(m_DecoderSection);
443   if (m_DisplayState == VDPAU_LOST)
444   {
445     m_DisplayState = VDPAU_RESET;
446     lock.Leave();
447     m_DisplayEvent.Set();
448   }
449
450   g_graphicsContext.restore(count);
451 }
452
453 int CDecoder::Check(AVCodecContext* avctx)
454 {
455   EDisplayState state;
456
457   { CSingleLock lock(m_DecoderSection);
458     state = m_DisplayState;
459   }
460
461   if (state == VDPAU_LOST)
462   {
463     CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
464     if (!m_DisplayEvent.WaitMSec(4000))
465     {
466       CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
467       state = VDPAU_RESET;
468     }
469     else
470     {
471       CSingleLock lock(m_DecoderSection);
472       state = m_DisplayState;
473     }
474   }
475   if (state == VDPAU_RESET || state == VDPAU_ERROR)
476   {
477     CSingleLock lock(m_DecoderSection);
478
479     FiniVDPAUOutput();
480     FiniVDPAUProcs();
481
482     InitVDPAUProcs();
483
484     if (state == VDPAU_RESET)
485       return VC_FLUSHED;
486     else
487       return VC_ERROR;
488   }
489   return 0;
490 }
491
492 bool CDecoder::IsVDPAUFormat(PixelFormat format)
493 {
494   if (format == AV_PIX_FMT_VDPAU)
495     return true;
496   else
497     return false;
498 }
499
500 bool CDecoder::Supports(VdpVideoMixerFeature feature)
501 {
502   for(int i = 0; i < m_vdpauConfig.featureCount; i++)
503   {
504     if(m_vdpauConfig.vdpFeatures[i] == feature)
505       return true;
506   }
507   return false;
508 }
509
510 bool CDecoder::Supports(EINTERLACEMETHOD method)
511 {
512   if(method == VS_INTERLACEMETHOD_VDPAU_BOB
513   || method == VS_INTERLACEMETHOD_AUTO)
514     return true;
515
516   if (!m_vdpauConfig.usePixmaps)
517   {
518     if (method == VS_INTERLACEMETHOD_RENDER_BOB)
519       return true;
520   }
521
522   if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
523     return false;
524
525   for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
526   {
527     if(p->method == method)
528       return Supports(p->feature);
529   }
530   return false;
531 }
532
533 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
534 {
535   return VS_INTERLACEMETHOD_RENDER_BOB;
536 }
537
538 void CDecoder::InitVDPAUProcs()
539 {
540   char* error;
541
542   (void)dlerror();
543   dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(dl_handle, (const char*)"vdp_device_create_x11");
544   error = dlerror();
545   if (error)
546   {
547     CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
548     m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
549     return;
550   }
551
552   if (dl_vdp_device_create_x11)
553   {
554     m_Display = XOpenDisplay(NULL);
555   }
556
557   int mScreen = g_Windowing.GetCurrentScreen();
558   VdpStatus vdp_st;
559
560   // Create Device
561   vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
562                                  mScreen, //x_screen,
563                                  &m_vdpauConfig.vdpDevice,
564                                  &m_vdpauConfig.vdpProcs.vdp_get_proc_address);
565
566   CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st);
567   if (vdp_st != VDP_STATUS_OK)
568   {
569     CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x.  Falling back.",vdp_st);
570     m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
571     return;
572   }
573
574 #define VDP_PROC(id, proc) \
575   do { \
576     vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \
577     CheckStatus(vdp_st, __LINE__); \
578   } while(0);
579
580   VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING                    , m_vdpauConfig.vdpProcs.vdp_get_error_string);
581   VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY                      , m_vdpauConfig.vdpProcs.vdp_device_destroy);
582   VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX                 , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix);
583   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE                , m_vdpauConfig.vdpProcs.vdp_video_surface_create);
584   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY               , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy);
585   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR      , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
586   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR      , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
587   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR     , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
588   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE      , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native);
589   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE               , m_vdpauConfig.vdpProcs.vdp_output_surface_create);
590   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY              , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy);
591   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE      , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native);
592   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface);
593   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED     , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed);
594   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE                  , m_vdpauConfig.vdpProcs.vdp_video_mixer_create);
595   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES     , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables);
596   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY                 , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy);
597   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER                  , m_vdpauConfig.vdpProcs.vdp_video_mixer_render);
598   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES    , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values);
599   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support);
600   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT   , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support);
601   VDP_PROC(VDP_FUNC_ID_DECODER_CREATE                      , m_vdpauConfig.vdpProcs.vdp_decoder_create);
602   VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY                     , m_vdpauConfig.vdpProcs.vdp_decoder_destroy);
603   VDP_PROC(VDP_FUNC_ID_DECODER_RENDER                      , m_vdpauConfig.vdpProcs.vdp_decoder_render);
604   VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES          , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps);
605   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY          , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy);
606   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE                  , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create);
607   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY                 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy);
608   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY                 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display);
609   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle);
610   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11       , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11);
611   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS    , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status);
612   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME                , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time);
613
614 #undef VDP_PROC
615
616   // set all vdpau resources to invalid
617   m_DisplayState = VDPAU_OPEN;
618   m_vdpauConfigured = false;
619 }
620
621 void CDecoder::FiniVDPAUProcs()
622 {
623   if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return;
624
625   VdpStatus vdp_st;
626   vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice);
627   CheckStatus(vdp_st, __LINE__);
628   m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
629 }
630
631 void CDecoder::FiniVDPAUOutput()
632 {
633   if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return;
634
635   CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
636
637   // uninit output
638   m_vdpauOutput.Dispose();
639   m_vdpauConfigured = false;
640
641   VdpStatus vdp_st;
642
643   vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
644   if (CheckStatus(vdp_st, __LINE__))
645     return;
646   m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
647
648   CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
649
650   VdpVideoSurface surf;
651   while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
652   {
653     m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(surf);
654     if (CheckStatus(vdp_st, __LINE__))
655       return;
656   }
657   m_videoSurfaces.Reset();
658 }
659
660 void CDecoder::ReadFormatOf( AVCodecID codec
661                            , VdpDecoderProfile &vdp_decoder_profile
662                            , VdpChromaType     &vdp_chroma_type)
663 {
664   switch (codec)
665   {
666     case AV_CODEC_ID_MPEG1VIDEO:
667       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
668       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
669       break;
670     case AV_CODEC_ID_MPEG2VIDEO:
671       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
672       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
673       break;
674     case AV_CODEC_ID_H264:
675       vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
676       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
677       break;
678     case AV_CODEC_ID_WMV3:
679       vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
680       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
681       break;
682     case AV_CODEC_ID_VC1:
683       vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
684       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
685       break;
686     case AV_CODEC_ID_MPEG4:
687       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
688       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
689       break;
690     default:
691       vdp_decoder_profile = 0;
692       vdp_chroma_type     = 0;
693       break;
694   }
695 }
696
697 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
698 {
699   FiniVDPAUOutput();
700
701   VdpStatus vdp_st;
702   VdpDecoderProfile vdp_decoder_profile;
703
704   m_vdpauConfig.vidWidth = avctx->width;
705   m_vdpauConfig.vidHeight = avctx->height;
706   m_vdpauConfig.surfaceWidth = avctx->coded_width;
707   m_vdpauConfig.surfaceHeight = avctx->coded_height;
708
709   SetWidthHeight(avctx->width,avctx->height);
710
711   CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
712   CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
713
714   ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
715
716   if(avctx->codec_id == AV_CODEC_ID_H264)
717   {
718     m_vdpauConfig.maxReferences = ref_frames;
719     if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
720     if (m_vdpauConfig.maxReferences < 5)  m_vdpauConfig.maxReferences = 5;
721   }
722   else
723     m_vdpauConfig.maxReferences = 2;
724
725   vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice,
726                               vdp_decoder_profile,
727                               m_vdpauConfig.surfaceWidth,
728                               m_vdpauConfig.surfaceHeight,
729                               m_vdpauConfig.maxReferences,
730                               &m_vdpauConfig.vdpDecoder);
731   if (CheckStatus(vdp_st, __LINE__))
732     return false;
733
734   // initialize output
735   CSingleLock lock(g_graphicsContext);
736   m_vdpauConfig.stats = &m_bufferStats;
737   m_vdpauConfig.vdpau = this;
738   m_bufferStats.Reset();
739   m_vdpauOutput.Start();
740   Message *reply;
741   if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
742                                                  &reply,
743                                                  2000,
744                                                  &m_vdpauConfig,
745                                                  sizeof(m_vdpauConfig)))
746   {
747     bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
748     if (success)
749     {
750       CVdpauConfig *data;
751       data = (CVdpauConfig*)reply->data;
752       if (data)
753       {
754         m_vdpauConfig.usePixmaps = data->usePixmaps;
755       }
756     }
757     reply->Release();
758     if (!success)
759     {
760       CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
761       m_vdpauOutput.Dispose();
762       return false;
763     }
764   }
765   else
766   {
767     CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
768     m_vdpauOutput.Dispose();
769     return false;
770   }
771
772   m_inMsgEvent.Reset();
773   m_vdpauConfigured = true;
774   return true;
775 }
776
777 void CDecoder::SpewHardwareAvailable()  //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan  -- VDPInfo
778 {
779   VdpStatus rv;
780   CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
781   CLog::Log(LOGNOTICE,"name          level macbs width height");
782   CLog::Log(LOGNOTICE,"------------------------------------");
783   for(unsigned int x=0; x<decoder_profile_count; ++x)
784   {
785     VdpBool is_supported = false;
786     uint32_t max_level, max_macroblocks, max_width, max_height;
787     rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id,
788                                 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
789     if(rv == VDP_STATUS_OK && is_supported)
790     {
791       CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
792                 max_level, max_macroblocks, max_width, max_height);
793     }
794   }
795   CLog::Log(LOGNOTICE,"------------------------------------");
796   m_vdpauConfig.featureCount = 0;
797 #define CHECK_SUPPORT(feature)  \
798   do { \
799     VdpBool supported; \
800     if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
801       CLog::Log(LOGNOTICE, "Mixer feature: "#feature);  \
802       m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \
803     } \
804   } while(false)
805
806   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
807   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
808   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
809   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
810   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
811 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
812   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
813   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
814   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
815   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
816   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
817   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
818   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
819   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
820   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
821 #endif
822 #undef CHECK_SUPPORT
823
824 }
825
826 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
827 {
828   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
829   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
830   CDecoder*             vdp        = (CDecoder*)ctx->GetHardware();
831
832   // while we are waiting to recover we can't do anything
833   CSingleLock lock(vdp->m_DecoderSection);
834
835   if(vdp->m_DisplayState != VDPAU_OPEN)
836   {
837     CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
838     return -1;
839   }
840
841   VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
842   surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
843
844   VdpStatus vdp_st = VDP_STATUS_ERROR;
845   if (surf == VDP_INVALID_HANDLE)
846   {
847     // create a new surface
848     VdpDecoderProfile profile;
849     ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
850
851     vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice,
852                                          vdp->m_vdpauConfig.vdpChromaType,
853                                          avctx->coded_width,
854                                          avctx->coded_height,
855                                          &surf);
856     vdp->CheckStatus(vdp_st, __LINE__);
857     if (vdp_st != VDP_STATUS_OK)
858     {
859       CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
860       return -1;
861     }
862     vdp->m_videoSurfaces.AddSurface(surf);
863   }
864
865   pic->data[1] = pic->data[2] = NULL;
866   pic->data[0] = (uint8_t*)(uintptr_t)surf;
867   pic->data[3] = (uint8_t*)(uintptr_t)surf;
868
869   pic->linesize[0] = pic->linesize[1] =  pic->linesize[2] = 0;
870
871   pic->type= FF_BUFFER_TYPE_USER;
872
873   pic->reordered_opaque= avctx->reordered_opaque;
874   return 0;
875 }
876
877 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
878 {
879   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
880   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
881   CDecoder*             vdp        = (CDecoder*)ctx->GetHardware();
882
883   VdpVideoSurface surf;
884   unsigned int i;
885
886   CSingleLock lock(vdp->m_DecoderSection);
887
888   surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
889
890   vdp->m_videoSurfaces.ClearReference(surf);
891
892   for(i=0; i<4; i++)
893     pic->data[i]= NULL;
894 }
895
896 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
897                             VdpPictureInfo const *picture_info,
898                             uint32_t bitstream_buffer_count,
899                             VdpBitstreamBuffer const * bitstream_buffers)
900 {
901   return VDP_STATUS_OK;
902 }
903
904 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
905                                            const AVFrame *src, int offset[4],
906                                            int y, int type, int height)
907 {
908   CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
909   CDecoder*               vdp = (CDecoder*)ctx->GetHardware();
910
911   // while we are waiting to recover we can't do anything
912   CSingleLock lock(vdp->m_DecoderSection);
913
914   if(vdp->m_DisplayState != VDPAU_OPEN)
915     return;
916
917   if(src->linesize[0] || src->linesize[1] || src->linesize[2]
918   || offset[0] || offset[1] || offset[2])
919   {
920     CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
921     return;
922   }
923
924   VdpStatus vdp_st;
925   VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
926
927   // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
928   if (!vdp->m_videoSurfaces.IsValid(surf))
929   {
930     CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
931     return;
932   }
933
934   uint32_t max_refs = 0;
935   if(s->codec_id == AV_CODEC_ID_H264)
936     max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
937
938   if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
939   || vdp->m_vdpauConfigured == false
940   || vdp->m_vdpauConfig.maxReferences < max_refs)
941   {
942     if(!vdp->ConfigVDPAU(s, max_refs))
943       return;
944   }
945
946 //  uint64_t startTime = CurrentHostCounter();
947   uint16_t decoded, processed, rend;
948   vdp->m_bufferStats.Get(decoded, processed, rend);
949   vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
950                                    surf,
951                                    (VdpPictureInfo const *)&(vdp->m_hwContext.info),
952                                    vdp->m_hwContext.bitstream_buffers_used,
953                                    vdp->m_hwContext.bitstream_buffers);
954   vdp->CheckStatus(vdp_st, __LINE__);
955 //  uint64_t diff = CurrentHostCounter() - startTime;
956 //  if (diff*1000/CurrentHostFrequency() > 30)
957 //    CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
958
959 }
960
961
962 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
963 {
964   int result = Check(avctx);
965   if (result)
966     return result;
967
968   CSingleLock lock(m_DecoderSection);
969
970   if (!m_vdpauConfigured)
971     return VC_ERROR;
972
973   if(pFrame)
974   { // we have a new frame from decoder
975
976     VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
977     // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
978     if (!m_videoSurfaces.IsValid(surf))
979     {
980       CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
981       return VC_BUFFER;
982     }
983     m_videoSurfaces.MarkRender(surf);
984
985     // send frame to output for processing
986     CVdpauDecodedPicture pic;
987     memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
988     ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
989     pic.videoSurface = surf;
990     pic.DVDPic.color_matrix = avctx->colorspace;
991     m_bufferStats.IncDecoded();
992     m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
993
994     //TODO
995     // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
996   }
997
998   int retval = 0;
999   uint16_t decoded, processed, render;
1000   Message *msg;
1001   while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1002   {
1003     if (msg->signal == COutputControlProtocol::ERROR)
1004     {
1005       m_DisplayState = VDPAU_ERROR;
1006       retval |= VC_ERROR;
1007     }
1008     msg->Release();
1009   }
1010
1011   m_bufferStats.Get(decoded, processed, render);
1012
1013   uint64_t startTime = CurrentHostCounter();
1014   while (!retval)
1015   {
1016     if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1017     {
1018       if (msg->signal == COutputDataProtocol::PICTURE)
1019       {
1020         if (m_presentPicture)
1021         {
1022           m_presentPicture->ReturnUnused();
1023           m_presentPicture = 0;
1024         }
1025
1026         m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1027         m_presentPicture->vdpau = this;
1028         m_bufferStats.DecRender();
1029         m_bufferStats.Get(decoded, processed, render);
1030         retval |= VC_PICTURE;
1031         msg->Release();
1032         break;
1033       }
1034       msg->Release();
1035     }
1036     else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1037     {
1038       if (msg->signal == COutputControlProtocol::STATS)
1039       {
1040         m_bufferStats.Get(decoded, processed, render);
1041       }
1042       else
1043       {
1044         m_DisplayState = VDPAU_ERROR;
1045         retval |= VC_ERROR;
1046       }
1047       msg->Release();
1048     }
1049
1050     // TODO
1051     if (1) //(m_codecControl & DVP_FLAG_DRAIN))
1052     {
1053       if (decoded + processed + render < 4)
1054       {
1055         retval |= VC_BUFFER;
1056       }
1057     }
1058     else
1059     {
1060       if (decoded < 4 && (processed + render) < 3)
1061       {
1062         retval |= VC_BUFFER;
1063       }
1064     }
1065
1066     if (!retval && !m_inMsgEvent.WaitMSec(2000))
1067       break;
1068   }
1069   uint64_t diff = CurrentHostCounter() - startTime;
1070   if (retval & VC_PICTURE)
1071   {
1072     m_bufferStats.SetParams(diff, m_codecControl);
1073   }
1074   if (diff*1000/CurrentHostFrequency() > 50)
1075     CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1076
1077   if (!retval)
1078   {
1079     CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1080     m_DisplayState = VDPAU_ERROR;
1081     retval |= VC_ERROR;
1082   }
1083
1084   return retval;
1085 }
1086
1087 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1088 {
1089   CSingleLock lock(m_DecoderSection);
1090
1091   if (m_DisplayState != VDPAU_OPEN)
1092     return false;
1093
1094   *picture = m_presentPicture->DVDPic;
1095   picture->vdpau = m_presentPicture;
1096
1097   return true;
1098 }
1099
1100 void CDecoder::Reset()
1101 {
1102   CSingleLock lock(m_DecoderSection);
1103
1104   if (!m_vdpauConfigured)
1105     return;
1106
1107   Message *reply;
1108   if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1109                                                  &reply,
1110                                                  2000))
1111   {
1112     bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1113     reply->Release();
1114     if (!success)
1115     {
1116       CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1117       m_DisplayState = VDPAU_ERROR;
1118     }
1119     else
1120       m_bufferStats.Reset();
1121   }
1122   else
1123   {
1124     CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1125     m_DisplayState = VDPAU_ERROR;
1126   }
1127 }
1128
1129 bool CDecoder::CanSkipDeint()
1130 {
1131   return m_bufferStats.CanSkipDeint();
1132 }
1133
1134 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1135 {
1136   m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1137 }
1138
1139 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1140 {
1141   if (vdp_st != VDP_STATUS_OK)
1142   {
1143     CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1144
1145     if(m_DisplayState == VDPAU_OPEN)
1146     {
1147       if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1148       {
1149         m_DisplayEvent.Reset();
1150         m_DisplayState = VDPAU_LOST;
1151       }
1152       else
1153         m_DisplayState = VDPAU_ERROR;
1154     }
1155
1156     return true;
1157   }
1158   return false;
1159 }
1160
1161 //-----------------------------------------------------------------------------
1162 // RenderPicture
1163 //-----------------------------------------------------------------------------
1164
1165 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1166 {
1167   CSingleLock lock(renderPicSection);
1168
1169   if (refCount == 0)
1170     vdpau->Acquire();
1171
1172   refCount++;
1173   return this;
1174 }
1175
1176 long CVdpauRenderPicture::Release()
1177 {
1178   CSingleLock lock(renderPicSection);
1179
1180   refCount--;
1181   if (refCount > 0)
1182     return refCount;
1183
1184   lock.Leave();
1185   vdpau->ReturnRenderPicture(this);
1186   vdpau->ReleasePicReference();
1187
1188   return refCount;
1189 }
1190
1191 void CVdpauRenderPicture::ReturnUnused()
1192 {
1193   { CSingleLock lock(renderPicSection);
1194     if (refCount > 0)
1195       return;
1196   }
1197   if (vdpau)
1198     vdpau->ReturnRenderPicture(this);
1199 }
1200
1201 void CVdpauRenderPicture::Sync()
1202 {
1203 #ifdef GL_ARB_sync
1204   CSingleLock lock(renderPicSection);
1205   if (usefence)
1206   {
1207     if(glIsSync(fence))
1208     {
1209       glDeleteSync(fence);
1210       fence = None;
1211     }
1212     fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1213   }
1214 #endif
1215 }
1216
1217 //-----------------------------------------------------------------------------
1218 // Mixer
1219 //-----------------------------------------------------------------------------
1220 CMixer::CMixer(CEvent *inMsgEvent) :
1221   CThread("Vdpau Mixer Thread"),
1222   m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1223   m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1224 {
1225   m_inMsgEvent = inMsgEvent;
1226 }
1227
1228 CMixer::~CMixer()
1229 {
1230   Dispose();
1231 }
1232
1233 void CMixer::Start()
1234 {
1235   Create();
1236 }
1237
1238 void CMixer::Dispose()
1239 {
1240   m_bStop = true;
1241   m_outMsgEvent.Set();
1242   StopThread();
1243
1244   m_controlPort.Purge();
1245   m_dataPort.Purge();
1246 }
1247
1248 bool CMixer::IsActive()
1249 {
1250   return IsRunning();
1251 }
1252
1253 void CMixer::OnStartup()
1254 {
1255   CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1256 }
1257
1258 void CMixer::OnExit()
1259 {
1260   CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1261 }
1262
1263 enum MIXER_STATES
1264 {
1265   M_TOP = 0,                      // 0
1266   M_TOP_ERROR,                    // 1
1267   M_TOP_UNCONFIGURED,             // 2
1268   M_TOP_CONFIGURED,               // 3
1269   M_TOP_CONFIGURED_WAIT1,         // 4
1270   M_TOP_CONFIGURED_STEP1,         // 5
1271   M_TOP_CONFIGURED_WAIT2,         // 6
1272   M_TOP_CONFIGURED_STEP2,         // 7
1273 };
1274
1275 int MIXER_parentStates[] = {
1276     -1,
1277     0, //TOP_ERROR
1278     0, //TOP_UNCONFIGURED
1279     0, //TOP_CONFIGURED
1280     3, //TOP_CONFIGURED_WAIT1
1281     3, //TOP_CONFIGURED_STEP1
1282     3, //TOP_CONFIGURED_WAIT2
1283     3, //TOP_CONFIGURED_STEP2
1284 };
1285
1286 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1287 {
1288   for (int state = m_state; ; state = MIXER_parentStates[state])
1289   {
1290     switch (state)
1291     {
1292     case M_TOP: // TOP
1293       if (port == &m_controlPort)
1294       {
1295         switch (signal)
1296         {
1297         case CMixerControlProtocol::FLUSH:
1298           Flush();
1299           msg->Reply(CMixerControlProtocol::ACC);
1300           return;
1301         default:
1302           break;
1303         }
1304       }
1305       {
1306         std::string portName = port == NULL ? "timer" : port->portName;
1307         CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1308       }
1309       return;
1310
1311     case M_TOP_ERROR: // TOP
1312       break;
1313
1314     case M_TOP_UNCONFIGURED:
1315       if (port == &m_controlPort)
1316       {
1317         switch (signal)
1318         {
1319         case CMixerControlProtocol::INIT:
1320           CVdpauConfig *data;
1321           data = (CVdpauConfig*)msg->data;
1322           if (data)
1323           {
1324             m_config = *data;
1325           }
1326           Init();
1327           if (!m_vdpError)
1328           {
1329             m_state = M_TOP_CONFIGURED_WAIT1;
1330             msg->Reply(CMixerControlProtocol::ACC);
1331           }
1332           else
1333           {
1334             msg->Reply(CMixerControlProtocol::ERROR);
1335           }
1336           return;
1337         default:
1338           break;
1339         }
1340       }
1341       break;
1342
1343     case M_TOP_CONFIGURED:
1344       if (port == &m_dataPort)
1345       {
1346         switch (signal)
1347         {
1348         case CMixerDataProtocol::FRAME:
1349           CVdpauDecodedPicture *frame;
1350           frame = (CVdpauDecodedPicture*)msg->data;
1351           if (frame)
1352           {
1353             m_decodedPics.push(*frame);
1354           }
1355           m_extTimeout = 0;
1356           return;
1357         case CMixerDataProtocol::BUFFER:
1358           VdpOutputSurface *surf;
1359           surf = (VdpOutputSurface*)msg->data;
1360           if (surf)
1361           {
1362             m_outputSurfaces.push(*surf);
1363           }
1364           m_extTimeout = 0;
1365           return;
1366         default:
1367           break;
1368         }
1369       }
1370       break;
1371
1372     case M_TOP_CONFIGURED_WAIT1:
1373       if (port == NULL) // timeout
1374       {
1375         switch (signal)
1376         {
1377         case CMixerControlProtocol::TIMEOUT:
1378           if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1379           {
1380             m_state = M_TOP_CONFIGURED_STEP1;
1381             m_bStateMachineSelfTrigger = true;
1382           }
1383           else
1384           {
1385 //            if (m_extTimeout != 0)
1386 //            {
1387 //              SetPostProcFeatures(false);
1388 //              CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1389 //            }
1390             m_extTimeout = 100;
1391           }
1392           return;
1393         default:
1394           break;
1395         }
1396       }
1397       break;
1398
1399     case M_TOP_CONFIGURED_STEP1:
1400       if (port == NULL) // timeout
1401       {
1402         switch (signal)
1403         {
1404         case CMixerControlProtocol::TIMEOUT:
1405           m_mixerInput.push_front(m_decodedPics.front());
1406           m_decodedPics.pop();
1407           if (m_mixerInput.size() < 2)
1408           {
1409             m_state = M_TOP_CONFIGURED_WAIT1;
1410             m_extTimeout = 0;
1411             return;
1412           }
1413           InitCycle();
1414           ProcessPicture();
1415           if (m_vdpError)
1416           {
1417             m_state = M_TOP_CONFIGURED_WAIT1;
1418             m_extTimeout = 1000;
1419             return;
1420           }
1421           if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1422             m_outputSurfaces.pop();
1423           m_config.stats->IncProcessed();
1424           m_config.stats->DecDecoded();
1425           m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1426           if (m_mixersteps > 1)
1427           {
1428             m_state = M_TOP_CONFIGURED_WAIT2;
1429             m_extTimeout = 0;
1430           }
1431           else
1432           {
1433             FiniCycle();
1434             m_state = M_TOP_CONFIGURED_WAIT1;
1435             m_extTimeout = 0;
1436           }
1437           return;
1438         default:
1439           break;
1440         }
1441       }
1442       break;
1443
1444     case M_TOP_CONFIGURED_WAIT2:
1445       if (port == NULL) // timeout
1446       {
1447         switch (signal)
1448         {
1449         case CMixerControlProtocol::TIMEOUT:
1450           if (!m_outputSurfaces.empty())
1451           {
1452             m_state = M_TOP_CONFIGURED_STEP2;
1453             m_bStateMachineSelfTrigger = true;
1454           }
1455           else
1456           {
1457 //            if (m_extTimeout != 0)
1458 //            {
1459 //              SetPostProcFeatures(false);
1460 //              CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1461 //            }
1462             m_extTimeout = 100;
1463           }
1464           return;
1465         default:
1466           break;
1467         }
1468       }
1469       break;
1470
1471     case M_TOP_CONFIGURED_STEP2:
1472        if (port == NULL) // timeout
1473        {
1474          switch (signal)
1475          {
1476          case CMixerControlProtocol::TIMEOUT:
1477            m_processPicture.outputSurface = m_outputSurfaces.front();
1478            m_mixerstep = 1;
1479            ProcessPicture();
1480            if (m_vdpError)
1481            {
1482              m_state = M_TOP_CONFIGURED_WAIT1;
1483              m_extTimeout = 1000;
1484              return;
1485            }
1486            if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1487              m_outputSurfaces.pop();
1488            m_config.stats->IncProcessed();
1489            m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1490            FiniCycle();
1491            m_state = M_TOP_CONFIGURED_WAIT1;
1492            m_extTimeout = 0;
1493            return;
1494          default:
1495            break;
1496          }
1497        }
1498        break;
1499
1500     default: // we are in no state, should not happen
1501       CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1502       return;
1503     }
1504   } // for
1505 }
1506
1507 void CMixer::Process()
1508 {
1509   Message *msg = NULL;
1510   Protocol *port = NULL;
1511   bool gotMsg;
1512
1513   m_state = M_TOP_UNCONFIGURED;
1514   m_extTimeout = 1000;
1515   m_bStateMachineSelfTrigger = false;
1516
1517   while (!m_bStop)
1518   {
1519     gotMsg = false;
1520
1521     if (m_bStateMachineSelfTrigger)
1522     {
1523       m_bStateMachineSelfTrigger = false;
1524       // self trigger state machine
1525       StateMachine(msg->signal, port, msg);
1526       if (!m_bStateMachineSelfTrigger)
1527       {
1528         msg->Release();
1529         msg = NULL;
1530       }
1531       continue;
1532     }
1533     // check control port
1534     else if (m_controlPort.ReceiveOutMessage(&msg))
1535     {
1536       gotMsg = true;
1537       port = &m_controlPort;
1538     }
1539     // check data port
1540     else if (m_dataPort.ReceiveOutMessage(&msg))
1541     {
1542       gotMsg = true;
1543       port = &m_dataPort;
1544     }
1545
1546     if (gotMsg)
1547     {
1548       StateMachine(msg->signal, port, msg);
1549       if (!m_bStateMachineSelfTrigger)
1550       {
1551         msg->Release();
1552         msg = NULL;
1553       }
1554       continue;
1555     }
1556
1557     // wait for message
1558     else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1559     {
1560       continue;
1561     }
1562     // time out
1563     else
1564     {
1565       msg = m_controlPort.GetMessage();
1566       msg->signal = CMixerControlProtocol::TIMEOUT;
1567       port = 0;
1568       // signal timeout to state machine
1569       StateMachine(msg->signal, port, msg);
1570       if (!m_bStateMachineSelfTrigger)
1571       {
1572         msg->Release();
1573         msg = NULL;
1574       }
1575     }
1576   }
1577   Uninit();
1578 }
1579
1580 void CMixer::CreateVdpauMixer()
1581 {
1582   CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1583
1584   InitCSCMatrix(m_config.vidWidth);
1585
1586   VdpVideoMixerParameter parameters[] = {
1587     VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1588     VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1589     VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1590
1591   void const * parameter_values[] = {
1592     &m_config.surfaceWidth,
1593     &m_config.surfaceHeight,
1594     &m_config.vdpChromaType};
1595
1596   VdpStatus vdp_st = VDP_STATUS_ERROR;
1597   vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice,
1598                                 m_config.featureCount,
1599                                 m_config.vdpFeatures,
1600                                 ARSIZE(parameters),
1601                                 parameters,
1602                                 parameter_values,
1603                                 &m_videoMixer);
1604   CheckStatus(vdp_st, __LINE__);
1605
1606   // create 3 pitches of black lines needed for clipping top
1607   // and bottom lines when de-interlacing
1608   m_BlackBar = new uint32_t[3*m_config.outWidth];
1609   memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t));
1610
1611 }
1612
1613 void CMixer::InitCSCMatrix(int Width)
1614 {
1615   m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1616   m_Procamp.brightness     = 0.0;
1617   m_Procamp.contrast       = 1.0;
1618   m_Procamp.saturation     = 1.0;
1619   m_Procamp.hue            = 0;
1620 }
1621
1622 void CMixer::CheckFeatures()
1623 {
1624   if (m_Upscale != m_config.upscale)
1625   {
1626     SetHWUpscaling();
1627     m_Upscale = m_config.upscale;
1628   }
1629   if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1630       m_Contrast   != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1631       m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1632   {
1633     SetColor();
1634     m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1635     m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1636     m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1637   }
1638   if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1639   {
1640     m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1641     SetNoiseReduction();
1642   }
1643   if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1644   {
1645     m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1646     SetSharpness();
1647   }
1648   if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1649       m_Deint     != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1650   {
1651     m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1652     m_Deint     = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1653     SetDeinterlacing();
1654   }
1655 }
1656
1657 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1658 {
1659   if (m_PostProc != postProcEnabled)
1660   {
1661     if (postProcEnabled)
1662     {
1663       SetNoiseReduction();
1664       SetSharpness();
1665       SetDeinterlacing();
1666       SetHWUpscaling();
1667     }
1668     else
1669       PostProcOff();
1670     m_PostProc = postProcEnabled;
1671   }
1672 }
1673
1674 void CMixer::PostProcOff()
1675 {
1676   VdpStatus vdp_st;
1677
1678   if (m_videoMixer == VDP_INVALID_HANDLE)
1679     return;
1680
1681   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1682                                      VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1683                                      VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1684
1685   VdpBool enabled[]={0,0,0};
1686   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1687   CheckStatus(vdp_st, __LINE__);
1688
1689   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1690   {
1691     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1692
1693     VdpBool enabled[]={0};
1694     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1695     CheckStatus(vdp_st, __LINE__);
1696   }
1697
1698   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1699   {
1700     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1701
1702     VdpBool enabled[]={0};
1703     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1704     CheckStatus(vdp_st, __LINE__);
1705   }
1706
1707   DisableHQScaling();
1708 }
1709
1710 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1711 {
1712    // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1713    // m00 = mRY = red: luma factor (contrast factor) (1.0)
1714    // m10 = mGY = green: luma factor (contrast factor) (1.0)
1715    // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1716    //
1717    // m01 = mRB = red: blue color diff coeff (0.0)
1718    // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1719    // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1720    //
1721    // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1722    // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1723    // m22 = mBR = blue: red color diff coeff (0.0)
1724    //
1725    // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1726    // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1727    // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1728
1729    // columns
1730    int Y = 0;
1731    int Cb = 1;
1732    int Cr = 2;
1733    int C = 3;
1734    // rows
1735    int R = 0;
1736    int G = 1;
1737    int B = 2;
1738    // colour standard coefficients for red, geen, blue
1739    double Kr, Kg, Kb;
1740    // colour diff zero position (use standard 8-bit coding precision)
1741    double CDZ = 128; //256*0.5
1742    // range excursion (use standard 8-bit coding precision)
1743    double EXC = 255; //256-1
1744
1745    if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1746    {
1747       Kr = studioCSCKCoeffs601[0];
1748       Kg = studioCSCKCoeffs601[1];
1749       Kb = studioCSCKCoeffs601[2];
1750    }
1751    else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1752    {
1753       Kr = studioCSCKCoeffs709[0];
1754       Kg = studioCSCKCoeffs709[1];
1755       Kb = studioCSCKCoeffs709[2];
1756    }
1757    // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1758    studioCSCMatrix[R][Y] = 1.0;
1759    studioCSCMatrix[G][Y] = 1.0;
1760    studioCSCMatrix[B][Y] = 1.0;
1761
1762    studioCSCMatrix[R][Cb] = 0.0;
1763    studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1764    studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1765
1766    studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1767    studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1768    studioCSCMatrix[B][Cr] = 0.0;
1769
1770    studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1771    studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1772    studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1773
1774    return true;
1775 }
1776
1777 void CMixer::SetColor()
1778 {
1779   VdpStatus vdp_st;
1780
1781   if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1782     m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1783   if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1784     m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1785
1786   VdpColorStandard colorStandard;
1787   switch(m_mixerInput[1].DVDPic.color_matrix)
1788   {
1789     case AVCOL_SPC_BT709:
1790       colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1791       break;
1792     case AVCOL_SPC_BT470BG:
1793     case AVCOL_SPC_SMPTE170M:
1794       colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1795       break;
1796     case AVCOL_SPC_SMPTE240M:
1797       colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1798       break;
1799     case AVCOL_SPC_FCC:
1800     case AVCOL_SPC_UNSPECIFIED:
1801     case AVCOL_SPC_RGB:
1802     default:
1803       if(m_config.surfaceWidth > 1000)
1804         colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1805       else
1806         colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1807   }
1808
1809   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1810   if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1811   {
1812     float studioCSC[3][4];
1813     GenerateStudioCSCMatrix(colorStandard, studioCSC);
1814     void const * pm_CSCMatix[] = { &studioCSC };
1815     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1816   }
1817   else
1818   {
1819     vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1820     void const * pm_CSCMatix[] = { &m_CSCMatrix };
1821     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1822   }
1823
1824   CheckStatus(vdp_st, __LINE__);
1825 }
1826
1827 void CMixer::SetNoiseReduction()
1828 {
1829   if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1830     return;
1831
1832   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1833   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1834   VdpStatus vdp_st;
1835
1836   if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1837   {
1838     VdpBool enabled[]= {0};
1839     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1840     CheckStatus(vdp_st, __LINE__);
1841     return;
1842   }
1843   VdpBool enabled[]={1};
1844   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1845   CheckStatus(vdp_st, __LINE__);
1846   void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1847   CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1848   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1849   CheckStatus(vdp_st, __LINE__);
1850 }
1851
1852 void CMixer::SetSharpness()
1853 {
1854   if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1855     return;
1856
1857   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1858   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1859   VdpStatus vdp_st;
1860
1861   if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1862   {
1863     VdpBool enabled[]={0};
1864     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1865     CheckStatus(vdp_st, __LINE__);
1866     return;
1867   }
1868   VdpBool enabled[]={1};
1869   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1870   CheckStatus(vdp_st, __LINE__);
1871   void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1872   CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1873   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1874   CheckStatus(vdp_st, __LINE__);
1875 }
1876
1877 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1878 {
1879   EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1880   if (method == VS_INTERLACEMETHOD_AUTO)
1881   {
1882     int deint = -1;
1883 //    if (m_config.outHeight >= 720)
1884 //      deint = g_advancedSettings.m_videoVDPAUdeintHD;
1885 //    else
1886 //      deint = g_advancedSettings.m_videoVDPAUdeintSD;
1887
1888     if (deint != -1)
1889     {
1890       if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
1891       {
1892         method = EINTERLACEMETHOD(deint);
1893         if (log)
1894           CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d",  deint);
1895       }
1896       else
1897       {
1898         if (log)
1899           CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
1900       }
1901     }
1902   }
1903   return method;
1904 }
1905
1906 void CMixer::SetDeinterlacing()
1907 {
1908   VdpStatus vdp_st;
1909
1910   if (m_videoMixer == VDP_INVALID_HANDLE)
1911     return;
1912
1913   EDEINTERLACEMODE   mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1914   EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
1915
1916   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1917                                      VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1918                                      VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
1919
1920   if (mode == VS_DEINTERLACEMODE_OFF)
1921   {
1922     VdpBool enabled[] = {0,0,0};
1923     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1924   }
1925   else
1926   {
1927     if (method == VS_INTERLACEMETHOD_AUTO)
1928     {
1929       VdpBool enabled[] = {1,0,0};
1930       if (g_advancedSettings.m_videoVDPAUtelecine)
1931         enabled[2] = 1;
1932       vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1933     }
1934     else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
1935          ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
1936     {
1937       VdpBool enabled[] = {1,0,0};
1938       if (g_advancedSettings.m_videoVDPAUtelecine)
1939         enabled[2] = 1;
1940       vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1941     }
1942     else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
1943          ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
1944     {
1945       VdpBool enabled[] = {1,1,0};
1946       if (g_advancedSettings.m_videoVDPAUtelecine)
1947         enabled[2] = 1;
1948       vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1949     }
1950     else
1951     {
1952       VdpBool enabled[]={0,0,0};
1953       vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1954     }
1955   }
1956   CheckStatus(vdp_st, __LINE__);
1957
1958   SetDeintSkipChroma();
1959
1960   m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
1961 }
1962
1963 void CMixer::SetDeintSkipChroma()
1964 {
1965   VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
1966   VdpStatus vdp_st;
1967
1968   uint8_t val;
1969   if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
1970     val = 1;
1971   else
1972     val = 0;
1973
1974   void const *values[]={&val};
1975   vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
1976
1977   CheckStatus(vdp_st, __LINE__);
1978 }
1979
1980 void CMixer::SetHWUpscaling()
1981 {
1982 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
1983
1984   VdpStatus vdp_st;
1985   VdpBool enabled[]={1};
1986   switch (m_config.upscale)
1987   {
1988     case 9:
1989        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
1990        {
1991           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
1992           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1993           break;
1994        }
1995     case 8:
1996        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
1997        {
1998           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
1999           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2000           break;
2001        }
2002     case 7:
2003        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2004        {
2005           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2006           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2007           break;
2008        }
2009     case 6:
2010        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2011        {
2012           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2013           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2014           break;
2015        }
2016     case 5:
2017        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2018        {
2019           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2020           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2021           break;
2022        }
2023     case 4:
2024        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2025        {
2026           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2027           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2028           break;
2029        }
2030     case 3:
2031        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2032        {
2033           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2034           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2035           break;
2036        }
2037     case 2:
2038        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2039        {
2040           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2041           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2042           break;
2043        }
2044     case 1:
2045        if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2046        {
2047           VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2048           vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2049           break;
2050        }
2051     default:
2052        DisableHQScaling();
2053        return;
2054   }
2055   CheckStatus(vdp_st, __LINE__);
2056 #endif
2057 }
2058
2059 void CMixer::DisableHQScaling()
2060 {
2061   VdpStatus vdp_st;
2062
2063   if (m_videoMixer == VDP_INVALID_HANDLE)
2064     return;
2065
2066   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2067   {
2068     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2069     VdpBool enabled[]={0};
2070     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2071     CheckStatus(vdp_st, __LINE__);
2072   }
2073
2074   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2075   {
2076     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2077     VdpBool enabled[]={0};
2078     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2079     CheckStatus(vdp_st, __LINE__);
2080   }
2081
2082   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2083   {
2084     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2085     VdpBool enabled[]={0};
2086     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2087     CheckStatus(vdp_st, __LINE__);
2088   }
2089
2090   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2091   {
2092     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2093     VdpBool enabled[]={0};
2094     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2095     CheckStatus(vdp_st, __LINE__);
2096   }
2097
2098   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2099   {
2100     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2101     VdpBool enabled[]={0};
2102     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2103     CheckStatus(vdp_st, __LINE__);
2104   }
2105
2106   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2107   {
2108     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2109     VdpBool enabled[]={0};
2110     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2111     CheckStatus(vdp_st, __LINE__);
2112   }
2113
2114   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2115   {
2116     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2117     VdpBool enabled[]={0};
2118     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2119     CheckStatus(vdp_st, __LINE__);
2120   }
2121
2122   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2123   {
2124     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2125     VdpBool enabled[]={0};
2126     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2127     CheckStatus(vdp_st, __LINE__);
2128   }
2129
2130   if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2131   {
2132     VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2133     VdpBool enabled[]={0};
2134     vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2135     CheckStatus(vdp_st, __LINE__);
2136   }
2137 }
2138
2139
2140 void CMixer::Init()
2141 {
2142   m_Brightness = 0.0;
2143   m_Contrast = 0.0;
2144   m_NoiseReduction = 0.0;
2145   m_Sharpness = 0.0;
2146   m_DeintMode = 0;
2147   m_Deint = 0;
2148   m_ColorMatrix = 0;
2149   m_PostProc = false;
2150   m_vdpError = false;
2151
2152   m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2153   m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2154
2155   CreateVdpauMixer();
2156 }
2157
2158 void CMixer::Uninit()
2159 {
2160   Flush();
2161   while (!m_outputSurfaces.empty())
2162   {
2163     m_outputSurfaces.pop();
2164   }
2165   m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
2166
2167   delete [] m_BlackBar;
2168 }
2169
2170 void CMixer::Flush()
2171 {
2172   while (!m_mixerInput.empty())
2173   {
2174     CVdpauDecodedPicture pic = m_mixerInput.back();
2175     m_mixerInput.pop_back();
2176     m_config.videoSurfaces->ClearRender(pic.videoSurface);
2177   }
2178   while (!m_decodedPics.empty())
2179   {
2180     CVdpauDecodedPicture pic = m_decodedPics.front();
2181     m_decodedPics.pop();
2182     m_config.videoSurfaces->ClearRender(pic.videoSurface);
2183   }
2184   Message *msg;
2185   while (m_dataPort.ReceiveOutMessage(&msg))
2186   {
2187     if (msg->signal == CMixerDataProtocol::FRAME)
2188     {
2189       CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2190       m_config.videoSurfaces->ClearRender(pic.videoSurface);
2191     }
2192     else if (msg->signal == CMixerDataProtocol::BUFFER)
2193     {
2194       VdpOutputSurface *surf;
2195       surf = (VdpOutputSurface*)msg->data;
2196       m_outputSurfaces.push(*surf);
2197     }
2198     msg->Release();
2199   }
2200 }
2201
2202 void CMixer::InitCycle()
2203 {
2204   CheckFeatures();
2205   uint64_t latency;
2206   int flags;
2207   m_config.stats->GetParams(latency, flags);
2208   latency = (latency*1000)/CurrentHostFrequency();
2209   // TODO
2210   if (0) //flags & DVP_FLAG_NO_POSTPROC)
2211     SetPostProcFeatures(false);
2212   else
2213     SetPostProcFeatures(true);
2214
2215   m_config.stats->SetCanSkipDeint(false);
2216
2217   EDEINTERLACEMODE   mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2218   EINTERLACEMETHOD method = GetDeinterlacingMethod();
2219   bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2220
2221   // TODO
2222   if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2223       (mode == VS_DEINTERLACEMODE_FORCE ||
2224       (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2225   {
2226     if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2227       ||  method == VS_INTERLACEMETHOD_VDPAU_BOB
2228       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2229       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2230       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2231       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2232       ||  method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2233     {
2234       if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2235         || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2236         || !g_graphicsContext.IsFullScreenVideo())
2237         m_mixersteps = 1;
2238       else
2239       {
2240         m_mixersteps = 2;
2241         m_config.stats->SetCanSkipDeint(true);
2242       }
2243
2244       // TODO
2245       if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2246       {
2247         m_mixersteps = 1;
2248       }
2249
2250       if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2251         m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2252       else
2253         m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2254
2255       m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2256       m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2257                                         DVP_FLAG_REPEAT_TOP_FIELD |
2258                                         DVP_FLAG_INTERLACED);
2259       m_config.useInteropYuv = false;
2260     }
2261     else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2262     {
2263       m_mixersteps = 1;
2264       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2265       m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2266       m_config.useInteropYuv = true;
2267     }
2268     else
2269     {
2270       CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2271       m_mixersteps = 1;
2272       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2273       m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2274       m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2275                                         DVP_FLAG_REPEAT_TOP_FIELD |
2276                                         DVP_FLAG_INTERLACED);
2277
2278       CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2279     }
2280   }
2281   else
2282   {
2283     m_mixersteps = 1;
2284     m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2285
2286     if (m_config.useInteropYuv)
2287       m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2288     else
2289     {
2290       m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2291       m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2292                                         DVP_FLAG_REPEAT_TOP_FIELD |
2293                                         DVP_FLAG_INTERLACED);
2294     }
2295   }
2296   m_mixerstep = 0;
2297
2298   if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2299   {
2300     m_processPicture.outputSurface = m_outputSurfaces.front();
2301     m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2302     m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2303   }
2304   else
2305   {
2306     m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2307     m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2308   }
2309
2310   m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2311   m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2312 }
2313
2314 void CMixer::FiniCycle()
2315 {
2316   while (m_mixerInput.size() > 3)
2317   {
2318     CVdpauDecodedPicture &tmp = m_mixerInput.back();
2319     if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2320     {
2321       m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2322     }
2323     m_mixerInput.pop_back();
2324 //    m_config.stats->DecDecoded();
2325   }
2326 }
2327
2328 void CMixer::ProcessPicture()
2329 {
2330   if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2331     return;
2332
2333   VdpStatus vdp_st;
2334
2335   if (m_mixerstep == 1)
2336   {
2337     if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2338       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2339     else
2340       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2341   }
2342
2343   VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2344   VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2345   uint32_t pastCount = 4;
2346   uint32_t futuCount = 2;
2347
2348   if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2349   {
2350     // use only 2 past 1 future for progressive/weave
2351     // (only used for postproc anyway eg noise reduction)
2352     if (m_mixerInput.size() > 3)
2353       past_surfaces[1] = m_mixerInput[3].videoSurface;
2354     if (m_mixerInput.size() > 2)
2355       past_surfaces[0] = m_mixerInput[2].videoSurface;
2356     futu_surfaces[0] = m_mixerInput[0].videoSurface;
2357     pastCount = 2;
2358     futuCount = 1;
2359   }
2360   else
2361   {
2362     if(m_mixerstep == 0)
2363     { // first field
2364       if (m_mixerInput.size() > 3)
2365       {
2366         past_surfaces[3] = m_mixerInput[3].videoSurface;
2367         past_surfaces[2] = m_mixerInput[3].videoSurface;
2368       }
2369       if (m_mixerInput.size() > 2)
2370       {
2371         past_surfaces[1] = m_mixerInput[2].videoSurface;
2372         past_surfaces[0] = m_mixerInput[2].videoSurface;
2373       }
2374       futu_surfaces[0] = m_mixerInput[1].videoSurface;
2375       futu_surfaces[1] = m_mixerInput[0].videoSurface;
2376     }
2377     else
2378     { // second field
2379       if (m_mixerInput.size() > 3)
2380       {
2381         past_surfaces[3] = m_mixerInput[3].videoSurface;
2382       }
2383       if (m_mixerInput.size() > 2)
2384       {
2385         past_surfaces[2] = m_mixerInput[2].videoSurface;
2386         past_surfaces[1] = m_mixerInput[2].videoSurface;
2387       }
2388       past_surfaces[0] = m_mixerInput[1].videoSurface;
2389       futu_surfaces[0] = m_mixerInput[1].videoSurface;
2390       futu_surfaces[1] = m_mixerInput[1].videoSurface;
2391
2392       if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2393           m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2394       {
2395         m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2396                                      (m_mixerInput[0].DVDPic.pts -
2397                                       m_mixerInput[1].DVDPic.pts) / 2;
2398       }
2399       else
2400         m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2401       m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2402     }
2403     m_processPicture.DVDPic.iRepeatPicture = 0.0;
2404   } // interlaced
2405
2406   VdpRect sourceRect;
2407   sourceRect.x0 = 0;
2408   sourceRect.y0 = 0;
2409   sourceRect.x1 = m_config.vidWidth;
2410   sourceRect.y1 = m_config.vidHeight;
2411
2412   VdpRect destRect;
2413   destRect.x0 = 0;
2414   destRect.y0 = 0;
2415   destRect.x1 = m_config.outWidth;
2416   destRect.y1 = m_config.outHeight;
2417
2418   // start vdpau video mixer
2419   vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer,
2420                                 VDP_INVALID_HANDLE,
2421                                 0,
2422                                 m_mixerfield,
2423                                 pastCount,
2424                                 past_surfaces,
2425                                 m_mixerInput[1].videoSurface,
2426                                 futuCount,
2427                                 futu_surfaces,
2428                                 &sourceRect,
2429                                 m_processPicture.outputSurface,
2430                                 &destRect,
2431                                 &destRect,
2432                                 0,
2433                                 NULL);
2434   CheckStatus(vdp_st, __LINE__);
2435
2436   if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2437   {
2438     // in order to clip top and bottom lines when de-interlacing
2439     // we black those lines as a work around for not working
2440     // background colour using the mixer
2441     // pixel perfect is preferred over overscanning or zooming
2442
2443     VdpRect clipRect = destRect;
2444     clipRect.y1 = clipRect.y0 + 2;
2445     uint32_t *data[] = {m_BlackBar};
2446     uint32_t pitches[] = {destRect.x1};
2447     vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2448                                             (void**)data,
2449                                             pitches,
2450                                             &clipRect);
2451     CheckStatus(vdp_st, __LINE__);
2452
2453     clipRect = destRect;
2454     clipRect.y0 = clipRect.y1 - 2;
2455     vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2456                                             (void**)data,
2457                                             pitches,
2458                                             &clipRect);
2459     CheckStatus(vdp_st, __LINE__);
2460   }
2461 }
2462
2463
2464 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2465 {
2466   if (vdp_st != VDP_STATUS_OK)
2467   {
2468     CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
2469     m_vdpError = true;
2470     return true;
2471   }
2472   return false;
2473 }
2474
2475 //-----------------------------------------------------------------------------
2476 // Buffer Pool
2477 //-----------------------------------------------------------------------------
2478
2479 VdpauBufferPool::VdpauBufferPool()
2480 {
2481   CVdpauRenderPicture *pic;
2482   for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2483   {
2484     pic = new CVdpauRenderPicture(renderPicSec);
2485     allRenderPics.push_back(pic);
2486   }
2487 }
2488
2489 VdpauBufferPool::~VdpauBufferPool()
2490 {
2491   CVdpauRenderPicture *pic;
2492   for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2493   {
2494     pic = allRenderPics[i];
2495     delete pic;
2496   }
2497   allRenderPics.clear();
2498 }
2499
2500 //-----------------------------------------------------------------------------
2501 // Output
2502 //-----------------------------------------------------------------------------
2503 COutput::COutput(CEvent *inMsgEvent) :
2504   CThread("Vdpau Output Thread"),
2505   m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2506   m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2507   m_mixer(&m_outMsgEvent)
2508 {
2509   m_inMsgEvent = inMsgEvent;
2510
2511   for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2512   {
2513     m_bufferPool.freeRenderPics.push_back(i);
2514   }
2515 }
2516
2517 void COutput::Start()
2518 {
2519   Create();
2520 }
2521
2522 COutput::~COutput()
2523 {
2524   Dispose();
2525
2526   m_bufferPool.freeRenderPics.clear();
2527   m_bufferPool.usedRenderPics.clear();
2528 }
2529
2530 void COutput::Dispose()
2531 {
2532   CSingleLock lock(g_graphicsContext);
2533   m_bStop = true;
2534   m_outMsgEvent.Set();
2535   StopThread();
2536   m_controlPort.Purge();
2537   m_dataPort.Purge();
2538 }
2539
2540 void COutput::OnStartup()
2541 {
2542   CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2543 }
2544
2545 void COutput::OnExit()
2546 {
2547   CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2548 }
2549
2550 enum OUTPUT_STATES
2551 {
2552   O_TOP = 0,                      // 0
2553   O_TOP_ERROR,                    // 1
2554   O_TOP_UNCONFIGURED,             // 2
2555   O_TOP_CONFIGURED,               // 3
2556   O_TOP_CONFIGURED_IDLE,          // 4
2557   O_TOP_CONFIGURED_WORK,          // 5
2558 };
2559
2560 int VDPAU_OUTPUT_parentStates[] = {
2561     -1,
2562     0, //TOP_ERROR
2563     0, //TOP_UNCONFIGURED
2564     0, //TOP_CONFIGURED
2565     3, //TOP_CONFIGURED_IDLE
2566     3, //TOP_CONFIGURED_WORK
2567 };
2568
2569 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2570 {
2571   for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2572   {
2573     switch (state)
2574     {
2575     case O_TOP: // TOP
2576       if (port == &m_controlPort)
2577       {
2578         switch (signal)
2579         {
2580         case COutputControlProtocol::FLUSH:
2581           msg->Reply(COutputControlProtocol::ACC);
2582           return;
2583         case COutputControlProtocol::PRECLEANUP:
2584           msg->Reply(COutputControlProtocol::ACC);
2585           return;
2586         default:
2587           break;
2588         }
2589       }
2590       else if (port == &m_dataPort)
2591       {
2592         switch (signal)
2593         {
2594         case COutputDataProtocol::RETURNPIC:
2595           CVdpauRenderPicture *pic;
2596           pic = *((CVdpauRenderPicture**)msg->data);
2597           QueueReturnPicture(pic);
2598           return;
2599         default:
2600           break;
2601         }
2602       }
2603       {
2604         std::string portName = port == NULL ? "timer" : port->portName;
2605         CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2606       }
2607       return;
2608
2609     case O_TOP_ERROR:
2610       break;
2611
2612     case O_TOP_UNCONFIGURED:
2613       if (port == &m_controlPort)
2614       {
2615         switch (signal)
2616         {
2617         case COutputControlProtocol::INIT:
2618           CVdpauConfig *data;
2619           data = (CVdpauConfig*)msg->data;
2620           if (data)
2621           {
2622             m_config = *data;
2623           }
2624           Init();
2625           Message *reply;
2626           if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2627                                      &reply, 1000, &m_config, sizeof(m_config)))
2628           {
2629             if (reply->signal != CMixerControlProtocol::ACC)
2630               m_vdpError = true;
2631             reply->Release();
2632           }
2633
2634           // set initial number of
2635           m_bufferPool.numOutputSurfaces = 4;
2636           EnsureBufferPool();
2637           if (!m_vdpError)
2638           {
2639             m_state = O_TOP_CONFIGURED_IDLE;
2640             msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2641           }
2642           else
2643           {
2644             m_state = O_TOP_ERROR;
2645             msg->Reply(COutputControlProtocol::ERROR);
2646           }
2647           return;
2648         default:
2649           break;
2650         }
2651       }
2652       break;
2653
2654     case O_TOP_CONFIGURED:
2655       if (port == &m_controlPort)
2656       {
2657         switch (signal)
2658         {
2659         case COutputControlProtocol::FLUSH:
2660           Flush();
2661           msg->Reply(COutputControlProtocol::ACC);
2662           return;
2663         case COutputControlProtocol::PRECLEANUP:
2664           Flush();
2665           PreCleanup();
2666           msg->Reply(COutputControlProtocol::ACC);
2667           return;
2668         default:
2669           break;
2670         }
2671       }
2672       else if (port == &m_dataPort)
2673       {
2674         switch (signal)
2675         {
2676         case COutputDataProtocol::NEWFRAME:
2677           CVdpauDecodedPicture *frame;
2678           frame = (CVdpauDecodedPicture*)msg->data;
2679           if (frame)
2680           {
2681             m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2682                                                frame,sizeof(CVdpauDecodedPicture));
2683           }
2684           return;
2685         case COutputDataProtocol::RETURNPIC:
2686           CVdpauRenderPicture *pic;
2687           pic = *((CVdpauRenderPicture**)msg->data);
2688           QueueReturnPicture(pic);
2689           m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2690           m_state = O_TOP_CONFIGURED_WORK;
2691           m_extTimeout = 0;
2692           return;
2693         default:
2694           break;
2695         }
2696       }
2697       else if (port == &m_mixer.m_dataPort)
2698       {
2699         switch (signal)
2700         {
2701         case CMixerDataProtocol::PICTURE:
2702           CVdpauProcessedPicture *pic;
2703           pic = (CVdpauProcessedPicture*)msg->data;
2704           m_bufferPool.processedPics.push(*pic);
2705           m_state = O_TOP_CONFIGURED_WORK;
2706           m_extTimeout = 0;
2707           return;
2708         default:
2709           break;
2710         }
2711       }
2712       break;
2713
2714     case O_TOP_CONFIGURED_IDLE:
2715       if (port == NULL) // timeout
2716       {
2717         switch (signal)
2718         {
2719         case COutputControlProtocol::TIMEOUT:
2720           if (ProcessSyncPicture())
2721             m_extTimeout = 10;
2722           else
2723             m_extTimeout = 100;
2724           if (HasWork())
2725           {
2726             m_state = O_TOP_CONFIGURED_WORK;
2727             m_extTimeout = 0;
2728           }
2729           return;
2730         default:
2731           break;
2732         }
2733       }
2734       break;
2735
2736     case O_TOP_CONFIGURED_WORK:
2737       if (port == NULL) // timeout
2738       {
2739         switch (signal)
2740         {
2741         case COutputControlProtocol::TIMEOUT:
2742           if (HasWork())
2743           {
2744             CVdpauRenderPicture *pic;
2745             pic = ProcessMixerPicture();
2746             if (pic)
2747             {
2748               m_config.stats->DecProcessed();
2749               m_config.stats->IncRender();
2750               m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2751             }
2752             m_extTimeout = 1;
2753           }
2754           else
2755           {
2756             m_state = O_TOP_CONFIGURED_IDLE;
2757             m_extTimeout = 0;
2758           }
2759           return;
2760         default:
2761           break;
2762         }
2763       }
2764       break;
2765
2766     default: // we are in no state, should not happen
2767       CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2768       return;
2769     }
2770   } // for
2771 }
2772
2773 void COutput::Process()
2774 {
2775   Message *msg = NULL;
2776   Protocol *port = NULL;
2777   bool gotMsg;
2778
2779   m_state = O_TOP_UNCONFIGURED;
2780   m_extTimeout = 1000;
2781   m_bStateMachineSelfTrigger = false;
2782
2783   while (!m_bStop)
2784   {
2785     gotMsg = false;
2786
2787     if (m_bStateMachineSelfTrigger)
2788     {
2789       m_bStateMachineSelfTrigger = false;
2790       // self trigger state machine
2791       StateMachine(msg->signal, port, msg);
2792       if (!m_bStateMachineSelfTrigger)
2793       {
2794         msg->Release();
2795         msg = NULL;
2796       }
2797       continue;
2798     }
2799     // check control port
2800     else if (m_controlPort.ReceiveOutMessage(&msg))
2801     {
2802       gotMsg = true;
2803       port = &m_controlPort;
2804     }
2805     // check data port
2806     else if (m_dataPort.ReceiveOutMessage(&msg))
2807     {
2808       gotMsg = true;
2809       port = &m_dataPort;
2810     }
2811     // check mixer data port
2812     else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2813     {
2814       gotMsg = true;
2815       port = &m_mixer.m_dataPort;
2816     }
2817     if (gotMsg)
2818     {
2819       StateMachine(msg->signal, port, msg);
2820       if (!m_bStateMachineSelfTrigger)
2821       {
2822         msg->Release();
2823         msg = NULL;
2824       }
2825       continue;
2826     }
2827
2828     // wait for message
2829     else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2830     {
2831       continue;
2832     }
2833     // time out
2834     else
2835     {
2836       msg = m_controlPort.GetMessage();
2837       msg->signal = COutputControlProtocol::TIMEOUT;
2838       port = 0;
2839       // signal timeout to state machine
2840       StateMachine(msg->signal, port, msg);
2841       if (!m_bStateMachineSelfTrigger)
2842       {
2843         msg->Release();
2844         msg = NULL;
2845       }
2846     }
2847   }
2848   Flush();
2849   Uninit();
2850 }
2851
2852 bool COutput::Init()
2853 {
2854   if (!CreateGlxContext())
2855     return false;
2856
2857   if (!GLInit())
2858     return false;
2859
2860   m_mixer.Start();
2861   m_vdpError = false;
2862
2863   return true;
2864 }
2865
2866 bool COutput::Uninit()
2867 {
2868   m_mixer.Dispose();
2869   GLUnmapSurfaces();
2870   GLUnbindPixmaps();
2871   ReleaseBufferPool();
2872   DestroyGlxContext();
2873   return true;
2874 }
2875
2876 void COutput::Flush()
2877 {
2878   if (m_mixer.IsActive())
2879   {
2880     Message *reply;
2881     if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2882                                                  &reply,
2883                                                  2000))
2884     {
2885       reply->Release();
2886     }
2887     else
2888       CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2889   }
2890
2891   Message *msg;
2892   while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2893   {
2894     if (msg->signal == CMixerDataProtocol::PICTURE)
2895     {
2896       CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2897       m_bufferPool.processedPics.push(pic);
2898     }
2899     msg->Release();
2900   }
2901
2902   while (m_dataPort.ReceiveOutMessage(&msg))
2903   {
2904     if (msg->signal == COutputDataProtocol::NEWFRAME)
2905     {
2906       CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2907       m_config.videoSurfaces->ClearRender(pic.videoSurface);
2908     }
2909     else if (msg->signal == COutputDataProtocol::RETURNPIC)
2910     {
2911       CVdpauRenderPicture *pic;
2912       pic = *((CVdpauRenderPicture**)msg->data);
2913       QueueReturnPicture(pic);
2914     }
2915     msg->Release();
2916   }
2917
2918   while (m_dataPort.ReceiveInMessage(&msg))
2919   {
2920     if (msg->signal == COutputDataProtocol::PICTURE)
2921     {
2922       CVdpauRenderPicture *pic;
2923       pic = *((CVdpauRenderPicture**)msg->data);
2924       QueueReturnPicture(pic);
2925     }
2926   }
2927
2928   // reset used render flag which was cleared on mixer flush
2929   std::deque<int>::iterator it;
2930   for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
2931   {
2932     CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
2933     if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
2934     {
2935       std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
2936       it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
2937       if (it2 == m_bufferPool.glVideoSurfaceMap.end())
2938       {
2939         CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
2940         continue;
2941       }
2942       m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
2943     }
2944   }
2945
2946   // clear processed pics
2947   while(!m_bufferPool.processedPics.empty())
2948   {
2949     CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
2950     if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
2951     {
2952       m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
2953     }
2954     else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
2955     {
2956       m_config.videoSurfaces->ClearRender(procPic.videoSurface);
2957     }
2958     m_bufferPool.processedPics.pop();
2959   }
2960 }
2961
2962 bool COutput::HasWork()
2963 {
2964   if (m_config.usePixmaps)
2965   {
2966     if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2967       return true;
2968     if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
2969       return true;
2970     return false;
2971   }
2972   else
2973   {
2974     if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
2975       return true;
2976     return false;
2977   }
2978 }
2979
2980 CVdpauRenderPicture* COutput::ProcessMixerPicture()
2981 {
2982   CVdpauRenderPicture *retPic = NULL;
2983
2984   if (m_config.usePixmaps)
2985   {
2986     if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2987     {
2988       unsigned int i = FindFreePixmap();
2989       VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[i];
2990       pixmap->used = true;
2991       CVdpauProcessedPicture pic = m_bufferPool.processedPics.front();
2992       m_bufferPool.processedPics.pop();
2993       pixmap->surface = pic.outputSurface;
2994       pixmap->DVDPic = pic.DVDPic;
2995       pixmap->id = i;
2996       m_bufferPool.notVisiblePixmaps.push_back(i);
2997       m_config.vdpProcs.vdp_presentation_queue_display(pixmap->vdp_flip_queue,
2998                                                        pixmap->surface,0,0,0);
2999     }
3000     if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
3001     {
3002       VdpStatus vdp_st;
3003       VdpTime time;
3004       VdpPresentationQueueStatus status;
3005       int idx = m_bufferPool.notVisiblePixmaps.front();
3006       VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[idx];
3007       vdp_st = m_config.vdpProcs.vdp_presentation_queue_query_surface_status(
3008                         pixmap->vdp_flip_queue, pixmap->surface, &status, &time);
3009
3010       if (vdp_st == VDP_STATUS_OK && status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE)
3011       {
3012         int idx = m_bufferPool.freeRenderPics.front();
3013         retPic = m_bufferPool.allRenderPics[idx];
3014         m_bufferPool.freeRenderPics.pop_front();
3015         m_bufferPool.usedRenderPics.push_back(idx);
3016         retPic->sourceIdx = pixmap->id;
3017         retPic->DVDPic = pixmap->DVDPic;
3018         retPic->valid = true;
3019         retPic->texture[0] = pixmap->texture;
3020         retPic->crop = CRect(0,0,0,0);
3021         m_bufferPool.notVisiblePixmaps.pop_front();
3022         m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &pixmap->surface, sizeof(pixmap->surface));
3023       }
3024     }
3025   } // pixmap
3026   else if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3027   {
3028     int idx = m_bufferPool.freeRenderPics.front();
3029     retPic = m_bufferPool.allRenderPics[idx];
3030     m_bufferPool.freeRenderPics.pop_front();
3031     m_bufferPool.usedRenderPics.push_back(idx);
3032     CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3033     m_bufferPool.processedPics.pop();
3034
3035     retPic->DVDPic = procPic.DVDPic;
3036     retPic->valid = true;
3037     if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3038     {
3039       m_config.useInteropYuv = false;
3040       m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3041       EnsureBufferPool();
3042       GLMapSurfaces();
3043       retPic->sourceIdx = procPic.outputSurface;
3044       retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3045       retPic->crop = CRect(0,0,0,0);
3046     }
3047     else
3048     {
3049       m_config.useInteropYuv = true;
3050       GLMapSurfaces();
3051       retPic->sourceIdx = procPic.videoSurface;
3052       for (unsigned int i=0; i<4; ++i)
3053         retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3054       retPic->texWidth = m_config.surfaceWidth;
3055       retPic->texHeight = m_config.surfaceHeight;
3056       retPic->crop.x1 = 0;
3057       retPic->crop.y1 = 0;
3058       retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3059       retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3060     }
3061   }
3062   return retPic;
3063 }
3064
3065 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3066 {
3067   std::deque<int>::iterator it;
3068   for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3069   {
3070     if (m_bufferPool.allRenderPics[*it] == pic)
3071     {
3072       break;
3073     }
3074   }
3075
3076   if (it == m_bufferPool.usedRenderPics.end())
3077   {
3078     CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3079     return;
3080   }
3081
3082   // check if already queued
3083   std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3084                                        m_bufferPool.syncRenderPics.end(),
3085                                        *it);
3086   if (it2 == m_bufferPool.syncRenderPics.end())
3087   {
3088     m_bufferPool.syncRenderPics.push_back(*it);
3089   }
3090
3091   ProcessSyncPicture();
3092 }
3093
3094 bool COutput::ProcessSyncPicture()
3095 {
3096   CVdpauRenderPicture *pic;
3097   bool busy = false;
3098
3099   std::deque<int>::iterator it;
3100   for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3101   {
3102     pic = m_bufferPool.allRenderPics[*it];
3103
3104 #ifdef GL_ARB_sync
3105     if (pic->usefence)
3106     {
3107       if (glIsSync(pic->fence))
3108       {
3109         GLint state;
3110         GLsizei length;
3111         glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3112         if(state == GL_SIGNALED)
3113         {
3114           glDeleteSync(pic->fence);
3115           pic->fence = None;
3116         }
3117         else
3118         {
3119           busy = true;
3120           ++it;
3121           continue;
3122         }
3123       }
3124     }
3125 #endif
3126
3127     m_bufferPool.freeRenderPics.push_back(*it);
3128
3129     std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3130                                          m_bufferPool.usedRenderPics.end(),
3131                                          *it);
3132     if (it2 == m_bufferPool.usedRenderPics.end())
3133     {
3134       CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3135     }
3136     else
3137     {
3138       m_bufferPool.usedRenderPics.erase(it2);
3139     }
3140     it = m_bufferPool.syncRenderPics.erase(it);
3141
3142     if (pic->valid)
3143     {
3144       ProcessReturnPicture(pic);
3145     }
3146     else
3147     {
3148       CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3149     }
3150   }
3151   return busy;
3152 }
3153
3154 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3155 {
3156   if (m_config.usePixmaps)
3157   {
3158     m_bufferPool.pixmaps[pic->sourceIdx].used = false;
3159     return;
3160   }
3161   else if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3162   {
3163     std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3164     it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3165     if (it == m_bufferPool.glVideoSurfaceMap.end())
3166     {
3167       CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3168       return;
3169     }
3170     VdpVideoSurface surf = it->second.sourceVuv;
3171     m_config.videoSurfaces->ClearRender(surf);
3172   }
3173   else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3174   {
3175     std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3176     it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3177     if (it == m_bufferPool.glOutputSurfaceMap.end())
3178     {
3179       CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3180       return;
3181     }
3182     VdpOutputSurface outSurf = it->second.sourceRgb;
3183     m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3184   }
3185 }
3186
3187 int COutput::FindFreePixmap()
3188 {
3189   // find free pixmap
3190   unsigned int i;
3191   for (i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3192   {
3193     if (!m_bufferPool.pixmaps[i].used)
3194       break;
3195   }
3196   if (i == m_bufferPool.pixmaps.size())
3197     return -1;
3198   else
3199     return i;
3200 }
3201
3202 bool COutput::EnsureBufferPool()
3203 {
3204   VdpStatus vdp_st;
3205
3206   // Creation of outputSurfaces
3207   VdpOutputSurface outputSurface;
3208   for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3209   {
3210     vdp_st = m_config.vdpProcs.vdp_output_surface_create(m_config.vdpDevice,
3211                                       VDP_RGBA_FORMAT_B8G8R8A8,
3212                                       m_config.outWidth,
3213                                       m_config.outHeight,
3214                                       &outputSurface);
3215     if (CheckStatus(vdp_st, __LINE__))
3216       return false;
3217     m_bufferPool.outputSurfaces.push_back(outputSurface);
3218
3219     m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3220                                       &outputSurface,
3221                                       sizeof(VdpOutputSurface));
3222     CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3223   }
3224
3225
3226   if (m_config.usePixmaps && m_bufferPool.pixmaps.empty())
3227   {
3228     // create pixmpas
3229     VdpauBufferPool::Pixmaps pixmap;
3230     unsigned int numPixmaps = NUM_RENDER_PICS;
3231     for (unsigned int i = 0; i < numPixmaps; i++)
3232     {
3233       pixmap.pixmap = None;
3234       pixmap.glPixmap = None;
3235       pixmap.vdp_flip_queue = VDP_INVALID_HANDLE;
3236       pixmap.vdp_flip_target = VDP_INVALID_HANDLE;
3237       MakePixmap(pixmap);
3238       glXMakeCurrent(m_Display, None, NULL);
3239       vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_create_x11(m_config.vdpDevice,
3240                                              pixmap.pixmap, //x_window,
3241                                              &pixmap.vdp_flip_target);
3242
3243       CheckStatus(vdp_st, __LINE__);
3244
3245       vdp_st = m_config.vdpProcs.vdp_presentation_queue_create(m_config.vdpDevice,
3246                                             pixmap.vdp_flip_target,
3247                                             &pixmap.vdp_flip_queue);
3248       CheckStatus(vdp_st, __LINE__);
3249       glXMakeCurrent(m_Display, m_glPixmap, m_glContext);
3250
3251       pixmap.id = i;
3252       pixmap.used = false;
3253       m_bufferPool.pixmaps.push_back(pixmap);
3254     }
3255     GLBindPixmaps();
3256   }
3257
3258   return true;
3259 }
3260
3261 void COutput::ReleaseBufferPool()
3262 {
3263   VdpStatus vdp_st;
3264
3265   CSingleLock lock(m_bufferPool.renderPicSec);
3266
3267   if (m_config.usePixmaps)
3268   {
3269     for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3270     {
3271       if (m_bufferPool.pixmaps[i].vdp_flip_queue != VDP_INVALID_HANDLE)
3272       {
3273         vdp_st = m_config.vdpProcs.vdp_presentation_queue_destroy(m_bufferPool.pixmaps[i].vdp_flip_queue);
3274         CheckStatus(vdp_st, __LINE__);
3275       }
3276       if (m_bufferPool.pixmaps[i].vdp_flip_target != VDP_INVALID_HANDLE)
3277       {
3278         vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_destroy(m_bufferPool.pixmaps[i].vdp_flip_target);
3279         CheckStatus(vdp_st, __LINE__);
3280       }
3281       if (m_bufferPool.pixmaps[i].glPixmap)
3282       {
3283         glXDestroyPixmap(m_Display, m_bufferPool.pixmaps[i].glPixmap);
3284       }
3285       if (m_bufferPool.pixmaps[i].pixmap)
3286       {
3287         XFreePixmap(m_Display, m_bufferPool.pixmaps[i].pixmap);
3288       }
3289     }
3290     m_bufferPool.pixmaps.clear();
3291   }
3292
3293   // release all output surfaces
3294   for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3295   {
3296     if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3297       continue;
3298     vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3299     CheckStatus(vdp_st, __LINE__);
3300   }
3301   m_bufferPool.outputSurfaces.clear();
3302
3303   // wait for all fences
3304   XbmcThreads::EndTime timeout(1000);
3305   for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3306   {
3307     CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3308     if (pic->usefence)
3309     {
3310 #ifdef GL_ARB_sync
3311       while (glIsSync(pic->fence))
3312       {
3313         GLint state;
3314         GLsizei length;
3315         glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3316         if(state == GL_SIGNALED || timeout.IsTimePast())
3317         {
3318           glDeleteSync(pic->fence);
3319         }
3320         else
3321         {
3322           Sleep(5);
3323         }
3324       }
3325       pic->fence = None;
3326 #endif
3327     }
3328   }
3329   if (timeout.IsTimePast())
3330   {
3331     CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3332   }
3333   ProcessSyncPicture();
3334
3335   // invalidate all used render pictures
3336   for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3337   {
3338     CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3339     pic->valid = false;
3340   }
3341 }
3342
3343 void COutput::PreCleanup()
3344 {
3345
3346   VdpStatus vdp_st;
3347
3348   m_mixer.Dispose();
3349   ProcessSyncPicture();
3350
3351   CSingleLock lock(m_bufferPool.renderPicSec);
3352   for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3353   {
3354     if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3355       continue;
3356
3357     // check if output surface is in use
3358     bool used = false;
3359     std::deque<int>::iterator it;
3360     CVdpauRenderPicture *pic;
3361     for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3362     {
3363       pic = m_bufferPool.allRenderPics[*it];
3364       if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3365       {
3366         used = true;
3367         break;
3368       }
3369     }
3370     if (used)
3371       continue;
3372
3373 #ifdef GL_NV_vdpau_interop
3374     // unmap surface
3375     std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3376     it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3377     if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3378     {
3379       CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3380       continue;
3381     }
3382     glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3383     glDeleteTextures(1, it_map->second.texture);
3384     m_bufferPool.glOutputSurfaceMap.erase(it_map);
3385 #endif
3386
3387     vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3388     CheckStatus(vdp_st, __LINE__);
3389
3390     m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3391
3392     CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3393   }
3394
3395 }
3396
3397 void COutput::InitMixer()
3398 {
3399   for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3400   {
3401     m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3402                                       &m_bufferPool.outputSurfaces[i],
3403                                       sizeof(VdpOutputSurface));
3404   }
3405 }
3406
3407 bool COutput::MakePixmap(VdpauBufferPool::Pixmaps &pixmap)
3408 {
3409   CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", m_config.outWidth, m_config.outHeight);
3410
3411     // Get our window attribs.
3412   XWindowAttributes wndattribs;
3413   XGetWindowAttributes(m_Display, g_Windowing.GetWindow(), &wndattribs);
3414
3415   pixmap.pixmap = XCreatePixmap(m_Display,
3416                            g_Windowing.GetWindow(),
3417                            m_config.outWidth,
3418                            m_config.outHeight,
3419                            wndattribs.depth);
3420   if (!pixmap.pixmap)
3421   {
3422     CLog::Log(LOGERROR, "VDPAU::COUtput::MakePixmap - GLX Error: MakePixmap: Unable to create XPixmap");
3423     return false;
3424   }
3425
3426 //  XGCValues values = {};
3427 //  GC xgc;
3428 //  values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
3429 //  xgc = XCreateGC(m_Display, pixmap.pixmap, GCForeground, &values);
3430 //  XFillRectangle(m_Display, pixmap.pixmap, xgc, 0, 0, m_config.outWidth, m_config.outHeight);
3431 //  XFreeGC(m_Display, xgc);
3432
3433   if(!MakePixmapGL(pixmap))
3434     return false;
3435
3436   return true;
3437 }
3438
3439 bool COutput::MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap)
3440 {
3441   int num=0;
3442   int fbConfigIndex = 0;
3443
3444   int doubleVisAttributes[] = {
3445     GLX_RENDER_TYPE, GLX_RGBA_BIT,
3446     GLX_RED_SIZE, 8,
3447     GLX_GREEN_SIZE, 8,
3448     GLX_BLUE_SIZE, 8,
3449     GLX_ALPHA_SIZE, 8,
3450     GLX_DEPTH_SIZE, 8,
3451     GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
3452     GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
3453     GLX_DOUBLEBUFFER, False,
3454     GLX_Y_INVERTED_EXT, True,
3455     GLX_X_RENDERABLE, True,
3456     None
3457   };
3458
3459   int pixmapAttribs[] = {
3460     GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
3461     GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
3462     None
3463   };
3464
3465   GLXFBConfig *fbConfigs;
3466   fbConfigs = glXChooseFBConfig(m_Display, g_Windowing.GetCurrentScreen(), doubleVisAttributes, &num);
3467   if (fbConfigs==NULL)
3468   {
3469     CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - No compatible framebuffers found");
3470     return false;
3471   }
3472   fbConfigIndex = 0;
3473
3474   pixmap.glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pixmap.pixmap, pixmapAttribs);
3475
3476   if (!pixmap.glPixmap)
3477   {
3478     CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - Could not create Pixmap");
3479     XFree(fbConfigs);
3480     return false;
3481   }
3482   XFree(fbConfigs);
3483   return true;
3484 }
3485
3486 bool COutput::GLInit()
3487 {
3488   glXBindTexImageEXT = NULL;
3489   glXReleaseTexImageEXT = NULL;
3490 #ifdef GL_NV_vdpau_interop
3491   glVDPAUInitNV = NULL;
3492   glVDPAUFiniNV = NULL;
3493   glVDPAURegisterOutputSurfaceNV = NULL;
3494   glVDPAURegisterVideoSurfaceNV = NULL;
3495   glVDPAUIsSurfaceNV = NULL;
3496   glVDPAUUnregisterSurfaceNV = NULL;
3497   glVDPAUSurfaceAccessNV = NULL;
3498   glVDPAUMapSurfacesNV = NULL;
3499   glVDPAUUnmapSurfacesNV = NULL;
3500   glVDPAUGetSurfaceivNV = NULL;
3501 #endif
3502
3503   m_config.usePixmaps = false;
3504
3505 #ifdef GL_NV_vdpau_interop
3506   if (glewIsSupported("GL_NV_vdpau_interop"))
3507   {
3508     if (!glVDPAUInitNV)
3509       glVDPAUInitNV    = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3510     if (!glVDPAUFiniNV)
3511       glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3512     if (!glVDPAURegisterOutputSurfaceNV)
3513       glVDPAURegisterOutputSurfaceNV    = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3514     if (!glVDPAURegisterVideoSurfaceNV)
3515       glVDPAURegisterVideoSurfaceNV    = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3516     if (!glVDPAUIsSurfaceNV)
3517       glVDPAUIsSurfaceNV    = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3518     if (!glVDPAUUnregisterSurfaceNV)
3519       glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3520     if (!glVDPAUSurfaceAccessNV)
3521       glVDPAUSurfaceAccessNV    = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3522     if (!glVDPAUMapSurfacesNV)
3523       glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3524     if (!glVDPAUUnmapSurfacesNV)
3525       glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3526     if (!glVDPAUGetSurfaceivNV)
3527       glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3528
3529     CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported");
3530   }
3531   else
3532 #endif
3533   {
3534     m_config.usePixmaps = true;
3535     CSettings::Get().SetBool("videoplayer.usevdpaumixer",true);
3536   }
3537   if (!glXBindTexImageEXT)
3538     glXBindTexImageEXT    = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
3539   if (!glXReleaseTexImageEXT)
3540     glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
3541
3542 #ifdef GL_NV_vdpau_interop
3543   if (!m_config.usePixmaps)
3544   {
3545     while (glGetError() != GL_NO_ERROR);
3546     glVDPAUInitNV(reinterpret_cast<void*>(m_config.vdpDevice), reinterpret_cast<void*>(m_config.vdpProcs.vdp_get_proc_address));
3547     if (glGetError() != GL_NO_ERROR)
3548     {
3549       CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3550       m_vdpError = true;
3551       return false;
3552     }
3553     CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3554   }
3555 #endif
3556
3557 #ifdef GL_ARB_sync
3558   bool hasfence = glewIsSupported("GL_ARB_sync");
3559   for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3560   {
3561     m_bufferPool.allRenderPics[i]->usefence = hasfence;
3562   }
3563 #endif
3564
3565   return true;
3566 }
3567
3568 void COutput::GLMapSurfaces()
3569 {
3570 #ifdef GL_NV_vdpau_interop
3571   if (m_config.usePixmaps)
3572     return;
3573
3574   if (m_config.useInteropYuv)
3575   {
3576     VdpauBufferPool::GLVideoSurface glSurface;
3577     VdpVideoSurface surf;
3578     if (m_config.videoSurfaces->Size() != m_bufferPool.glVideoSurfaceMap.size())
3579     {
3580       for (unsigned int i = 0; i < m_config.videoSurfaces->Size(); i++)
3581       {
3582         surf = m_config.videoSurfaces->GetAtIndex(i);
3583
3584         if (surf == VDP_INVALID_HANDLE)
3585           continue;
3586
3587         if (m_bufferPool.glVideoSurfaceMap.find(surf) == m_bufferPool.glVideoSurfaceMap.end())
3588         {
3589           glSurface.sourceVuv = surf;
3590           while (glGetError() != GL_NO_ERROR) ;
3591           glGenTextures(4, glSurface.texture);
3592           if (glGetError() != GL_NO_ERROR)
3593           {
3594              CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3595              m_vdpError = true;
3596           }
3597           glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3598                                                     GL_TEXTURE_2D, 4, glSurface.texture);
3599
3600           if (glGetError() != GL_NO_ERROR)
3601           {
3602             CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3603             m_vdpError = true;
3604           }
3605           glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3606           if (glGetError() != GL_NO_ERROR)
3607           {
3608             CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3609             m_vdpError = true;
3610           }
3611           glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3612           if (glGetError() != GL_NO_ERROR)
3613           {
3614             CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3615             m_vdpError = true;
3616           }
3617           m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3618           if (m_vdpError)
3619             return;
3620           CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3621         }
3622       }
3623     }
3624   }
3625   else
3626   {
3627     if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces)
3628     {
3629       VdpauBufferPool::GLVideoSurface glSurface;
3630       for (unsigned int i = m_bufferPool.glOutputSurfaceMap.size(); i<m_bufferPool.outputSurfaces.size(); i++)
3631       {
3632         glSurface.sourceRgb = m_bufferPool.outputSurfaces[i];
3633         glGenTextures(1, glSurface.texture);
3634         glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[i]),
3635                                                GL_TEXTURE_2D, 1, glSurface.texture);
3636         if (glGetError() != GL_NO_ERROR)
3637         {
3638           CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3639           m_vdpError = true;
3640         }
3641         glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3642         if (glGetError() != GL_NO_ERROR)
3643         {
3644           CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3645           m_vdpError = true;
3646         }
3647         glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3648         if (glGetError() != GL_NO_ERROR)
3649         {
3650           CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3651           m_vdpError = true;
3652         }
3653         m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface;
3654         if (m_vdpError)
3655           return;
3656       }
3657       CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3658     }
3659   }
3660 #endif
3661 }
3662
3663 void COutput::GLUnmapSurfaces()
3664 {
3665 #ifdef GL_NV_vdpau_interop
3666   if (m_config.usePixmaps)
3667     return;
3668
3669   {
3670     std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3671     for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3672     {
3673       glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3674       glDeleteTextures(4, it->second.texture);
3675     }
3676     m_bufferPool.glVideoSurfaceMap.clear();
3677   }
3678
3679   std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3680   for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3681   {
3682     glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3683     glDeleteTextures(1, it->second.texture);
3684   }
3685   m_bufferPool.glOutputSurfaceMap.clear();
3686
3687   glVDPAUFiniNV();
3688
3689   CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3690
3691 #endif
3692 }
3693
3694 void COutput::GLBindPixmaps()
3695 {
3696   if (!m_config.usePixmaps)
3697     return;
3698
3699   for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3700   {
3701     // create texture
3702     glGenTextures(1, &m_bufferPool.pixmaps[i].texture);
3703
3704     //bind texture
3705     glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3706
3707     // bind pixmap
3708     glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL);
3709
3710     glBindTexture(GL_TEXTURE_2D, 0);
3711   }
3712
3713   CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps");
3714 }
3715
3716 void COutput::GLUnbindPixmaps()
3717 {
3718   if (!m_config.usePixmaps)
3719     return;
3720
3721   for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3722   {
3723     // create texture
3724     if (!glIsTexture(m_bufferPool.pixmaps[i].texture))
3725       continue;
3726
3727     //bind texture
3728     glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3729
3730     // release pixmap
3731     glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT);
3732
3733     glBindTexture(GL_TEXTURE_2D, 0);
3734
3735     glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture);
3736   }
3737   CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps");
3738 }
3739
3740 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3741 {
3742   if (vdp_st != VDP_STATUS_OK)
3743   {
3744     CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
3745     m_vdpError = true;
3746     return true;
3747   }
3748   return false;
3749 }
3750
3751 bool COutput::CreateGlxContext()
3752 {
3753   GLXContext   glContext;
3754
3755   m_Display = g_Windowing.GetDisplay();
3756   glContext = g_Windowing.GetGlxContext();
3757   m_Window = g_Windowing.GetWindow();
3758
3759   // Get our window attribs.
3760   XWindowAttributes wndattribs;
3761   XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3762
3763   // Get visual Info
3764   XVisualInfo visInfo;
3765   visInfo.visualid = wndattribs.visual->visualid;
3766   int nvisuals = 0;
3767   XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3768   if (nvisuals != 1)
3769   {
3770     CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3771     return false;
3772   }
3773   visInfo = visuals[0];
3774   XFree(visuals);
3775
3776   m_pixmap = XCreatePixmap(m_Display,
3777                            m_Window,
3778                            192,
3779                            108,
3780                            visInfo.depth);
3781   if (!m_pixmap)
3782   {
3783     CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3784     return false;
3785   }
3786
3787   // create gl pixmap
3788   m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3789
3790   if (!m_glPixmap)
3791   {
3792     CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3793     return false;
3794   }
3795
3796   m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3797
3798   if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3799   {
3800     CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3801     return false;
3802   }
3803
3804   CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3805   return true;
3806 }
3807
3808 bool COutput::DestroyGlxContext()
3809 {
3810   if (m_glContext)
3811   {
3812     glXMakeCurrent(m_Display, None, NULL);
3813     glXDestroyContext(m_Display, m_glContext);
3814   }
3815   m_glContext = 0;
3816
3817   if (m_glPixmap)
3818     glXDestroyPixmap(m_Display, m_glPixmap);
3819   m_glPixmap = 0;
3820
3821   if (m_pixmap)
3822     XFreePixmap(m_Display, m_pixmap);
3823   m_pixmap = 0;
3824
3825   return true;
3826 }
3827
3828 #endif