diff --git a/packages/mediacenter/xbmc/patches/xbmc-991.01-VAAPI-Add-class-which-handles-VPP-deinterlacing.patch b/packages/mediacenter/xbmc/patches/xbmc-991.01-VAAPI-Add-class-which-handles-VPP-deinterlacing.patch new file mode 100644 index 0000000000..f84708f85c --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-991.01-VAAPI-Add-class-which-handles-VPP-deinterlacing.patch @@ -0,0 +1,694 @@ +From d9739fe6ee21362f196bf4641e38c39a6f0c1eb7 Mon Sep 17 00:00:00 2001 +From: BtbN +Date: Thu, 3 Oct 2013 14:49:25 +0200 +Subject: [PATCH 1/2] VAAPI: Add class which handles VPP deinterlacing + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 1 + + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.cpp | 540 +++++++++++++++++++++ + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.h | 114 +++++ + 3 files changed, 655 insertions(+) + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.cpp + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.h + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +index 23261f1..cfa05ec 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -9,6 +9,7 @@ SRCS += VDPAU.cpp + endif + ifeq (@USE_VAAPI@,1) + SRCS += VAAPI.cpp ++SRCS += VAAPI_VPP.cpp + endif + ifeq (@USE_CRYSTALHD@,1) + SRCS += CrystalHD.cpp +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.cpp +new file mode 100644 +index 0000000..78e786a +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.cpp +@@ -0,0 +1,540 @@ ++/* ++ * Copyright (C) 2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "system.h" ++#ifdef HAVE_LIBVA ++ ++#include "VAAPI_VPP.h" ++#if VA_CHECK_VERSION(0,34,0) ++# define VPP_AVAIL 1 ++#endif ++ ++#ifdef VPP_AVAIL ++#include ++#endif ++ ++#include "utils/log.h" ++#include "threads/SingleLock.h" ++ ++#include ++#include ++ ++#ifndef VA_SURFACE_ATTRIB_SETTABLE ++#define vaCreateSurfaces(d, f, w, h, s, ns, a, na) \ ++ vaCreateSurfaces(d, w, h, f, ns, s) ++#endif ++ ++using namespace VAAPI; ++ ++ ++CVPP::SupportState CVPP::g_supported = CVPP::Unknown; ++CVPP::SupportState CVPP::g_deintSupported[VAAPI::Deinterlacing_Count] = {CVPP::Unknown}; ++ ++CVPP::CVPP() ++ :m_width(0) ++ ,m_height(0) ++ ,m_configId(VA_INVALID_ID) ++ ,m_vppReady(CVPP::InitFailed) ++ ,m_deintReady(CVPP::InitFailed) ++ ,m_deintContext(VA_INVALID_ID) ++ ,m_deintFilter(VA_INVALID_ID) ++{} ++ ++CVPP::CVPP(CDisplayPtr& display, int width, int height) ++ :m_usedMethod(VAAPI::DeinterlacingNone) ++ ,m_display(display) ++ ,m_width(width) ++ ,m_height(height) ++ ,m_configId(VA_INVALID_ID) ++ ,m_vppReady(CVPP::NotReady) ++ ,m_deintReady(CVPP::NotReady) ++ ,m_deintContext(VA_INVALID_ID) ++ ,m_deintFilter(VA_INVALID_ID) ++{ ++ assert(display.get() && display->get()); ++ assert(width > 0 && height > 0); ++ ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Probing available methods"); ++ for(int i = 1; i < VAAPI::Deinterlacing_Count; ++i) ++ { ++ if(VppSupported() && g_deintSupported[i] == Unknown && InitVpp()) ++ { ++ if(InitDeint((DeintMethod)i, 1)) ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Method %d is supported!", i); ++ else ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Method %d is NOT supported!", i); ++ Deinit(); ++ } ++ } ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Done probing available methods"); ++} ++ ++CVPP::~CVPP() ++{ ++ Deinit(); ++} ++ ++bool CVPP::VppSupported() ++{ ++#ifdef VPP_AVAIL ++ return g_supported != Unsupported; ++#else ++ return false; ++#endif ++} ++ ++bool CVPP::DeintSupported(DeintMethod method) ++{ ++#ifdef VPP_AVAIL ++ if(method == DeinterlacingNone) ++ return false; ++ ++ return VppSupported() && g_deintSupported[method] != Unsupported; ++#else ++ return false; ++#endif ++} ++ ++void CVPP::Deinit() ++{ ++#ifdef VPP_AVAIL ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Deinitializing"); ++ ++ DeinitDeint(); ++ DeinitVpp(); ++#endif ++} ++ ++void CVPP::DeinitVpp() ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ if(VppReady()) ++ { ++ vaDestroyConfig(m_display->get(), m_configId); ++ m_vppReady = NotReady; ++ ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Deinitialized vpp"); ++ } ++#endif ++} ++ ++void CVPP::DeinitDeint() ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ if(DeintReady() || m_deintReady == RuntimeFailed) ++ { ++ vaDestroyBuffer(m_display->get(), m_deintFilter); ++ vaDestroyContext(m_display->get(), m_deintContext); ++ m_deintTargets.clear(); ++ m_deintReady = NotReady; ++ m_usedMethod = DeinterlacingNone; ++ ++ m_forwardReferences.clear(); ++ m_backwardReferences.clear(); ++ ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Deinitialized deint"); ++ } ++#endif ++} ++ ++bool CVPP::InitVpp() ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ if(VppFailed() || VppReady()) ++ return false; ++ ++ int numEntrypoints = vaMaxNumEntrypoints(m_display->get()); ++ boost::scoped_array entrypoints(new VAEntrypoint[numEntrypoints]); ++ ++ if(vaQueryConfigEntrypoints(m_display->get(), VAProfileNone, entrypoints.get(), &numEntrypoints) != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed querying entrypoints"); ++ ++ m_vppReady = InitFailed; ++ return false; ++ } ++ ++ int i; ++ for(i = 0; i < numEntrypoints; ++i) ++ if(entrypoints[i] == VAEntrypointVideoProc) ++ break; ++ ++ if(i >= numEntrypoints) ++ { ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Entrypoint VideoProc not supported"); ++ m_vppReady = InitFailed; ++ g_supported = Unsupported; ++ return false; ++ } ++ ++ if(vaCreateConfig(m_display->get(), VAProfileNone, VAEntrypointVideoProc, NULL, 0, &m_configId) != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed creating va config"); ++ m_vppReady = InitFailed; ++ return false; ++ } ++ ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Successfully initialized VPP"); ++ ++ m_vppReady = Ready; ++ g_supported = Supported; ++ return true; ++#else ++ g_supported = Unsupported; ++ m_vppReady = InitFailed; ++ return false; ++#endif ++} ++ ++bool CVPP::InitDeint(DeintMethod method, int num_surfaces) ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ assert(VppReady()); ++ ++ if(DeintReady()) ++ return false; ++ ++ VAProcDeinterlacingType selectedMethod = VAProcDeinterlacingNone; ++ switch(method) ++ { ++ case DeinterlacingBob: ++ selectedMethod = VAProcDeinterlacingBob; ++ break; ++ case DeinterlacingWeave: ++ selectedMethod = VAProcDeinterlacingWeave; ++ break; ++ case DeinterlacingMotionAdaptive: ++ selectedMethod = VAProcDeinterlacingMotionAdaptive; ++ break; ++ case DeinterlacingMotionCompensated: ++ selectedMethod = VAProcDeinterlacingMotionCompensated; ++ break; ++ default: ++ selectedMethod = VAProcDeinterlacingNone; ++ break; ++ } ++ ++ if(selectedMethod == VAProcDeinterlacingNone) ++ { ++ CLog::Log(LOGERROR, "VAAPI_VPP - invalid deinterlacing method requested!"); ++ m_deintReady = InitFailed; ++ return false; ++ } ++ ++ boost::scoped_array deintTargetsInternal(new VASurfaceID[num_surfaces]); ++ if(vaCreateSurfaces(m_display->get(), VA_RT_FORMAT_YUV420, m_width, m_height, deintTargetsInternal.get(), num_surfaces, NULL, 0) != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed creating deint target surfaces"); ++ m_deintReady = InitFailed; ++ return false; ++ } ++ ++ if(vaCreateContext(m_display->get(), m_configId, m_width, m_height, VA_PROGRESSIVE, deintTargetsInternal.get(), num_surfaces, &m_deintContext) != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed creating deint context"); ++ vaDestroySurfaces(m_display->get(), deintTargetsInternal.get(), num_surfaces); ++ m_deintReady = InitFailed; ++ return false; ++ } ++ ++ VAProcFilterType filters[VAProcFilterCount]; ++ unsigned int numFilters = VAProcFilterCount; ++ VAProcFilterCapDeinterlacing deinterlacingCaps[VAProcDeinterlacingCount]; ++ unsigned int numDeinterlacingCaps = VAProcDeinterlacingCount; ++ ++ if( ++ vaQueryVideoProcFilters(m_display->get(), m_deintContext, filters, &numFilters) != VA_STATUS_SUCCESS ++ || vaQueryVideoProcFilterCaps(m_display->get(), m_deintContext, VAProcFilterDeinterlacing, deinterlacingCaps, &numDeinterlacingCaps) != VA_STATUS_SUCCESS) ++ { ++ vaDestroyContext(m_display->get(), m_deintContext); ++ vaDestroySurfaces(m_display->get(), deintTargetsInternal.get(), num_surfaces); ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed querying filter caps"); ++ m_deintReady = InitFailed; ++ g_deintSupported[method] = Unsupported; ++ return false; ++ } ++ ++ bool methodSupported = false; ++ for(unsigned int fi = 0; fi < numFilters; ++fi) ++ if(filters[fi] == VAProcFilterDeinterlacing) ++ for(unsigned int ci = 0; ci < numDeinterlacingCaps; ++ci) ++ { ++ if(deinterlacingCaps[ci].type != selectedMethod) ++ continue; ++ methodSupported = true; ++ break; ++ } ++ ++ if(!methodSupported) ++ { ++ vaDestroyContext(m_display->get(), m_deintContext); ++ vaDestroySurfaces(m_display->get(), deintTargetsInternal.get(), num_surfaces); ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - deinterlacing filter is not supported"); ++ m_deintReady = InitFailed; ++ g_deintSupported[method] = Unsupported; ++ return false; ++ } ++ ++ VAProcFilterParameterBufferDeinterlacing deint; ++ deint.type = VAProcFilterDeinterlacing; ++ deint.algorithm = selectedMethod; ++ deint.flags = 0; ++ ++ if(vaCreateBuffer(m_display->get(), m_deintContext, VAProcFilterParameterBufferType, sizeof(deint), 1, &deint, &m_deintFilter) != VA_STATUS_SUCCESS) ++ { ++ vaDestroyContext(m_display->get(), m_deintContext); ++ vaDestroySurfaces(m_display->get(), deintTargetsInternal.get(), num_surfaces); ++ CLog::Log(LOGERROR, "VAAPI_VPP - creating ProcFilterParameterBuffer failed"); ++ m_deintReady = InitFailed; ++ return false; ++ } ++ ++ VAProcPipelineCaps pplCaps; ++ if(vaQueryVideoProcPipelineCaps(m_display->get(), m_deintContext, &m_deintFilter, 1, &pplCaps) != VA_STATUS_SUCCESS) ++ { ++ vaDestroyBuffer(m_display->get(), m_deintFilter); ++ vaDestroyContext(m_display->get(), m_deintContext); ++ vaDestroySurfaces(m_display->get(), deintTargetsInternal.get(), num_surfaces); ++ CLog::Log(LOGERROR, "VAAPI_VPP - querying ProcPipelineCaps failed"); ++ m_deintReady = InitFailed; ++ return false; ++ } ++ ++ m_forwardReferencesCount = pplCaps.num_forward_references; ++ m_backwardReferencesCount = pplCaps.num_backward_references; ++ ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - Successfully initialized deinterlacer %d. Need %d forward and %d backward refs.", (int)method, m_forwardReferencesCount, m_backwardReferencesCount); ++ ++ m_deintTargets.resize(num_surfaces); ++ for(int i = 0; i < num_surfaces; ++i) ++ m_deintTargets[i] = CSurfacePtr(new CSurface(deintTargetsInternal[i], m_display)); ++ ++ m_deintReady = Ready; ++ m_usedMethod = method; ++ g_deintSupported[method] = Supported; ++ m_forwardReferences.clear(); ++ return true; ++#else ++ m_deintReady = InitFailed; ++ return false; ++#endif ++} ++ ++#define CHECK_VA(s, b) \ ++{\ ++ VAStatus res = s;\ ++ if(res != VA_STATUS_SUCCESS)\ ++ {\ ++ CLog::Log(LOGERROR, "VAAPI_VPP - failed executing "#s" at line %d with error 0x%x:%s", __LINE__, res, vaErrorStr(res));\ ++ VABufferID buf = b;\ ++ if(buf != 0)\ ++ vaDestroyBuffer(m_display->get(), buf);\ ++ if(forwRefs != 0)\ ++ delete[] forwRefs;\ ++ m_forwardReferences.clear();\ ++ return CVPPPicture();\ ++ }\ ++} ++ ++CVPPPicture CVPP::DoDeint(const CVPPPicture& input, bool topFieldFirst, bool firstCall) ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ assert(input.valid); ++ ++ if(!DeintReady()) ++ return CVPPPicture(); ++ ++ VAStatus syncStatus = vaSyncSurface(m_display->get(), input.surface->m_id); ++ if(syncStatus != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - failed syncing surface with error 0x%x:%s", syncStatus, vaErrorStr(syncStatus)); ++ ++ if(syncStatus != VA_STATUS_ERROR_DECODING_ERROR) ++ return CVPPPicture(); ++ ++ VASurfaceDecodeMBErrors *errors; ++ if(vaQuerySurfaceError(m_display->get(), input.surface->m_id, syncStatus, (void**)&errors) != VA_STATUS_SUCCESS) ++ return CVPPPicture(); ++ ++ while(errors != 0 && errors->status == 1) ++ { ++ CLog::Log(LOGDEBUG, "VAAPI_VPP - detected decode error: start_mb: %d, end_mb: %d, error_type: %d", errors->start_mb, errors->end_mb, (int)errors->decode_error_type); ++ ++errors; ++ } ++ ++ return CVPPPicture(); ++ } ++ ++ CVPPPicture procPic = input; ++ ++ if(firstCall && m_forwardReferences.size() < m_forwardReferencesCount) ++ return CVPPPicture(); ++ ++ CSurfacePtr deintTarget = getFreeSurface(); ++ if(!deintTarget.get()) ++ return CVPPPicture(); ++ ++ VAProcFilterParameterBufferDeinterlacing *deint; ++ VABufferID pipelineBuf; ++ VAProcPipelineParameterBuffer *pipelineParam; ++ VARectangle inputRegion; ++ VARectangle outputRegion; ++ ++ VASurfaceID *forwRefs = 0; ++ ++ CHECK_VA(vaBeginPicture(m_display->get(), m_deintContext, deintTarget->m_id), 0); ++ ++ CHECK_VA(vaMapBuffer(m_display->get(), m_deintFilter, (void**)&deint), 0); ++ ++ if(firstCall || m_forwardReferences.size() < m_forwardReferencesCount) ++ { ++ if(!topFieldFirst) ++ deint->flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD; ++ else ++ deint->flags = 0; ++ } ++ else ++ { ++ if(topFieldFirst) ++ deint->flags = VA_DEINTERLACING_BOTTOM_FIELD; ++ else ++ deint->flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST; ++ } ++ ++ CHECK_VA(vaUnmapBuffer(m_display->get(), m_deintFilter), 0); ++ ++ CHECK_VA(vaCreateBuffer(m_display->get(), m_deintContext, VAProcPipelineParameterBufferType, sizeof(VAProcPipelineParameterBuffer), 1, NULL, &pipelineBuf), 0); ++ CHECK_VA(vaMapBuffer(m_display->get(), pipelineBuf, (void**)&pipelineParam), pipelineBuf); ++ ++ memset(pipelineParam, 0, sizeof(VAProcPipelineParameterBuffer)); ++ ++ // This input/output regions crop two the top and bottom pixel rows ++ // It removes the flickering pixels caused by bob ++ const int vcrop = 1; ++ const int hcrop = 0; ++ inputRegion.x = outputRegion.x = hcrop; ++ inputRegion.y = outputRegion.y = vcrop; ++ inputRegion.width = outputRegion.width = m_width - (2 * hcrop); ++ inputRegion.height = outputRegion.height = m_height - (2 * vcrop); ++ ++ pipelineParam->surface = procPic.surface->m_id; ++ pipelineParam->output_region = &outputRegion; ++ pipelineParam->surface_region = &inputRegion; ++ pipelineParam->output_background_color = 0xff000000; ++ ++ pipelineParam->filter_flags = 0; ++ ++ pipelineParam->filters = &m_deintFilter; ++ pipelineParam->num_filters = 1; ++ ++ if(m_forwardReferencesCount > 0) ++ { ++ forwRefs = new VASurfaceID[m_forwardReferencesCount]; ++ ++ unsigned int i; ++ ++ if(m_forwardReferences.size() < m_forwardReferencesCount) ++ { ++ for(i = 0; i < m_forwardReferencesCount; ++i) ++ forwRefs[i] = VA_INVALID_SURFACE; ++ } ++ else ++ { ++ i = 0; ++ for(std::list::iterator it = m_forwardReferences.begin(); it != m_forwardReferences.end(); ++it, ++i) ++ forwRefs[i] = it->surface->m_id; ++ } ++ } ++ ++ pipelineParam->num_forward_references = m_forwardReferences.size(); ++ pipelineParam->forward_references = forwRefs; ++ pipelineParam->num_backward_references = 0; ++ pipelineParam->backward_references = NULL; ++ ++ CHECK_VA(vaUnmapBuffer(m_display->get(), pipelineBuf), pipelineBuf); ++ ++ CHECK_VA(vaRenderPicture(m_display->get(), m_deintContext, &pipelineBuf, 1), pipelineBuf); ++ CHECK_VA(vaEndPicture(m_display->get(), m_deintContext), pipelineBuf); ++ ++ CHECK_VA(vaDestroyBuffer(m_display->get(), pipelineBuf), 0); ++ ++ CHECK_VA(vaSyncSurface(m_display->get(), deintTarget->m_id), 0); ++ ++ if(!firstCall && m_forwardReferencesCount > 0) ++ { ++ if(m_forwardReferences.size() >= m_forwardReferencesCount) ++ m_forwardReferences.pop_front(); ++ ++ if(m_forwardReferences.size() < m_forwardReferencesCount) ++ m_forwardReferences.push_back(input); ++ } ++ ++ if(forwRefs) ++ delete[] forwRefs; ++ ++ CVPPPicture res; ++ res.valid = true; ++ res.DVDPic = procPic.DVDPic; ++ res.surface = deintTarget; ++ ++ return res; ++#else ++ return CVPPPicture(); ++#endif ++} ++ ++void CVPP::Flush() ++{ ++#ifdef VPP_AVAIL ++ CSingleLock lock(m_deint_lock); ++ ++ m_forwardReferences.clear(); ++ m_backwardReferences.clear(); ++#endif ++} ++ ++CSurfacePtr CVPP::getFreeSurface() ++{ ++#ifdef VPP_AVAIL ++ for(int i = 0; i < m_deintTargets.size(); ++i) ++ { ++ if(m_deintTargets[i].unique()) ++ { ++ return m_deintTargets[i]; ++ } ++ } ++ ++ CLog::Log(LOGWARNING, "VAAPI_VPP - Running out of surfaces"); ++#endif ++ ++ return CSurfacePtr(); ++} ++ ++#endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.h +new file mode 100644 +index 0000000..093e270 +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI_VPP.h +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#include "VAAPI.h" ++#include "threads/CriticalSection.h" ++ ++#include ++#include ++#include ++ ++namespace VAAPI ++{ ++ struct CVPPPicture ++ { ++ CVPPPicture():valid(false) {} ++ ++ bool valid; ++ DVDVideoPicture DVDPic; ++ CSurfacePtr surface; ++ }; ++ ++ class CVPP ++ { ++ CVPP(); ++ ++ public: ++ enum ReadyState ++ { ++ NotReady = 0, ++ Ready, ++ InitFailed, ++ RuntimeFailed ++ }; ++ enum SupportState ++ { ++ Unknown = 0, ++ Supported, ++ Unsupported ++ }; ++ ++ CVPP(CDisplayPtr& display, int width, int height); ++ ~CVPP(); ++ ++ static bool VppSupported(); ++ static bool DeintSupported(DeintMethod method); ++ ++ void Deinit(); ++ void DeinitVpp(); ++ void DeinitDeint(); ++ ++ bool InitVpp(); ++ bool InitDeint(DeintMethod method, int num_surfaces); ++ ++ inline bool VppReady() { return m_vppReady == Ready; } ++ inline bool VppFailed() { return m_vppReady == InitFailed || m_vppReady == RuntimeFailed; } ++ inline bool DeintReady() { return m_deintReady == Ready; } ++ inline bool DeintFailed() { return m_deintReady == InitFailed || m_deintReady == RuntimeFailed; } ++ inline DeintMethod getUsedMethod() { return m_usedMethod; } ++ ++ CVPPPicture DoDeint(const CVPPPicture& input, bool topFieldFirst, bool firstCall); ++ ++ void Flush(); ++ ++ private: ++ CSurfacePtr getFreeSurface(); ++ ++ ++ static SupportState g_supported; ++ static SupportState g_deintSupported[VAAPI::Deinterlacing_Count]; ++ ++ ++ DeintMethod m_usedMethod; ++ unsigned int m_forwardReferencesCount; ++ unsigned int m_backwardReferencesCount; ++ std::list m_forwardReferences; ++ std::list m_backwardReferences; ++ ++ CDisplayPtr m_display; ++ int m_width; ++ int m_height; ++ ++ VAConfigID m_configId; ++ ++ ReadyState m_vppReady; ++ ReadyState m_deintReady; ++ ++ //VPP Deinterlacing ++ CCriticalSection m_deint_lock; ++ VAContextID m_deintContext; ++ std::vector m_deintTargets; ++ VABufferID m_deintFilter; ++ }; ++ ++} ++ +-- +1.8.3.2 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-991.02-VAAPI-Integrate-VPP-into-existing-vaapi-code.patch b/packages/mediacenter/xbmc/patches/xbmc-991.02-VAAPI-Integrate-VPP-into-existing-vaapi-code.patch new file mode 100644 index 0000000000..b1f722c80d --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-991.02-VAAPI-Integrate-VPP-into-existing-vaapi-code.patch @@ -0,0 +1,850 @@ +From 7e27055debe5e9851e6a9b8707253a4b5c926a28 Mon Sep 17 00:00:00 2001 +From: BtbN +Date: Thu, 3 Oct 2013 14:49:38 +0200 +Subject: [PATCH 2/2] VAAPI: Integrate VPP into existing vaapi code + +--- + language/English/strings.po | 27 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 28 ++ + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 399 ++++++++++++++++++++++--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 85 +++++- + xbmc/settings/AdvancedSettings.cpp | 2 + + xbmc/settings/AdvancedSettings.h | 1 + + xbmc/settings/VideoSettings.h | 6 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 5 + + 8 files changed, 513 insertions(+), 40 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 15cee63..4495364 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -7129,7 +7129,32 @@ msgctxt "#16325" + msgid "VDPAU - Bob" + msgstr "" + +-#empty strings from id 16326 to 16399 ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16326" ++msgid "VAAPI Auto" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16327" ++msgid "VAAPI Weave" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16328" ++msgid "VAAPI Bob" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16329" ++msgid "VAAPI Motion Adaptive" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16330" ++msgid "VAAPI Motion Compensated" ++msgstr "" ++ ++#empty strings from id 16331 to 16399 + + #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp + msgctxt "#16400" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 600ffa7..375af79 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -3480,6 +3480,26 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + if(m_renderMethod & RENDER_VAAPI) + { + #ifdef HAVE_LIBVA ++ if(method == VS_INTERLACEMETHOD_VAAPI_AUTO) ++ return VAAPI::VppSupported(); ++ ++ if(method == VS_INTERLACEMETHOD_VAAPI_BOB) ++ return VAAPI::DeintSupported(VAAPI::DeinterlacingBob); ++ ++ // MADI and MACI still produce problems ++ // disable them completely by now ++ if(g_advancedSettings.m_useVAAPIAdvancedDeinterlacing) ++ { ++ if(method == VS_INTERLACEMETHOD_VAAPI_WEAVE) ++ return VAAPI::DeintSupported(VAAPI::DeinterlacingWeave); ++ ++ if(method == VS_INTERLACEMETHOD_VAAPI_MOTION_ADAPTIVE) ++ return VAAPI::DeintSupported(VAAPI::DeinterlacingMotionAdaptive); ++ ++ if(method == VS_INTERLACEMETHOD_VAAPI_MOTION_COMPENSATED) ++ return VAAPI::DeintSupported(VAAPI::DeinterlacingMotionCompensated); ++ } ++ + VAAPI::CDisplayPtr disp = m_buffers[m_iYV12RenderBuffer].vaapi.display; + if(disp) + { +@@ -3567,6 +3587,14 @@ EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod() + if(m_renderMethod & RENDER_VDPAU) + return VS_INTERLACEMETHOD_NONE; + ++ if(m_renderMethod & RENDER_VAAPI) ++ { ++#ifdef HAVE_LIBVA ++ if(VAAPI::VppSupported()) ++ return VS_INTERLACEMETHOD_VAAPI_AUTO; ++#endif ++ } ++ + if(Supports(VS_INTERLACEMETHOD_RENDER_BOB)) + return VS_INTERLACEMETHOD_RENDER_BOB; + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 3facfce..e7304e0 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -20,8 +20,11 @@ + #include "system.h" + #ifdef HAVE_LIBVA + #include "windowing/WindowingFactory.h" ++#include "settings/MediaSettings.h" + #include "settings/Settings.h" ++#include "cores/dvdplayer/DVDClock.h" + #include "VAAPI.h" ++#include "VAAPI_VPP.h" + #include "DVDVideoCodec.h" + #include + #include +@@ -66,7 +69,7 @@ static int compare_version(int major_l, int minor_l, int micro_l, int major_r, i + static void RelBufferS(AVCodecContext *avctx, AVFrame *pic) + { ((CDecoder*)((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetHardware())->RelBuffer(avctx, pic); } + +-static int GetBufferS(AVCodecContext *avctx, AVFrame *pic) ++static int GetBufferS(AVCodecContext *avctx, AVFrame *pic) + { return ((CDecoder*)((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetHardware())->GetBuffer(avctx, pic); } + + static inline VASurfaceID GetSurfaceID(AVFrame *pic) +@@ -83,7 +86,7 @@ static CDisplayPtr GetGlobalDisplay() + { + CLog::Log(LOGERROR, "VAAPI - vaapi display is in lost state"); + display.reset(); +- } ++ } + return display; + } + +@@ -151,6 +154,9 @@ CSurfaceGL::~CSurfaceGL() + + CDecoder::CDecoder() + { ++ // Buffer size passed to VPP Init ++ m_buffer_size = 9; ++ + m_refs = 0; + m_surfaces_count = 0; + m_config = 0; +@@ -170,7 +176,7 @@ void CDecoder::RelBuffer(AVCodecContext *avctx, AVFrame *pic) + VASurfaceID surface = GetSurfaceID(pic); + + for(std::list::iterator it = m_surfaces_used.begin(); it != m_surfaces_used.end(); ++it) +- { ++ { + if((*it)->m_id == surface) + { + m_surfaces_free.push_back(*it); +@@ -205,19 +211,19 @@ int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic) + if(!wrapper) + { + CLog::Log(LOGERROR, "VAAPI - unable to find requested surface"); +- return -1; ++ return -1; + } + } + else + { + // To avoid stutter, we scan the free surface pool (provided by decoder) for surfaces +- // that are 100% not in use by renderer. The pointers to these surfaces have a use_count of 1. +- for (; it != m_surfaces_free.end() && it->use_count() > 1; ++it) {} ++ // that are 100% not in use by renderer or vpp. The pointers to these surfaces are unique(use_count() == 1). ++ for (; it != m_surfaces_free.end() && !it->unique(); ++it) {} + + // If we have zero free surface from decoder OR all free surfaces are in use by renderer, we allocate a new surface + if (it == m_surfaces_free.end()) + { +- if (!m_surfaces_free.empty()) CLog::Log(LOGERROR, "VAAPI - renderer still using all freed up surfaces by decoder"); ++ if (!m_surfaces_free.empty()) CLog::Log(LOGERROR, "VAAPI - renderer/vpp still using all freed up surfaces by decoder"); + CLog::Log(LOGERROR, "VAAPI - unable to find free surface, trying to allocate a new one"); + if(!EnsureSurfaces(avctx, m_surfaces_count+1) || m_surfaces_free.empty()) + { +@@ -238,7 +244,7 @@ int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic) + pic->data[0] = (uint8_t*)wrapper; + pic->data[1] = NULL; + pic->data[2] = NULL; +- pic->data[3] = (uint8_t*)surface; ++ pic->data[3] = (uint8_t*)(uintptr_t)surface; + pic->linesize[0] = 0; + pic->linesize[1] = 0; + pic->linesize[2] = 0; +@@ -248,7 +254,9 @@ int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic) + } + + void CDecoder::Close() +-{ ++{ ++ m_vppth.reset(); ++ + if(m_context) + WARN(vaDestroyContext(m_display->get(), m_context)) + m_context = 0; +@@ -256,7 +264,7 @@ void CDecoder::Close() + if(m_config) + WARN(vaDestroyConfig(m_display->get(), m_config)) + m_config = 0; +- ++ + m_surfaces_free.clear(); + m_surfaces_used.clear(); + m_surfaces_count = 0; +@@ -291,7 +299,7 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su + else + { + if(avctx->profile == FF_PROFILE_H264_MAIN) +- accepted.push_back(VAProfileH264Main); ++ accepted.push_back(VAProfileH264Main); + #else + { + // fallback to high profile if libavcodec is too old to export +@@ -371,10 +379,15 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su + CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id)) + m_config = m_hwaccel->config_id; + ++ m_vppth = CVPPThreadPtr(new CVPPThread(m_display, avctx->width, avctx->height)); ++ + m_renderbuffers_count = surfaces; + if (!EnsureContext(avctx)) + return false; + ++ m_vppth->Init(m_buffer_size); // Ignore result, VPPThread just passes frames if init failed ++ m_vppth->Start(); ++ + m_hwaccel->display = m_display->get(); + + avctx->hwaccel_context = m_hwaccel; +@@ -403,7 +416,12 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx) + else + m_refs = 2; + } +- return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1); ++ ++ int vpp_buf = 0; ++ if(m_vppth && m_vppth->getVPP() && m_vppth->getVPP()->VppSupported()) ++ vpp_buf = m_buffer_size / 2 + 4; ++ ++ return EnsureSurfaces(avctx, m_refs + vpp_buf + m_renderbuffers_count + 1); + } + + bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) +@@ -459,48 +477,75 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) + return status; + + if(frame) +- return VC_BUFFER | VC_PICTURE; +- else +- return VC_BUFFER; +-} +- +-bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) +-{ +- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(picture); +- VASurfaceID surface = GetSurfaceID(frame); +- ++ { ++ CVPPPicture picture; ++ VASurfaceID surface = GetSurfaceID(frame); + +- m_holder.surface.reset(); ++ std::list::iterator it; ++ for(it = m_surfaces_used.begin(); it != m_surfaces_used.end() && !picture.surface; ++it) ++ if((*it)->m_id == surface) ++ picture.surface = *it; ++ for(it = m_surfaces_free.begin(); it != m_surfaces_free.end() && !picture.surface; ++it) ++ if((*it)->m_id == surface) ++ picture.surface = *it; ++ if(!picture.surface) ++ { ++ CLog::Log(LOGERROR, "VAAPI - Unable to find surface"); ++ return VC_ERROR; ++ } + +- std::list::iterator it; +- for(it = m_surfaces_used.begin(); it != m_surfaces_used.end() && !m_holder.surface; ++it) +- { +- if((*it)->m_id == surface) ++ VASurfaceStatus surf_status; ++ if(vaQuerySurfaceStatus(m_display->get(), surface, &surf_status) != VA_STATUS_SUCCESS) + { +- m_holder.surface = *it; +- break; ++ CLog::Log(LOGERROR, "VAAPI - Unable to query surface status"); ++ return VC_ERROR; + } +- } + +- for(it = m_surfaces_free.begin(); it != m_surfaces_free.end() && !m_holder.surface; ++it) +- { +- if((*it)->m_id == surface) ++ if((((int)surf_status) & 16) == 0) + { +- m_holder.surface = *it; +- break; ++ picture.valid = true; ++ memset(&picture.DVDPic, 0, sizeof(picture.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&picture.DVDPic); ++ ++ m_vppth->InsertNewFrame(picture); + } + } +- if(!m_holder.surface) ++ ++ int ret = 0; ++ ++ if(m_vppth->GetInputQueueSize() < (m_buffer_size >> 2) && m_vppth->GetOutputQueueSize() < (m_buffer_size >> 1)) ++ ret |= VC_BUFFER; ++ if(m_vppth->GetOutputQueueSize() > 0) ++ ret |= VC_PICTURE; ++ ++ return ret; ++} ++ ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ m_holder.surface.reset(); ++ ++ CVPPPicture outPic = m_vppth->GetOutputPicture(); ++ if(!outPic.valid) + { +- CLog::Log(LOGERROR, "VAAPI - Unable to find surface"); ++ CLog::Log(LOGERROR, "VAAPI - Got an invalid render picture"); + return false; + } + ++ m_holder.surface = outPic.surface; ++ *picture = outPic.DVDPic; ++ + picture->format = RENDER_FMT_VAAPI; + picture->vaapi = &m_holder; ++ + return true; + } + ++void CDecoder::Reset() ++{ ++ m_vppth->Flush(); ++} ++ + int CDecoder::Check(AVCodecContext* avctx) + { + if (m_display == NULL) +@@ -537,4 +582,284 @@ unsigned CDecoder::GetAllowedReferences() + return m_renderbuffers_count; + } + ++ ++CVPPThread::CVPPThread(CDisplayPtr& display, int width, int height) ++ :CThread("VAAPI VPP Thread") ++ ,m_stop(false) ++ ,m_can_skip_deint(false) ++ ,m_num_refs(-1) ++ ,m_last_method(-1) ++{ ++ m_vpp = CVPPPtr(new CVPP(display, width, height)); ++} ++ ++CVPPThread::~CVPPThread() ++{ ++ Dispose(); ++} ++ ++bool CVPPThread::Init(int num_refs) ++{ ++ m_num_refs = num_refs; ++ return m_vpp->InitVpp(); ++} ++ ++void CVPPThread::Start() ++{ ++ m_stop = false; ++ m_last_method = -1; ++ Create(); ++} ++ ++void CVPPThread::Dispose() ++{ ++ m_stop = true; ++ m_input_cond.notifyAll(); ++ StopThread(); ++ ++ m_input_queue = std::queue(); ++ m_output_queue = std::queue(); ++ ++ m_vpp->Deinit(); ++ m_vpp.reset(); ++} ++ ++void CVPPThread::OnStartup() ++{ ++ CLog::Log(LOGDEBUG, "VAAPI - VPP thread on startup"); ++} ++ ++void CVPPThread::OnExit() ++{ ++ CLog::Log(LOGDEBUG, "VAAPI - VPP thread on exit"); ++} ++ ++void CVPPThread::InsertNewFrame(CVPPPicture &new_frame) ++{ ++ if(!IsRunning()) ++ return; ++ ++ CSingleLock lock(m_input_queue_lock); ++ ++ m_input_queue.push(new_frame); ++ m_input_cond.notify(); ++} ++ ++CVPPPicture CVPPThread::GetOutputPicture() ++{ ++ CVPPPicture res = CVPPPicture(); ++ ++ if(!IsRunning()) ++ return res; ++ ++ CSingleLock lock(m_output_queue_lock); ++ ++ if(!m_output_queue.empty()) ++ { ++ res = m_output_queue.front(); ++ m_output_queue.pop(); ++ } ++ ++ return res; ++} ++ ++CVPPPicture CVPPThread::GetCurrentFrame() ++{ ++ CVPPPicture res = CVPPPicture(); ++ ++ if(m_stop) ++ return res; ++ ++ CSingleLock lock(m_input_queue_lock); ++ ++ if(m_input_queue.empty()) ++ m_input_cond.wait(m_input_queue_lock); ++ ++ if(!m_input_queue.empty()) ++ { ++ res = m_input_queue.front(); ++ m_input_queue.pop(); ++ } ++ ++ return res; ++} ++ ++void CVPPThread::InsertOutputFrame(CVPPPicture &new_frame) ++{ ++ CSingleLock lock(m_output_queue_lock); ++ ++ m_output_queue.push(new_frame); ++} ++ ++int CVPPThread::GetInputQueueSize() ++{ ++ CSingleLock lock(m_input_queue_lock); ++ ++ return m_input_queue.size(); ++} ++ ++int CVPPThread::GetOutputQueueSize() ++{ ++ CSingleLock lock(m_output_queue_lock); ++ ++ return m_output_queue.size(); ++} ++ ++void CVPPThread::Flush() ++{ ++ CSingleLock lock(m_work_lock); ++ ++ m_input_queue_lock.lock(); ++ m_input_queue = std::queue(); ++ m_input_queue_lock.unlock(); ++ ++ m_output_queue_lock.lock(); ++ m_output_queue = std::queue(); ++ m_output_queue_lock.unlock(); ++ ++ m_vpp->Flush(); ++} ++ ++void CVPPThread::CheckMethod(int method) ++{ ++ if(method == m_last_method || !m_vpp->VppReady()) ++ return; ++ ++ EINTERLACEMETHOD emethod = (EINTERLACEMETHOD)method; ++ ++ m_vpp->DeinitDeint(); ++ ++ if(method == VS_INTERLACEMETHOD_VAAPI_AUTO || method == VS_INTERLACEMETHOD_AUTO) ++ { ++ if( !CVPP::DeintSupported(VAAPI::DeinterlacingBob) ++ || !m_vpp->InitDeint(VAAPI::DeinterlacingBob, m_num_refs)) ++ { ++ int i; ++ for(i = VAAPI::Deinterlacing_Count - 1; i >= 1; --i) ++ if(CVPP::DeintSupported((DeintMethod)i)) ++ if(m_vpp->InitDeint((DeintMethod)i, m_num_refs)) ++ break; ++ ++ if(i < 1) ++ CLog::Log(LOGDEBUG, "VAAPI - Requested auto deint method, but no method initialized propperly!"); ++ } ++ } ++ else if(method == VS_INTERLACEMETHOD_VAAPI_WEAVE) ++ { ++ if(CVPP::DeintSupported(VAAPI::DeinterlacingWeave)) ++ m_vpp->InitDeint(VAAPI::DeinterlacingWeave, m_num_refs); ++ else ++ CLog::Log(LOGDEBUG, "VAAPI - Requested unsupported deint method \"Weave\""); ++ } ++ else if(method == VS_INTERLACEMETHOD_VAAPI_BOB) ++ { ++ if(CVPP::DeintSupported(VAAPI::DeinterlacingBob)) ++ m_vpp->InitDeint(VAAPI::DeinterlacingBob, m_num_refs); ++ else ++ CLog::Log(LOGDEBUG, "VAAPI - Requested unsupported deint method \"Bob\""); ++ } ++ else if(method == VS_INTERLACEMETHOD_VAAPI_MOTION_ADAPTIVE) ++ { ++ if(CVPP::DeintSupported(VAAPI::DeinterlacingMotionAdaptive)) ++ m_vpp->InitDeint(VAAPI::DeinterlacingMotionAdaptive, m_num_refs); ++ else ++ CLog::Log(LOGDEBUG, "VAAPI - Requested unsupported deint method \"Motion Adaptive\""); ++ } ++ else if(method == VS_INTERLACEMETHOD_VAAPI_MOTION_COMPENSATED) ++ { ++ if(CVPP::DeintSupported(VAAPI::DeinterlacingMotionCompensated)) ++ m_vpp->InitDeint(VAAPI::DeinterlacingMotionCompensated, m_num_refs); ++ else ++ CLog::Log(LOGDEBUG, "VAAPI - Requested unsupported deint method \"Motion Compensated\""); ++ } ++ ++ m_last_method = method; ++} ++ ++void CVPPThread::DoDeinterlacing(const CVPPPicture &frame, bool topFieldFirst, bool firstCall) ++{ ++ if(!m_vpp->DeintReady()) ++ return; ++ ++ CVPPPicture res = m_vpp->DoDeint(frame, topFieldFirst, firstCall); ++ if(!res.valid) ++ return; ++ ++ res.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | DVP_FLAG_REPEAT_TOP_FIELD | DVP_FLAG_INTERLACED); ++ ++ if(!firstCall) ++ { ++ res.DVDPic.pts = DVD_NOPTS_VALUE; ++ res.DVDPic.dts = DVD_NOPTS_VALUE; ++ } ++ ++ res.DVDPic.iRepeatPicture = 0.0; ++ ++ InsertOutputFrame(res); ++} ++ ++void CVPPThread::Process() ++{ ++ CVPPPicture currentFrame = CVPPPicture(); ++ ++ m_work_lock.lock(); ++ ++ while(!m_stop) ++ { ++ if(currentFrame.valid) ++ { ++ bool isInterlaced = currentFrame.DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ bool skipDeint = false; ++ //if(currentFrame.DVDPic.iFlags & DVP_FLAG_DROPDEINT) ++ // skipDeint = true; ++ ++ EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; ++ ++ CheckMethod((int)method); ++ ++ bool doDeint = m_vpp->DeintReady() ++ && (mode == VS_DEINTERLACEMODE_FORCE || (mode == VS_DEINTERLACEMODE_AUTO && isInterlaced)); ++ ++ m_can_skip_deint = doDeint; ++ ++ if(doDeint && !skipDeint) ++ { ++ bool topFieldFirst = currentFrame.DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST == DVP_FLAG_TOP_FIELD_FIRST; ++ ++ DoDeinterlacing(currentFrame, topFieldFirst, true); ++ DoDeinterlacing(currentFrame, topFieldFirst, false); ++ } ++ else ++ { ++ CVPPPicture res; ++ res.valid = true; ++ res.DVDPic = currentFrame.DVDPic; ++ res.surface = currentFrame.surface; ++ InsertOutputFrame(res); ++ } ++ } ++ ++ currentFrame = CVPPPicture(); ++ ++ m_work_lock.unlock(); ++ currentFrame = GetCurrentFrame(); ++ m_work_lock.lock(); ++ } ++ ++ m_work_lock.unlock(); ++} ++ ++bool VAAPI::VppSupported() ++{ ++ return CVPP::VppSupported(); ++} ++ ++bool VAAPI::DeintSupported(DeintMethod method) ++{ ++ return CVPP::DeintSupported(method); ++} ++ + #endif ++ +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +index a520e42..684b8d0 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +@@ -23,11 +23,16 @@ + + #include "DllAvCodec.h" + #include "DVDVideoCodecFFmpeg.h" ++#include "threads/Thread.h" ++#include "threads/Condition.h" ++#include "threads/CriticalSection.h" ++ + #include + #include + #include + #include + #include ++#include + #include + + +@@ -83,13 +88,16 @@ struct CSurfaceGL + , m_display(display) + {} + ~CSurfaceGL(); +- ++ + void* m_id; + CDisplayPtr m_display; + }; + + typedef boost::shared_ptr CSurfaceGLPtr; + ++class CVPP; ++typedef boost::shared_ptr CVPPPtr; ++ + // silly type to avoid includes + struct CHolder + { +@@ -101,6 +109,59 @@ struct CHolder + {} + }; + ++struct CVPPPicture; ++ ++class CVPPThread : private CThread ++{ ++public: ++ CVPPThread(CDisplayPtr& display, int width, int height); ++ ~CVPPThread(); ++ ++ bool Init(int num_refs); ++ void Start(); ++ void Dispose(); ++ ++ void InsertNewFrame(CVPPPicture &new_frame); ++ CVPPPicture GetOutputPicture(); ++ ++ int GetInputQueueSize(); ++ int GetOutputQueueSize(); ++ ++ void Flush(); ++ ++ inline CVPPPtr getVPP() { return m_vpp; } ++ inline bool CanSkipDeint() { return m_can_skip_deint; } ++ ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ ++ void InsertOutputFrame(CVPPPicture &new_frame); ++ CVPPPicture GetCurrentFrame(); ++ void DoDeinterlacing(const CVPPPicture &frame, bool topFieldFirst, bool firstCall); ++ void CheckMethod(int method); ++ ++ CVPPPtr m_vpp; ++ ++ bool m_stop; ++ ++ bool m_can_skip_deint; ++ int m_num_refs; ++ int m_last_method; ++ ++ CCriticalSection m_work_lock; ++ ++ CCriticalSection m_input_queue_lock; ++ XbmcThreads::ConditionVariable m_input_cond; ++ std::queue m_input_queue; ++ ++ CCriticalSection m_output_queue_lock; ++ std::queue m_output_queue; ++}; ++ ++typedef boost::shared_ptr CVPPThreadPtr; ++ + class CDecoder + : public CDVDVideoCodecFFmpeg::IHardwareDecoder + { +@@ -113,22 +174,26 @@ public: + virtual int Decode (AVCodecContext* avctx, AVFrame* frame); + virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); + virtual int Check (AVCodecContext* avctx); ++ virtual void Reset (); + virtual void Close(); + virtual const std::string Name() { return "vaapi"; } + virtual CCriticalSection* Section() { if(m_display) return m_display.get(); else return NULL; } + virtual unsigned GetAllowedReferences(); ++ virtual bool CanSkipDeint() { if(m_vppth) return m_vppth->CanSkipDeint(); else return false; } + + int GetBuffer(AVCodecContext *avctx, AVFrame *pic); + void RelBuffer(AVCodecContext *avctx, AVFrame *pic); + + VADisplay GetDisplay() { return m_display->get(); } + protected: +- ++ + static const unsigned m_surfaces_max = 32; + unsigned m_surfaces_count; + VASurfaceID m_surfaces[m_surfaces_max]; + unsigned m_renderbuffers_count; + ++ int m_buffer_size; ++ + int m_refs; + std::list m_surfaces_used; + std::list m_surfaces_free; +@@ -139,7 +204,23 @@ protected: + + vaapi_context *m_hwaccel; + ++ CVPPThreadPtr m_vppth; ++ + CHolder m_holder; // silly struct to pass data to renderer + }; + ++enum DeintMethod ++{ ++ DeinterlacingNone = 0, ++ DeinterlacingWeave, ++ DeinterlacingBob, ++ DeinterlacingMotionAdaptive, ++ DeinterlacingMotionCompensated, ++ Deinterlacing_Count ++}; ++ ++bool VppSupported(); ++bool DeintSupported(DeintMethod method); ++ + } ++ +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 614e869..3667806 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -167,6 +167,7 @@ void CAdvancedSettings::Initialize() + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect + m_videoVDPAUtelecine = false; + m_videoVDPAUdeintSkipChromaHD = false; ++ m_useVAAPIAdvancedDeinterlacing = false; + m_DXVACheckCompatibility = false; + m_DXVACheckCompatibilityPresent = false; + m_DXVAForceProcessorRenderer = true; +@@ -605,6 +606,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); + XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); + XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); ++ XMLUtils::GetBoolean(pElement, "vaapiadvanceddeint", m_useVAAPIAdvancedDeinterlacing); + + TiXmlElement* pStagefrightElem = pElement->FirstChildElement("stagefright"); + if (pStagefrightElem) +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index 7d16957..6eae4ee 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -162,6 +162,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler + CStdString m_videoPPFFmpegPostProc; + bool m_videoVDPAUtelecine; + bool m_videoVDPAUdeintSkipChromaHD; ++ bool m_useVAAPIAdvancedDeinterlacing; + bool m_musicUseTimeSeeking; + int m_musicTimeSeekForward; + int m_musicTimeSeekBackward; +diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h +index 293f363..199290f 100644 +--- a/xbmc/settings/VideoSettings.h ++++ b/xbmc/settings/VideoSettings.h +@@ -63,6 +63,12 @@ enum EINTERLACEMETHOD + VS_INTERLACEMETHOD_SW_BLEND = 20, + VS_INTERLACEMETHOD_AUTO_ION = 21, + ++ VS_INTERLACEMETHOD_VAAPI_AUTO = 22, ++ VS_INTERLACEMETHOD_VAAPI_WEAVE = 23, ++ VS_INTERLACEMETHOD_VAAPI_BOB = 24, ++ VS_INTERLACEMETHOD_VAAPI_MOTION_ADAPTIVE = 25, ++ VS_INTERLACEMETHOD_VAAPI_MOTION_COMPENSATED = 26, ++ + VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. + }; + +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index 5218a83..6eca774 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -116,6 +116,11 @@ void CGUIDialogVideoSettings::CreateSettings() + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BOB , 16320)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BEST , 16321)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_AUTO_ION , 16325)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VAAPI_AUTO , 16326)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VAAPI_WEAVE , 16327)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VAAPI_BOB , 16328)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VAAPI_MOTION_ADAPTIVE , 16329)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VAAPI_MOTION_COMPENSATED , 16330)); + + /* remove unsupported methods */ + for(vector >::iterator it = entries.begin(); it != entries.end();) +-- +1.8.3.2 + diff --git a/packages/multimedia/libva-driver-intel/patches.upstream/libva-driver-intel-fix-surface_empty.patch b/packages/multimedia/libva-driver-intel/patches.upstream/libva-driver-intel-fix-surface_empty.patch new file mode 100644 index 0000000000..a912d87883 --- /dev/null +++ b/packages/multimedia/libva-driver-intel/patches.upstream/libva-driver-intel-fix-surface_empty.patch @@ -0,0 +1,16 @@ +diff --git a/src/i965_drv_video.c b/src/i965_drv_video.c +index 31dafa2..a58eb7b 100755 +--- a/src/i965_drv_video.c ++++ b/src/i965_drv_video.c +@@ -2358,7 +2358,11 @@ i965_QuerySurfaceStatus(VADriverContextP ctx, + *status = VASurfaceReady; + } + } else { ++#ifdef HAVE_VA_SURFACE_STATUS_EMPTY ++ *status = VASurfaceReady | VASurfaceEmpty; ++#else + *status = VASurfaceReady; ++#endif + } + + return VA_STATUS_SUCCESS; diff --git a/packages/multimedia/libva/patches/libva-patch-surface_empty.patch b/packages/multimedia/libva/patches/libva-patch-surface_empty.patch new file mode 100644 index 0000000000..2b5bb590d4 --- /dev/null +++ b/packages/multimedia/libva/patches/libva-patch-surface_empty.patch @@ -0,0 +1,23 @@ +diff --git a/va/va.h b/va/va.h +index d9e4c7e..dc0f092 100644 +--- a/va/va.h ++++ b/va/va.h +@@ -1905,6 +1905,8 @@ VAStatus vaSyncSurface ( + VASurfaceID render_target + ); + ++#define HAVE_VA_SURFACE_STATUS_EMPTY 1 ++ + typedef enum + { + VASurfaceRendering = 1, /* Rendering in progress */ +@@ -1912,7 +1914,8 @@ typedef enum + /* this status is useful if surface is used as the source */ + /* of an overlay */ + VASurfaceReady = 4, /* not being rendered or displayed */ +- VASurfaceSkipped = 8 /* Indicate a skipped frame during encode */ ++ VASurfaceSkipped = 8, /* Indicate a skipped frame during encode */ ++ VASurfaceEmpty = 16 /* contains no actual data */ + } VASurfaceStatus; + + /*