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