Merge pull request #1445 from Karlson2k/win32_xml_fix
[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 "DVDCodecs/DVDCodecUtils.h"
37
38 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
39
40 CVDPAU::Desc decoder_profiles[] = {
41 {"MPEG1",        VDP_DECODER_PROFILE_MPEG1},
42 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
43 {"MPEG2_MAIN",   VDP_DECODER_PROFILE_MPEG2_MAIN},
44 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
45 {"H264_MAIN",    VDP_DECODER_PROFILE_H264_MAIN},
46 {"H264_HIGH",    VDP_DECODER_PROFILE_H264_HIGH},
47 {"VC1_SIMPLE",   VDP_DECODER_PROFILE_VC1_SIMPLE},
48 {"VC1_MAIN",     VDP_DECODER_PROFILE_VC1_MAIN},
49 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
50 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
51 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
52 #endif
53 };
54 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CVDPAU::Desc);
55
56 static float studioCSC[3][4] =
57 {
58     { 1.0f,        0.0f, 1.57480000f,-0.78740000f},
59     { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f},
60     { 1.0f, 1.85556000f,        0.0f,-0.92780000f}
61 };
62
63 static struct SInterlaceMapping
64 {
65   const EINTERLACEMETHOD     method;
66   const VdpVideoMixerFeature feature;
67 } g_interlace_mapping[] = 
68 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL             , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
69 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF        , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
70 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL     , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
71 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
72 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE     , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} 
73 , {VS_INTERLACEMETHOD_NONE                       , (VdpVideoMixerFeature)-1}
74 };
75
76 //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
77 //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
78 //so we just keep a static handle to libvdpau around
79 void* CVDPAU::dl_handle;
80
81 CVDPAU::CVDPAU()
82 {
83   glXBindTexImageEXT = NULL;
84   glXReleaseTexImageEXT = NULL;
85   vdp_device = VDP_INVALID_HANDLE;
86   surfaceNum      = presentSurfaceNum = 0;
87   picAge.b_age    = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64;
88   vdpauConfigured = false;
89   m_DisplayState = VDPAU_OPEN;
90   m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
91   m_mixerstep  = 0;
92
93   m_glPixmap = 0;
94   m_Pixmap = 0;
95   if (!glXBindTexImageEXT)
96     glXBindTexImageEXT    = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
97   if (!glXReleaseTexImageEXT)
98     glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
99
100   totalAvailableOutputSurfaces = 0;
101   outputSurface = presentSurface = VDP_INVALID_HANDLE;
102   vdp_flip_target = VDP_INVALID_HANDLE;
103   vdp_flip_queue = VDP_INVALID_HANDLE;
104   vid_width = vid_height = OutWidth = OutHeight = 0;
105   surface_width = surface_height = 0;
106   
107   memset(&decoder, 0, sizeof(decoder));
108   memset(&outRect, 0, sizeof(outRect));
109   memset(&outRectVid, 0, sizeof(outRectVid));
110
111   m_Display = NULL;
112
113   tmpBrightness  = 0;
114   tmpContrast    = 0;
115   tmpDeintMode   = 0;
116   tmpDeintGUI    = 0;
117   tmpDeint       = 0;
118   max_references = 0;
119
120   for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
121     outputSurfaces[i] = VDP_INVALID_HANDLE;
122
123   videoMixer = VDP_INVALID_HANDLE;
124   m_BlackBar = NULL;
125
126   memset(m_features, 0, sizeof(m_features));
127   m_feature_count = 0;
128   m_vdpauOutputMethod = OUTPUT_NONE;
129
130   upScale = g_advancedSettings.m_videoVDPAUScaling;
131
132   vdp_video_mixer_set_attribute_values = NULL;
133   vdp_generate_csc_matrix = NULL;
134   vdp_presentation_queue_target_destroy = NULL;
135   vdp_presentation_queue_create = NULL;
136   vdp_presentation_queue_destroy = NULL;
137   vdp_presentation_queue_display = NULL;
138   vdp_presentation_queue_block_until_surface_idle = NULL;
139   vdp_presentation_queue_target_create_x11 = NULL;
140   vdp_presentation_queue_query_surface_status = NULL;
141   vdp_presentation_queue_get_time = NULL;
142   vdp_get_error_string = NULL;
143   vdp_decoder_create = NULL;
144   vdp_decoder_destroy = NULL;
145   vdp_decoder_render = NULL;
146   vdp_decoder_query_caps = NULL;
147   vdp_preemption_callback_register = NULL;
148   dl_vdp_device_create_x11 = NULL;
149   dl_vdp_get_proc_address = NULL;
150   dl_vdp_preemption_callback_register = NULL;
151   past[0] = NULL;
152   past[1] = NULL;
153   current = NULL;
154   future = NULL;
155   tmpNoiseReduction = 0.0f;
156   tmpSharpness = 0.0f;
157   vdp_get_proc_address = NULL;
158   vdp_device_destroy = NULL;
159   vdp_video_surface_create = NULL;
160   vdp_video_surface_destroy = NULL;
161   vdp_video_surface_put_bits_y_cb_cr = NULL;
162   vdp_video_surface_get_bits_y_cb_cr = NULL;
163   vdp_output_surface_put_bits_y_cb_cr = NULL;
164   vdp_output_surface_put_bits_native = NULL;
165   vdp_output_surface_create = NULL;
166   vdp_output_surface_destroy = NULL;
167   vdp_output_surface_get_bits_native = NULL;
168   vdp_output_surface_render_output_surface = NULL;
169   vdp_output_surface_put_bits_indexed = NULL;
170   vdp_video_mixer_create = NULL;
171   vdp_video_mixer_set_feature_enables = NULL;
172   vdp_video_mixer_query_parameter_support = NULL;
173   vdp_video_mixer_query_feature_support = NULL;
174   vdp_video_mixer_destroy = NULL;
175   vdp_video_mixer_render = NULL;
176   m_hwContext.bitstream_buffers_allocated = 0;
177 }
178
179 bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
180 {
181   if(avctx->coded_width  == 0
182   || avctx->coded_height == 0)
183   {
184     CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
185     return false;
186   }
187
188   if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
189     return false;
190
191   if (!dl_handle)
192   {
193     dl_handle  = dlopen("libvdpau.so.1", RTLD_LAZY);
194     if (!dl_handle)
195     {
196       const char* error = dlerror();
197       if (!error)
198         error = "dlerror() returned NULL";
199
200       CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
201       //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
202
203       return false;
204     }
205   }
206
207   if (!m_dllAvUtil.Load())
208     return false;
209
210   InitVDPAUProcs();
211
212   if (vdp_device != VDP_INVALID_HANDLE)
213   {
214     SpewHardwareAvailable();
215
216     VdpDecoderProfile profile = 0;
217     if(avctx->codec_id == AV_CODEC_ID_H264)
218       profile = VDP_DECODER_PROFILE_H264_HIGH;
219 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
220     else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
221       profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
222 #endif
223     if(profile)
224     {
225       if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
226         CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
227    
228       /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
229       VdpStatus vdp_st;
230       vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder);
231
232       if(vdp_st != VDP_STATUS_OK)
233       {
234         CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", vdp_get_error_string(vdp_st), vdp_st);
235         FiniVDPAUProcs();
236         return false;
237       }
238
239       vdp_decoder_destroy(decoder);
240       CheckStatus(vdp_st, __LINE__);
241     }
242
243     InitCSCMatrix(avctx->coded_height);
244
245     /* finally setup ffmpeg */
246     memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
247     m_hwContext.render = CVDPAU::Render;
248     m_hwContext.bitstream_buffers_allocated = 0;
249     avctx->get_buffer      = CVDPAU::FFGetBuffer;
250     avctx->release_buffer  = CVDPAU::FFReleaseBuffer;
251     avctx->draw_horiz_band = CVDPAU::FFDrawSlice;
252     avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
253     avctx->hwaccel_context = &m_hwContext;
254     avctx->thread_count    = 1;
255
256     g_Windowing.Register(this);
257     return true;
258   }
259   return false;
260 }
261
262 CVDPAU::~CVDPAU()
263 {
264   Close();
265 }
266
267 void CVDPAU::Close()
268 {
269   CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
270
271   FiniVDPAUOutput();
272   FiniVDPAUProcs();
273
274   while (!m_videoSurfaces.empty())
275   {
276     vdpau_render_state *render = m_videoSurfaces.back();
277     m_videoSurfaces.pop_back();
278     if (render->bitstream_buffers_allocated)
279       m_dllAvUtil.av_freep(&render->bitstream_buffers);
280     render->bitstream_buffers_allocated = 0;
281     free(render);
282   }
283
284   if (m_hwContext.bitstream_buffers_allocated)
285   {
286     m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
287   }
288
289   g_Windowing.Unregister(this);
290   m_dllAvUtil.Unload();
291 }
292
293 bool CVDPAU::MakePixmapGL()
294 {
295   int num=0;
296   int fbConfigIndex = 0;
297
298   int doubleVisAttributes[] = {
299     GLX_RENDER_TYPE, GLX_RGBA_BIT,
300     GLX_RED_SIZE, 8,
301     GLX_GREEN_SIZE, 8,
302     GLX_BLUE_SIZE, 8,
303     GLX_ALPHA_SIZE, 8,
304     GLX_DEPTH_SIZE, 8,
305     GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
306     GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
307     GLX_DOUBLEBUFFER, True,
308     GLX_Y_INVERTED_EXT, True,
309     GLX_X_RENDERABLE, True,
310     None
311   };
312
313   int pixmapAttribs[] = {
314     GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
315     GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
316     None
317   };
318
319   GLXFBConfig *fbConfigs;
320   fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num);
321   if (fbConfigs==NULL)
322   {
323     CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found");
324     return false;
325   }
326   CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num);
327   fbConfigIndex = 0;
328   CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex);
329
330   m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs);
331
332   if (!m_glPixmap)
333   {
334     CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap");
335     XFree(fbConfigs);
336     return false;
337   }
338   XFree(fbConfigs);
339
340   return true;
341 }
342
343 bool CVDPAU::MakePixmap(int width, int height)
344 {
345   //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
346   //this requires the least amount of gpu memory bandwidth
347   if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || upScale)
348   {
349     //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
350     if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
351     {
352       OutWidth = g_graphicsContext.GetWidth();
353       OutHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
354     }
355     else //scale height to the desktop size if the aspect ratio is smaller than the desktop
356     {
357       OutHeight = g_graphicsContext.GetHeight();
358       OutWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
359     }
360   }
361   else
362   { //let opengl scale
363     OutWidth = width;
364     OutHeight = height;
365   }
366
367   CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", OutWidth, OutHeight);
368
369     // Get our window attribs.
370   XWindowAttributes wndattribs;
371   XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); // returns a status but I don't know what success is
372
373   m_Pixmap = XCreatePixmap(m_Display,
374                            DefaultRootWindow(m_Display),
375                            OutWidth,
376                            OutHeight,
377                            wndattribs.depth);
378   if (!m_Pixmap)
379   {
380     CLog::Log(LOGERROR, "GLX Error: MakePixmap: Unable to create XPixmap");
381     return false;
382   }
383
384   XGCValues values = {};
385   GC xgc;
386   values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
387   xgc = XCreateGC(m_Display, m_Pixmap, GCForeground, &values);
388   XFillRectangle(m_Display, m_Pixmap, xgc, 0, 0, OutWidth, OutHeight);
389   XFreeGC(m_Display, xgc);
390
391   if(!MakePixmapGL())
392     return false;
393
394   return true;
395 }
396
397 void CVDPAU::BindPixmap()
398 {
399   CSharedLock lock(m_DecoderSection);
400
401   { CSharedLock dLock(m_DisplaySection);
402     if (m_DisplayState != VDPAU_OPEN)
403       return;
404   }
405
406   if (m_glPixmap)
407   {
408     if(presentSurface != VDP_INVALID_HANDLE)
409     {
410       VdpPresentationQueueStatus status;
411       VdpTime time;
412       VdpStatus vdp_st;
413       vdp_st = vdp_presentation_queue_query_surface_status(
414                     vdp_flip_queue, presentSurface, &status, &time);
415       CheckStatus(vdp_st, __LINE__);
416       while(status != VDP_PRESENTATION_QUEUE_STATUS_VISIBLE && vdp_st == VDP_STATUS_OK)
417       {
418         Sleep(1);
419         vdp_st = vdp_presentation_queue_query_surface_status(
420                       vdp_flip_queue, presentSurface, &status, &time);
421         CheckStatus(vdp_st, __LINE__);
422       }
423     }
424     
425     glXBindTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT, NULL);
426   }
427   else CLog::Log(LOGERROR,"(VDPAU) BindPixmap called without valid pixmap");
428 }
429
430 void CVDPAU::ReleasePixmap()
431 {
432   CSharedLock lock(m_DecoderSection);
433
434   { CSharedLock dLock(m_DisplaySection);
435     if (m_DisplayState != VDPAU_OPEN)
436       return;
437   }
438
439   if (m_glPixmap)
440   {
441     glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
442   }
443   else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap");
444 }
445
446 void CVDPAU::OnLostDevice()
447 {
448   CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
449
450   CExclusiveLock lock(m_DecoderSection);
451   FiniVDPAUOutput();
452   FiniVDPAUProcs();
453
454   m_DisplayState = VDPAU_LOST;
455   m_DisplayEvent.Reset();
456 }
457
458 void CVDPAU::OnResetDevice()
459 {
460   CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
461
462   CExclusiveLock lock(m_DisplaySection);
463   if (m_DisplayState == VDPAU_LOST)
464   {
465     m_DisplayState = VDPAU_RESET;
466     m_DisplayEvent.Set();
467   }
468 }
469
470 int CVDPAU::Check(AVCodecContext* avctx)
471 {
472   EDisplayState state;
473
474   { CSharedLock lock(m_DisplaySection);
475     state = m_DisplayState;
476   }
477
478   if (state == VDPAU_LOST)
479   {
480     CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
481     if (!m_DisplayEvent.WaitMSec(2000))
482     {
483       CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
484       state = VDPAU_RESET;
485     }
486     else
487     {
488       CSharedLock lock(m_DisplaySection);
489       state = m_DisplayState;
490     }
491   }
492   if (state == VDPAU_RESET || state == VDPAU_ERROR)
493   {
494     CLog::Log(LOGNOTICE,"Attempting recovery");
495
496     CSingleLock gLock(g_graphicsContext);
497     CExclusiveLock lock(m_DecoderSection);
498
499     FiniVDPAUOutput();
500     FiniVDPAUProcs();
501
502     InitVDPAUProcs();
503
504     if (state == VDPAU_RESET)
505       return VC_FLUSHED;
506     else
507       return VC_ERROR;
508   }
509   return 0;
510 }
511
512 bool CVDPAU::IsVDPAUFormat(PixelFormat format)
513 {
514   if (format == AV_PIX_FMT_VDPAU)
515     return true;
516   else
517     return false;
518 }
519
520 void CVDPAU::CheckFeatures()
521 {
522   if (videoMixer == VDP_INVALID_HANDLE)
523   {
524     CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
525     // Creation of VideoMixer.
526     VdpVideoMixerParameter parameters[] = {
527       VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
528       VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
529       VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
530     };
531
532     void const * parameter_values[] = {
533       &surface_width,
534       &surface_height,
535       &vdp_chroma_type
536     };
537
538     tmpBrightness = 0;
539     tmpContrast = 0;
540     tmpNoiseReduction = 0;
541     tmpSharpness = 0;
542
543     VdpStatus vdp_st = vdp_video_mixer_create(vdp_device,
544                                     m_feature_count,
545                                     m_features,
546                                     ARSIZE(parameters),
547                                     parameters,
548                                     parameter_values,
549                                     &videoMixer);
550     CheckStatus(vdp_st, __LINE__);
551
552     SetHWUpscaling();
553   }
554
555   if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
556       tmpContrast   != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
557   {
558     SetColor();
559     tmpBrightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
560     tmpContrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
561   }
562   if (tmpNoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
563   {
564     tmpNoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
565     SetNoiseReduction();
566   }
567   if (tmpSharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
568   {
569     tmpSharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
570     SetSharpness();
571   }
572   if (  tmpDeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
573         tmpDeintGUI  != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod ||
574        (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod()))
575   {
576     tmpDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
577     tmpDeintGUI  = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
578     if (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO)
579       tmpDeint = AutoInterlaceMethod();
580     else
581       tmpDeint = tmpDeintGUI;
582
583     SetDeinterlacing();
584   }
585 }
586
587 bool CVDPAU::Supports(VdpVideoMixerFeature feature)
588 {
589   for(int i = 0; i < m_feature_count; i++)
590   {
591     if(m_features[i] == feature)
592       return true;
593   }
594   return false;
595 }
596
597 bool CVDPAU::Supports(EINTERLACEMETHOD method)
598 {
599   if(method == VS_INTERLACEMETHOD_VDPAU_BOB
600   || method == VS_INTERLACEMETHOD_AUTO
601   || method == VS_INTERLACEMETHOD_AUTO_ION)
602     return true;
603
604   for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
605   {
606     if(p->method == method)
607       return Supports(p->feature);
608   }
609   return false;
610 }
611
612 EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod()
613 {
614   return VS_INTERLACEMETHOD_VDPAU_TEMPORAL;
615 }
616
617 void CVDPAU::SetColor()
618 {
619   VdpStatus vdp_st;
620
621   if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
622     m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
623   if (tmpContrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
624     m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
625
626   if(vid_height >= 600 || vid_width > 1024)
627     vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix);
628   else
629     vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
630
631   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
632   if (CSettings::Get().GetBool("videoscreen.limitedrange"))
633   {
634     void const * pm_CSCMatix[] = { &studioCSC };
635     vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
636   }
637   else
638   {
639     void const * pm_CSCMatix[] = { &m_CSCMatrix };
640     vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
641   }
642   CheckStatus(vdp_st, __LINE__);
643 }
644
645 void CVDPAU::SetNoiseReduction()
646 {
647   if(!Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
648     return;
649
650   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
651   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
652   VdpStatus vdp_st;
653
654   if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
655   {
656     VdpBool enabled[]= {0};
657     vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
658     CheckStatus(vdp_st, __LINE__);
659     return;
660   }
661   VdpBool enabled[]={1};
662   vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
663   CheckStatus(vdp_st, __LINE__);
664   void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
665   CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
666   vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, nr);
667   CheckStatus(vdp_st, __LINE__);
668 }
669
670 void CVDPAU::SetSharpness()
671 {
672   if(!Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
673     return;
674   
675   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
676   VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
677   VdpStatus vdp_st;
678
679   if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
680   {
681     VdpBool enabled[]={0};
682     vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
683     CheckStatus(vdp_st, __LINE__);
684     return;
685   }
686   VdpBool enabled[]={1};
687   vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
688   CheckStatus(vdp_st, __LINE__);
689   void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
690   CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
691   vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, sh);
692   CheckStatus(vdp_st, __LINE__);
693 }
694
695 void CVDPAU::SetHWUpscaling()
696 {
697 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
698   if(!Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1) || !upScale)
699     return;
700
701   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
702   VdpStatus vdp_st;
703   VdpBool enabled[]={1};
704   vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
705   CheckStatus(vdp_st, __LINE__);
706 #endif
707 }
708
709 void CVDPAU::SetDeinterlacing()
710 {
711   VdpStatus vdp_st;
712   EDEINTERLACEMODE   mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
713   EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
714   if (method == VS_INTERLACEMETHOD_AUTO)
715     method = AutoInterlaceMethod();
716
717   VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
718                                      VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
719                                      VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
720   if (mode == VS_DEINTERLACEMODE_OFF)
721   {
722     VdpBool enabled[]={0,0,0};
723     vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
724   }
725   else
726   {
727     if (method == VS_INTERLACEMETHOD_AUTO_ION)
728     {
729       if (vid_height <= 576)
730       {
731         VdpBool enabled[]={1,1,0};
732         vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
733       }
734       else if (vid_height > 576)
735       {
736         VdpBool enabled[]={1,0,0};
737         vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
738       }
739     }
740     else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
741          ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
742     {
743       VdpBool enabled[]={1,0,0};
744       vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
745     }
746     else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
747          ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
748     {
749       VdpBool enabled[]={1,1,0};
750       vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
751     }
752     else if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
753     {
754       VdpBool enabled[]={1,0,1};
755       vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
756     }
757     else
758     {
759       VdpBool enabled[]={0,0,0};
760       vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
761     }
762   }
763
764   CheckStatus(vdp_st, __LINE__);
765 }
766
767 void CVDPAU::InitVDPAUProcs()
768 {
769   char* error;
770
771   (void)dlerror();
772   dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(dl_handle, (const char*)"vdp_device_create_x11");
773   error = dlerror();
774   if (error)
775   {
776     CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
777     vdp_device = VDP_INVALID_HANDLE;
778
779     //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
780
781     return;
782   }
783
784   if (dl_vdp_device_create_x11)
785   {
786     CSingleLock lock(g_graphicsContext);
787     m_Display = g_Windowing.GetDisplay();
788   }
789   else
790   {
791     CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__);
792     vdp_device = VDP_INVALID_HANDLE;
793     return;
794   }
795
796   int mScreen = DefaultScreen(m_Display);
797   VdpStatus vdp_st;
798
799   // Create Device
800   // tested on 64bit Ubuntu 11.10 and it deadlocked without this
801   XLockDisplay(m_Display);
802   vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
803                                  mScreen, //x_screen,
804                                  &vdp_device,
805                                  &vdp_get_proc_address);
806   XUnlockDisplay(m_Display);
807
808   CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",vdp_device,vdp_st);
809   if (vdp_st != VDP_STATUS_OK)
810   {
811     CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x.  Falling back.",vdp_st);
812     vdp_device = VDP_INVALID_HANDLE;
813     return;
814   }
815
816 #define VDP_PROC(id, proc) \
817   do { \
818     vdp_st = vdp_get_proc_address(vdp_device, id, (void**)&proc); \
819     CheckStatus(vdp_st, __LINE__); \
820   } while(0);
821
822   VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING                    , vdp_get_error_string);
823   VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY                      , vdp_device_destroy);
824   VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX                 , vdp_generate_csc_matrix);
825   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE                , vdp_video_surface_create);
826   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY               , vdp_video_surface_destroy);
827   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR      , vdp_video_surface_put_bits_y_cb_cr);
828   VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR      , vdp_video_surface_get_bits_y_cb_cr);
829   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR     , vdp_output_surface_put_bits_y_cb_cr);
830   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE      , vdp_output_surface_put_bits_native);
831   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE               , vdp_output_surface_create);
832   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY              , vdp_output_surface_destroy);
833   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE      , vdp_output_surface_get_bits_native);
834   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, vdp_output_surface_render_output_surface);
835   VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED     , vdp_output_surface_put_bits_indexed);  
836   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE                  , vdp_video_mixer_create);
837   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES     , vdp_video_mixer_set_feature_enables);
838   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY                 , vdp_video_mixer_destroy);
839   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER                  , vdp_video_mixer_render);
840   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES    , vdp_video_mixer_set_attribute_values);
841   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , vdp_video_mixer_query_parameter_support);
842   VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT   , vdp_video_mixer_query_feature_support);
843   VDP_PROC(VDP_FUNC_ID_DECODER_CREATE                      , vdp_decoder_create);
844   VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY                     , vdp_decoder_destroy);
845   VDP_PROC(VDP_FUNC_ID_DECODER_RENDER                      , vdp_decoder_render);
846   VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES          , vdp_decoder_query_caps);
847   VDP_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER        , vdp_preemption_callback_register);
848   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY          , vdp_presentation_queue_target_destroy);
849   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE                  , vdp_presentation_queue_create);
850   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY                 , vdp_presentation_queue_destroy);
851   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY                 , vdp_presentation_queue_display);
852   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, vdp_presentation_queue_block_until_surface_idle);
853   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11       , vdp_presentation_queue_target_create_x11);
854   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS    , vdp_presentation_queue_query_surface_status);
855   VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME                , vdp_presentation_queue_get_time);
856   
857 #undef VDP_PROC
858
859   // set all vdpau resources to invalid
860   vdp_flip_target = VDP_INVALID_HANDLE;
861   vdp_flip_queue = VDP_INVALID_HANDLE;
862   videoMixer = VDP_INVALID_HANDLE;
863   totalAvailableOutputSurfaces = 0;
864   presentSurface = VDP_INVALID_HANDLE;
865   outputSurface = VDP_INVALID_HANDLE;
866   for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
867     outputSurfaces[i] = VDP_INVALID_HANDLE;
868
869   m_vdpauOutputMethod = OUTPUT_NONE;
870
871   CExclusiveLock lock(m_DisplaySection);
872   m_DisplayState = VDPAU_OPEN;
873   vdpauConfigured = false;
874 }
875
876 void CVDPAU::FiniVDPAUProcs()
877 {
878   if (vdp_device == VDP_INVALID_HANDLE) return;
879
880   VdpStatus vdp_st;
881   vdp_st = vdp_device_destroy(vdp_device);
882   CheckStatus(vdp_st, __LINE__);
883   vdp_device = VDP_INVALID_HANDLE;
884   vdpauConfigured = false;
885 }
886
887 void CVDPAU::InitCSCMatrix(int Height)
888 {
889   VdpStatus vdp_st;
890   m_Procamp.struct_version = VDP_PROCAMP_VERSION;
891   m_Procamp.brightness     = 0.0;
892   m_Procamp.contrast       = 1.0;
893   m_Procamp.saturation     = 1.0;
894   m_Procamp.hue            = 0;
895   vdp_st = vdp_generate_csc_matrix(&m_Procamp,
896                                    (Height < 720)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709,
897                                    &m_CSCMatrix);
898   CheckStatus(vdp_st, __LINE__);
899 }
900
901 void CVDPAU::FiniVDPAUOutput()
902 {
903   FiniOutputMethod();
904
905   if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return;
906
907   CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
908
909   VdpStatus vdp_st;
910
911   vdp_st = vdp_decoder_destroy(decoder);
912   if (CheckStatus(vdp_st, __LINE__))
913     return;
914   decoder = VDP_INVALID_HANDLE;
915
916   for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
917   {
918     vdpau_render_state *render = m_videoSurfaces[i];
919     if (render->surface != VDP_INVALID_HANDLE)
920     {
921       vdp_st = vdp_video_surface_destroy(render->surface);
922       render->surface = VDP_INVALID_HANDLE;
923     }
924     if (CheckStatus(vdp_st, __LINE__))
925       return;
926   }
927 }
928
929
930 void CVDPAU::ReadFormatOf( AVCodecID codec
931                          , VdpDecoderProfile &vdp_decoder_profile
932                          , VdpChromaType     &vdp_chroma_type)
933 {
934   switch (codec)
935   {
936     case AV_CODEC_ID_MPEG1VIDEO:
937       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
938       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
939       break;
940     case AV_CODEC_ID_MPEG2VIDEO:
941       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
942       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
943       break;
944     case  AV_CODEC_ID_H264:
945       vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
946       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
947       break;
948     case AV_CODEC_ID_WMV3:
949       vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
950       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
951       break;
952     case AV_CODEC_ID_VC1:
953       vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
954       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
955       break;
956 #if (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP)
957     case AV_CODEC_ID_MPEG4:
958       vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
959       vdp_chroma_type     = VDP_CHROMA_TYPE_420;
960       break;
961 #endif
962     default:
963       vdp_decoder_profile = 0;
964       vdp_chroma_type     = 0;
965       break;
966   }
967 }
968
969
970 bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
971 {
972   FiniVDPAUOutput();
973
974   VdpStatus vdp_st;
975   VdpDecoderProfile vdp_decoder_profile;
976   vid_width = avctx->width;
977   vid_height = avctx->height;
978   surface_width = avctx->coded_width;
979   surface_height = avctx->coded_height;
980
981   past[1] = past[0] = current = future = NULL;
982   CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width);
983   CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height);
984   ReadFormatOf(avctx->codec_id, vdp_decoder_profile, vdp_chroma_type);
985
986   if(avctx->codec_id == AV_CODEC_ID_H264)
987   {
988      max_references = ref_frames;
989      if (max_references > 16) max_references = 16;
990      if (max_references < 5)  max_references = 5;
991   }
992   else
993     max_references = 2;
994
995   vdp_st = vdp_decoder_create(vdp_device,
996                               vdp_decoder_profile,
997                               surface_width,
998                               surface_height,
999                               max_references,
1000                               &decoder);
1001   if (CheckStatus(vdp_st, __LINE__))
1002     return false;
1003
1004   m_vdpauOutputMethod = OUTPUT_NONE;
1005
1006   vdpauConfigured = true;
1007   return true;
1008 }
1009
1010 bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame)
1011 {
1012   VdpStatus vdp_st;
1013
1014   if (m_vdpauOutputMethod == OUTPUT_PIXMAP)
1015     return true;
1016
1017   FiniOutputMethod();
1018
1019   MakePixmap(avctx->width,avctx->height);
1020
1021   vdp_st = vdp_presentation_queue_target_create_x11(vdp_device,
1022                                                     m_Pixmap, //x_window,
1023                                                     &vdp_flip_target);
1024   if (CheckStatus(vdp_st, __LINE__))
1025     return false;
1026
1027   vdp_st = vdp_presentation_queue_create(vdp_device,
1028                                          vdp_flip_target,
1029                                          &vdp_flip_queue);
1030   if (CheckStatus(vdp_st, __LINE__))
1031     return false;
1032
1033   totalAvailableOutputSurfaces = 0;
1034
1035   int tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES;
1036   if (vid_width == FULLHD_WIDTH)
1037     tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES_FOR_FULLHD;
1038
1039   // Creation of outputSurfaces
1040   for (int i = 0; i < NUM_OUTPUT_SURFACES && i < tmpMaxOutputSurfaces; i++)
1041   {
1042     vdp_st = vdp_output_surface_create(vdp_device,
1043                                        VDP_RGBA_FORMAT_B8G8R8A8,
1044                                        OutWidth,
1045                                        OutHeight,
1046                                        &outputSurfaces[i]);
1047     if (CheckStatus(vdp_st, __LINE__))
1048       return false;
1049     totalAvailableOutputSurfaces++;
1050   }
1051   CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)",
1052                        totalAvailableOutputSurfaces,
1053                        tmpMaxOutputSurfaces,
1054                        NUM_OUTPUT_SURFACES);
1055
1056   // create 3 pitches of black lines needed for clipping top
1057   // and bottom lines when de-interlacing
1058   m_BlackBar = new uint32_t[3*OutWidth];
1059   memset(m_BlackBar, 0, 3*OutWidth*sizeof(uint32_t));
1060
1061   surfaceNum = presentSurfaceNum = 0;
1062   outputSurface = presentSurface = VDP_INVALID_HANDLE;
1063   videoMixer = VDP_INVALID_HANDLE;
1064
1065   m_vdpauOutputMethod = OUTPUT_PIXMAP;
1066
1067   return true;
1068 }
1069
1070 bool CVDPAU::FiniOutputMethod()
1071 {
1072   VdpStatus vdp_st;
1073
1074   if (vdp_flip_queue != VDP_INVALID_HANDLE)
1075   {
1076     vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
1077     vdp_flip_queue = VDP_INVALID_HANDLE;
1078     CheckStatus(vdp_st, __LINE__);
1079   }
1080
1081   if (vdp_flip_target != VDP_INVALID_HANDLE)
1082   {
1083     vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
1084     vdp_flip_target = VDP_INVALID_HANDLE;
1085     CheckStatus(vdp_st, __LINE__);
1086   }
1087
1088   if (m_glPixmap)
1089   {
1090     CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap");
1091     glXDestroyPixmap(m_Display, m_glPixmap);
1092     m_glPixmap = None;
1093   }
1094
1095   if (m_Pixmap)
1096   {
1097     CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap");
1098     XFreePixmap(m_Display, m_Pixmap);
1099     m_Pixmap = None;
1100   }
1101
1102   outputSurface = presentSurface = VDP_INVALID_HANDLE;
1103
1104   for (int i = 0; i < totalAvailableOutputSurfaces; i++)
1105   {
1106     if (outputSurfaces[i] == VDP_INVALID_HANDLE)
1107        continue;
1108     vdp_st = vdp_output_surface_destroy(outputSurfaces[i]);
1109     outputSurfaces[i] = VDP_INVALID_HANDLE;
1110     CheckStatus(vdp_st, __LINE__);
1111   }
1112
1113   if (videoMixer != VDP_INVALID_HANDLE)
1114   {
1115     vdp_st = vdp_video_mixer_destroy(videoMixer);
1116     videoMixer = VDP_INVALID_HANDLE;
1117     CheckStatus(vdp_st, __LINE__);
1118   }
1119
1120   if (m_BlackBar)
1121   {
1122     delete [] m_BlackBar;
1123     m_BlackBar = NULL;
1124   }
1125
1126   while (!m_DVDVideoPics.empty())
1127     m_DVDVideoPics.pop();
1128
1129   return true;
1130 }
1131
1132 void CVDPAU::SpewHardwareAvailable()  //Copyright (c) 2008 Wladimir J. van der Laan  -- VDPInfo
1133 {
1134   VdpStatus rv;
1135   CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
1136   CLog::Log(LOGNOTICE,"name          level macbs width height");
1137   CLog::Log(LOGNOTICE,"------------------------------------");
1138   for(unsigned int x=0; x<decoder_profile_count; ++x)
1139   {
1140     VdpBool is_supported = false;
1141     uint32_t max_level, max_macroblocks, max_width, max_height;
1142     rv = vdp_decoder_query_caps(vdp_device, decoder_profiles[x].id,
1143                                 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
1144     if(rv == VDP_STATUS_OK && is_supported)
1145     {
1146       CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
1147                 max_level, max_macroblocks, max_width, max_height);
1148     }
1149   }
1150   CLog::Log(LOGNOTICE,"------------------------------------");
1151   m_feature_count = 0;
1152 #define CHECK_SUPPORT(feature)  \
1153   do { \
1154     VdpBool supported; \
1155     if(vdp_video_mixer_query_feature_support(vdp_device, feature, &supported) == VDP_STATUS_OK && supported) { \
1156       CLog::Log(LOGNOTICE, "Mixer feature: "#feature);  \
1157       m_features[m_feature_count++] = feature; \
1158     } \
1159   } while(false)
1160
1161   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
1162   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
1163   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
1164   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
1165   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
1166 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
1167   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
1168   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
1169   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
1170   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
1171   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
1172   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
1173   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
1174   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
1175   CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
1176 #endif
1177 #undef CHECK_SUPPORT
1178
1179 }
1180
1181 bool CVDPAU::IsSurfaceValid(vdpau_render_state *render)
1182 {
1183   // find render state in queue
1184   bool found(false);
1185   unsigned int i;
1186   for(i = 0; i < m_videoSurfaces.size(); ++i)
1187   {
1188     if(m_videoSurfaces[i] == render)
1189     {
1190       found = true;
1191       break;
1192     }
1193   }
1194   if (!found)
1195   {
1196     CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__);
1197     return false;
1198   }
1199   if (m_videoSurfaces[i]->surface == VDP_INVALID_HANDLE)
1200   {
1201     m_videoSurfaces[i]->state = 0;
1202     return false;
1203   }
1204
1205   return true;
1206 }
1207
1208 int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
1209 {
1210   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1211   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1212   CVDPAU*               vdp        = (CVDPAU*)ctx->GetHardware();
1213   struct pictureAge*    pA         = &vdp->picAge;
1214
1215   // while we are waiting to recover we can't do anything
1216   CSharedLock lock(vdp->m_DecoderSection);
1217
1218   { CSharedLock dLock(vdp->m_DisplaySection);
1219     if(vdp->m_DisplayState != VDPAU_OPEN)
1220     {
1221       CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
1222       return -1;
1223     }
1224   }
1225
1226   vdpau_render_state * render = NULL;
1227
1228   // find unused surface
1229   for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++)
1230   {
1231     if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER)))
1232     {
1233       render = vdp->m_videoSurfaces[i];
1234       render->state = 0;
1235       break;
1236     }
1237   }
1238
1239   VdpStatus vdp_st = VDP_STATUS_ERROR;
1240   if (render == NULL)
1241   {
1242     // create a new surface
1243     VdpDecoderProfile profile;
1244     ReadFormatOf(avctx->codec_id, profile, vdp->vdp_chroma_type);
1245     render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1);
1246     if (render == NULL)
1247     {
1248       CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed");
1249       return -1;
1250     }
1251     render->surface = VDP_INVALID_HANDLE;
1252     vdp->m_videoSurfaces.push_back(render);
1253   }
1254
1255   if (render->surface == VDP_INVALID_HANDLE)
1256   {
1257     vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device,
1258                                          vdp->vdp_chroma_type,
1259                                          avctx->coded_width,
1260                                          avctx->coded_height,
1261                                          &render->surface);
1262     vdp->CheckStatus(vdp_st, __LINE__);
1263     if (vdp_st != VDP_STATUS_OK)
1264     {
1265       free(render);
1266       CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
1267       return -1;
1268     }
1269   }
1270
1271   pic->data[1] = pic->data[2] = NULL;
1272   pic->data[0] = (uint8_t*)render;
1273   pic->data[3] = (uint8_t*)(uintptr_t)render->surface;
1274
1275   pic->linesize[0] = pic->linesize[1] =  pic->linesize[2] = 0;
1276
1277   if(pic->reference)
1278   {
1279     pA->ip_age[0]= pA->ip_age[1]+1;
1280     pA->ip_age[1]= 1;
1281     pA->b_age++;
1282   }
1283   else
1284   {
1285     pA->ip_age[0]++;
1286     pA->ip_age[1]++;
1287     pA->b_age = 1;
1288   }
1289   pic->type= FF_BUFFER_TYPE_USER;
1290
1291   render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE;
1292   pic->reordered_opaque= avctx->reordered_opaque;
1293   return 0;
1294 }
1295
1296 void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
1297 {
1298   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1299   CDVDVideoCodecFFmpeg* ctx        = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1300   CVDPAU*               vdp        = (CVDPAU*)ctx->GetHardware();
1301   vdpau_render_state  * render;
1302   unsigned int i;
1303
1304   CSharedLock lock(vdp->m_DecoderSection);
1305
1306   render=(vdpau_render_state*)pic->data[0];
1307   if(!render)
1308   {
1309     CLog::Log(LOGERROR, "CVDPAU::FFReleaseBuffer - invalid context handle provided");
1310     return;
1311   }
1312
1313   for(i=0; i<4; i++)
1314     pic->data[i]= NULL;
1315
1316   // find render state in queue
1317   if (!vdp->IsSurfaceValid(render))
1318   {
1319     CLog::Log(LOGDEBUG, "CVDPAU::FFReleaseBuffer - ignoring invalid buffer");
1320     return;
1321   }
1322
1323   render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
1324 }
1325
1326 VdpStatus CVDPAU::Render(VdpDecoder decoder, VdpVideoSurface target,
1327                          VdpPictureInfo const *picture_info,
1328                          uint32_t bitstream_buffer_count,
1329                          VdpBitstreamBuffer const * bitstream_buffers)
1330 {
1331   return VDP_STATUS_OK;
1332 }
1333
1334 void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
1335                                            const AVFrame *src, int offset[4],
1336                                            int y, int type, int height)
1337 {
1338   CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1339   CVDPAU*               vdp = (CVDPAU*)ctx->GetHardware();
1340
1341   // while we are waiting to recover we can't do anything
1342   CSharedLock lock(vdp->m_DecoderSection);
1343
1344   { CSharedLock dLock(vdp->m_DisplaySection);
1345     if(vdp->m_DisplayState != VDPAU_OPEN)
1346       return;
1347   }
1348
1349
1350   if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1351   || offset[0] || offset[1] || offset[2])
1352   {
1353     CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1354     return;
1355   }
1356
1357   VdpStatus vdp_st;
1358   vdpau_render_state * render;
1359
1360   render = (vdpau_render_state*)src->data[0];
1361   if(!render)
1362   {
1363     CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided");
1364     return;
1365   }
1366
1367   // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1368   if (!vdp->IsSurfaceValid(render))
1369   {
1370     CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1371     return;
1372   }
1373
1374   uint32_t max_refs = 0;
1375   if(s->codec_id == AV_CODEC_ID_H264)
1376     max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1377
1378   if(vdp->decoder == VDP_INVALID_HANDLE
1379   || vdp->vdpauConfigured == false
1380   || vdp->max_references < max_refs)
1381   {
1382     if(!vdp->ConfigVDPAU(s, max_refs))
1383       return;
1384   }
1385
1386   vdp_st = vdp->vdp_decoder_render(vdp->decoder,
1387                                    render->surface,
1388                                    (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1389                                    vdp->m_hwContext.bitstream_buffers_used,
1390                                    vdp->m_hwContext.bitstream_buffers);
1391   vdp->CheckStatus(vdp_st, __LINE__);
1392 }
1393
1394 int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1395 {
1396   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1397   VdpStatus vdp_st;
1398   VdpTime time;
1399
1400   int result = Check(avctx);
1401   if (result)
1402     return result;
1403
1404   CSharedLock lock(m_DecoderSection);
1405
1406   if (!vdpauConfigured)
1407     return VC_ERROR;
1408
1409   // configure vdpau output
1410   if (!ConfigOutputMethod(avctx, pFrame))
1411     return VC_FLUSHED;
1412
1413   outputSurface = outputSurfaces[surfaceNum];
1414
1415   CheckFeatures();
1416
1417   if (( (int)outRectVid.x1 != OutWidth ) ||
1418       ( (int)outRectVid.y1 != OutHeight ))
1419   {
1420     outRectVid.x0 = 0;
1421     outRectVid.y0 = 0;
1422     outRectVid.x1 = OutWidth;
1423     outRectVid.y1 = OutHeight;
1424   }
1425
1426   EDEINTERLACEMODE   mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1427   EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1428   if (method == VS_INTERLACEMETHOD_AUTO)
1429     method = AutoInterlaceMethod();
1430
1431   if(pFrame)
1432   { // we have a new frame from decoder
1433
1434     vdpau_render_state * render = (vdpau_render_state*)pFrame->data[2];
1435     if(!render) // old style ffmpeg gave data on plane 0
1436       render = (vdpau_render_state*)pFrame->data[0];
1437     if(!render)
1438       return VC_ERROR;
1439
1440     // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1441     if (!IsSurfaceValid(render))
1442     {
1443       CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1444       return VC_BUFFER;
1445     }
1446
1447     render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
1448
1449     ClearUsedForRender(&past[0]);
1450     past[0] = past[1];
1451     past[1] = current;
1452     current = future;
1453     future = render;
1454
1455     DVDVideoPicture DVDPic;
1456     memset(&DVDPic, 0, sizeof(DVDVideoPicture));
1457     ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic);
1458     m_DVDVideoPics.push(DVDPic);
1459
1460     int pics = m_DVDVideoPics.size();
1461     if (pics < 2)
1462         return VC_BUFFER;
1463     else if (pics > 2)
1464     {
1465       // this should not normally happen
1466       CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue");
1467       while (pics-- != 2)
1468         m_DVDVideoPics.pop();
1469     }
1470
1471     if (mode == VS_DEINTERLACEMODE_FORCE
1472     || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED))
1473     {
1474       if((method == VS_INTERLACEMETHOD_AUTO_ION
1475       ||  method == VS_INTERLACEMETHOD_VDPAU_BOB
1476       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
1477       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
1478       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
1479       ||  method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
1480       ||  method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE ))
1481       {
1482         if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576)
1483         || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
1484         || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
1485         || avctx->skip_frame == AVDISCARD_NONREF)
1486           m_mixerstep = 0;
1487         else
1488           m_mixerstep = 1;
1489
1490         if(m_DVDVideoPics.front().iFlags & DVP_FLAG_TOP_FIELD_FIRST)
1491           m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
1492         else
1493           m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
1494       }
1495       else
1496       {
1497         m_mixerstep  = 0;
1498         m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
1499       }
1500     }
1501     else
1502     {
1503       m_mixerstep  = 0;
1504       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
1505     }
1506
1507   }
1508   else if(m_mixerstep == 1)
1509   { // no new frame given, output second field of old frame
1510
1511     if(avctx->skip_frame == AVDISCARD_NONREF)
1512     {
1513       ClearUsedForRender(&past[1]);
1514       m_DVDVideoPics.pop();
1515       return VC_BUFFER;
1516     }
1517
1518     m_mixerstep = 2;
1519     if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
1520       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
1521     else
1522       m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
1523   }
1524   else
1525   {
1526     CLog::Log(LOGERROR, "CVDPAU::Decode - invalid mixer state reached");
1527     return VC_BUFFER;
1528   }
1529
1530   VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
1531   VdpVideoSurface futu_surfaces[1] = { VDP_INVALID_HANDLE };
1532
1533   if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
1534   {
1535     if (past[0])
1536       past_surfaces[1] = past[0]->surface;
1537     if (past[1])
1538       past_surfaces[0] = past[1]->surface;
1539     futu_surfaces[0] = future->surface;
1540   }
1541   else
1542   {
1543     if(m_mixerstep == 1)
1544     { // first field
1545       if (past[1])
1546       {
1547         past_surfaces[1] = past[1]->surface;
1548         past_surfaces[0] = past[1]->surface;
1549       }
1550       futu_surfaces[0] = current->surface;
1551     }
1552     else
1553     { // second field
1554       if (past[1])
1555         past_surfaces[1] = past[1]->surface;
1556       past_surfaces[0] = current->surface;
1557       futu_surfaces[0] = future->surface;
1558     }
1559   }
1560
1561   vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time);
1562
1563   VdpRect sourceRect = {0,0,vid_width, vid_height};
1564
1565   vdp_st = vdp_video_mixer_render(videoMixer,
1566                                   VDP_INVALID_HANDLE,
1567                                   0, 
1568                                   m_mixerfield,
1569                                   2,
1570                                   past_surfaces,
1571                                   current->surface,
1572                                   1,
1573                                   futu_surfaces,
1574                                   &sourceRect,
1575                                   outputSurface,
1576                                   &(outRectVid),
1577                                   &(outRectVid),
1578                                   0,
1579                                   NULL);
1580   CheckStatus(vdp_st, __LINE__);
1581
1582   surfaceNum++;
1583   if (surfaceNum >= totalAvailableOutputSurfaces) surfaceNum = 0;
1584
1585   if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
1586   {
1587     ClearUsedForRender(&past[0]);
1588     return VC_BUFFER | VC_PICTURE;
1589   }
1590   else
1591   {
1592     // in order to clip top and bottom lines when de-interlacing
1593     // we black those lines as a work around for not working
1594     // background colour using the mixer
1595     // pixel perfect is preferred over overscanning or zooming
1596
1597     VdpRect clipRect = outRectVid;
1598     clipRect.y1 = clipRect.y0 + 2;
1599     uint32_t *data[] = {m_BlackBar};
1600     uint32_t pitches[] = {outRectVid.x1};
1601     vdp_st = vdp_output_surface_put_bits_native(outputSurface,
1602                                         (void**)data,
1603                                         pitches,
1604                                         &clipRect);
1605     CheckStatus(vdp_st, __LINE__);
1606
1607     clipRect = outRectVid;
1608     clipRect.y0 = clipRect.y1 - 2;
1609     vdp_st = vdp_output_surface_put_bits_native(outputSurface,
1610                                         (void**)data,
1611                                         pitches,
1612                                         &clipRect);
1613     CheckStatus(vdp_st, __LINE__);
1614
1615     if(m_mixerstep == 1)
1616       return VC_PICTURE;
1617     else
1618     {
1619       ClearUsedForRender(&past[1]);
1620       return VC_BUFFER | VC_PICTURE;
1621     }
1622   }
1623 }
1624
1625 bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1626 {
1627   CSharedLock lock(m_DecoderSection);
1628
1629   { CSharedLock dLock(m_DisplaySection);
1630     if (m_DisplayState != VDPAU_OPEN)
1631       return false;
1632   }
1633
1634   *picture = m_DVDVideoPics.front();
1635   // if this is the first field of an interlaced frame, we'll need
1636   // this same picture for the second field later
1637   if (m_mixerstep != 1)
1638     m_DVDVideoPics.pop();
1639
1640   picture->format = RENDER_FMT_VDPAU;
1641   picture->iFlags &= DVP_FLAG_DROPPED;
1642   picture->iWidth = OutWidth;
1643   picture->iHeight = OutHeight;
1644   picture->vdpau = this;
1645
1646   if(m_mixerstep)
1647   {
1648     picture->iRepeatPicture = -0.5;
1649     if(m_mixerstep > 1)
1650     {
1651       picture->dts = DVD_NOPTS_VALUE;
1652       picture->pts = DVD_NOPTS_VALUE;
1653     }
1654   }
1655   return true;
1656 }
1657
1658 void CVDPAU::Reset()
1659 {
1660   // invalidate surfaces and picture queue when seeking
1661   ClearUsedForRender(&past[0]);
1662   ClearUsedForRender(&past[1]);
1663   ClearUsedForRender(&current);
1664   ClearUsedForRender(&future);
1665
1666   while (!m_DVDVideoPics.empty())
1667     m_DVDVideoPics.pop();
1668 }
1669
1670 void CVDPAU::Present()
1671 {
1672   //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1673   VdpStatus vdp_st;
1674
1675   CSharedLock lock(m_DecoderSection);
1676
1677   { CSharedLock dLock(m_DisplaySection);
1678     if (m_DisplayState != VDPAU_OPEN)
1679       return;
1680   }
1681
1682   presentSurface = outputSurface;
1683
1684   vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
1685                                           presentSurface,
1686                                           0,
1687                                           0,
1688                                           0);
1689   CheckStatus(vdp_st, __LINE__);
1690 }
1691
1692 bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line)
1693 {
1694   if (vdp_st != VDP_STATUS_OK)
1695   {
1696     CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1697
1698     CExclusiveLock lock(m_DisplaySection);
1699
1700     if(m_DisplayState == VDPAU_OPEN)
1701     {
1702       if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1703       {
1704         m_DisplayEvent.Reset();
1705         m_DisplayState = VDPAU_LOST;
1706       }
1707       else
1708         m_DisplayState = VDPAU_ERROR;
1709     }
1710
1711     return true;
1712   }
1713   return false;
1714 }
1715
1716 #endif