PageRenderTime 294ms CodeModel.GetById 21ms app.highlight 250ms RepoModel.GetById 2ms app.codeStats 1ms

/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp

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