From 0020c9e146267fa3cbf8f247653628744f176204 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 6 Jul 2014 20:19:57 +0200 Subject: [PATCH] xbmc-master_ update to xbmc-master-14-687ac52, update FM patch, add patch to fix commit https://github.com/xbmc/xbmc/commit/6322457ea46e83491fa0675cb6ac9bf2e3578882 Signed-off-by: Stephan Raue --- .../xbmc-master-theme-Confluence/package.mk | 2 +- packages/mediacenter/xbmc-master/package.mk | 2 +- .../xbmc-master-995.01-fernetmenta.patch | 6278 +++++++++++++---- ...xbmc-master-999.91-patch_for_6322457.patch | 12 + 4 files changed, 5082 insertions(+), 1212 deletions(-) create mode 100644 packages/mediacenter/xbmc-master/patches/xbmc-master-999.91-patch_for_6322457.patch diff --git a/packages/mediacenter/xbmc-master-theme-Confluence/package.mk b/packages/mediacenter/xbmc-master-theme-Confluence/package.mk index dbd52978a0..9561dff32b 100644 --- a/packages/mediacenter/xbmc-master-theme-Confluence/package.mk +++ b/packages/mediacenter/xbmc-master-theme-Confluence/package.mk @@ -17,7 +17,7 @@ ################################################################################ PKG_NAME="xbmc-master-theme-Confluence" -PKG_VERSION="14-603c7fa" +PKG_VERSION="14-687ac52" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/mediacenter/xbmc-master/package.mk b/packages/mediacenter/xbmc-master/package.mk index 79b8af7fc4..af84e7903c 100644 --- a/packages/mediacenter/xbmc-master/package.mk +++ b/packages/mediacenter/xbmc-master/package.mk @@ -17,7 +17,7 @@ ################################################################################ PKG_NAME="xbmc-master" -PKG_VERSION="14-603c7fa" +PKG_VERSION="14-687ac52" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta.patch index 9b4386061b..26567c63b4 100644 --- a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta.patch +++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta.patch @@ -1,7 +1,7 @@ -From 653f57ae1d9895d66a0a4a188607ae9f93db7022 Mon Sep 17 00:00:00 2001 +From ac2b6e5ff95df17ab34590b569df8a68ad2201c1 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:34:39 +0200 -Subject: [PATCH 09/35] videoplayer: adapt lateness detection and dropping to +Subject: [PATCH 01/22] videoplayer: adapt lateness detection and dropping to buffering --- @@ -10,12 +10,12 @@ Subject: [PATCH 09/35] videoplayer: adapt lateness detection and dropping to .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 38 +++- .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 41 +++++ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 + - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 197 +++++++++++++++++---- - xbmc/cores/dvdplayer/DVDPlayerVideo.h | 22 +++ - 7 files changed, 295 insertions(+), 38 deletions(-) + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 199 ++++++++++++++++----- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 23 ++- + 7 files changed, 288 insertions(+), 48 deletions(-) diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 6832721..f4b381e 100644 +index ca9aa84..85467d2 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp @@ -286,6 +286,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi @@ -27,7 +27,7 @@ index 6832721..f4b381e 100644 m_presentevent.notifyAll(); m_firstFlipPage = false; // tempfix -@@ -629,7 +631,7 @@ void CXBMCRenderManager::SetViewMode(int iViewMode) +@@ -631,7 +633,7 @@ void CXBMCRenderManager::SetViewMode(int iViewMode) m_pRenderer->SetViewMode(iViewMode); } @@ -36,7 +36,7 @@ index 6832721..f4b381e 100644 { { CSharedLock lock(m_sharedSection); -@@ -697,6 +699,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L +@@ -699,6 +701,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L m.timestamp = timestamp; m.presentfield = sync; m.presentmethod = presentmethod; @@ -44,7 +44,7 @@ index 6832721..f4b381e 100644 requeue(m_queued, m_free); /* signal to any waiters to check state */ -@@ -1065,6 +1068,8 @@ void CXBMCRenderManager::PrepareNextRender() +@@ -1073,6 +1076,8 @@ void CXBMCRenderManager::PrepareNextRender() m_discard.push_back(m_presentsource); m_presentsource = idx; m_queued.pop_front(); @@ -53,7 +53,7 @@ index 6832721..f4b381e 100644 m_presentevent.notifyAll(); } } -@@ -1081,3 +1086,12 @@ void CXBMCRenderManager::DiscardBuffer() +@@ -1089,3 +1094,12 @@ void CXBMCRenderManager::DiscardBuffer() m_presentstep = PRESENT_IDLE; m_presentevent.notifyAll(); } @@ -67,7 +67,7 @@ index 6832721..f4b381e 100644 + return true; +} diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index c469795..949c652b 100644 +index c3f5517..d84ff6c 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.h +++ b/xbmc/cores/VideoRenderers/RenderManager.h @@ -98,10 +98,11 @@ class CXBMCRenderManager @@ -289,7 +289,7 @@ index 75ac0f2..1a80a48 100644 + int m_codecControlFlags; }; diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 633e333..09b7772 100644 +index 633e333..2950930 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp @@ -38,6 +38,7 @@ @@ -300,7 +300,23 @@ index 633e333..09b7772 100644 #include #include #include -@@ -319,8 +320,10 @@ void CDVDPlayerVideo::Process() +@@ -147,7 +148,6 @@ CDVDPlayerVideo::CDVDPlayerVideo( CDVDClock* pClock + m_messageQueue.SetMaxDataSize(40 * 1024 * 1024); + m_messageQueue.SetMaxTimeSize(8.0); + +- m_iCurrentPts = DVD_NOPTS_VALUE; + m_iDroppedFrames = 0; + m_fFrameRate = 25; + m_bCalcFrameRate = false; +@@ -297,7 +297,6 @@ void CDVDPlayerVideo::OnStartup() + m_crop.x1 = m_crop.x2 = 0.0f; + m_crop.y1 = m_crop.y2 = 0.0f; + +- m_iCurrentPts = DVD_NOPTS_VALUE; + m_FlipTimeStamp = m_pClock->GetAbsoluteClock(); + m_FlipTimePts = 0.0; + } +@@ -319,8 +318,10 @@ void CDVDPlayerVideo::Process() int iDropped = 0; //frames dropped in a row bool bRequestDrop = false; @@ -311,7 +327,7 @@ index 633e333..09b7772 100644 while (!m_bStop) { -@@ -432,6 +435,7 @@ void CDVDPlayerVideo::Process() +@@ -432,6 +433,7 @@ void CDVDPlayerVideo::Process() picture.iFlags &= ~DVP_FLAG_ALLOCATED; m_packets.clear(); m_started = false; @@ -319,7 +335,7 @@ index 633e333..09b7772 100644 } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) { -@@ -444,6 +448,7 @@ void CDVDPlayerVideo::Process() +@@ -444,6 +446,7 @@ void CDVDPlayerVideo::Process() //we need to recalculate the framerate //TODO: this needs to be set on a streamchange instead ResetFrameRateCalc(); @@ -327,7 +343,7 @@ index 633e333..09b7772 100644 m_stalled = true; m_started = false; -@@ -463,6 +468,7 @@ void CDVDPlayerVideo::Process() +@@ -463,6 +466,7 @@ void CDVDPlayerVideo::Process() m_iNrOfPicturesNotToSkip = 0; if (m_pVideoCodec) m_pVideoCodec->SetSpeed(m_speed); @@ -335,7 +351,7 @@ index 633e333..09b7772 100644 } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { -@@ -508,6 +514,28 @@ void CDVDPlayerVideo::Process() +@@ -508,6 +512,28 @@ void CDVDPlayerVideo::Process() m_iNrOfPicturesNotToSkip = 1; } @@ -364,7 +380,7 @@ index 633e333..09b7772 100644 if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { -@@ -560,15 +588,7 @@ void CDVDPlayerVideo::Process() +@@ -560,15 +586,7 @@ void CDVDPlayerVideo::Process() } m_videoStats.AddSampleBytes(pPacket->iSize); @@ -381,7 +397,19 @@ index 633e333..09b7772 100644 // reset the request, the following while loop may break before // setting the flag to a new value bRequestDrop = false; -@@ -1182,33 +1202,12 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) +@@ -1170,45 +1188,17 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + , "CDVDPlayerVideo::OutputPicture"); + } + +- // present the current pts of this frame to user, and include the actual +- // presentation delay, to allow him to adjust for it +- if( m_stalled ) +- m_iCurrentPts = DVD_NOPTS_VALUE; +- else +- m_iCurrentPts = pts - max(0.0, iSleepTime); +- + // timestamp when we think next picture should be displayed based on current duration + m_FlipTimeStamp = iCurrentClock; m_FlipTimeStamp += max(0.0, iSleepTime); m_FlipTimePts = pts; @@ -419,7 +447,7 @@ index 633e333..09b7772 100644 // set fieldsync if picture is interlaced EFIELDSYNC mDisplayField = FS_NONE; -@@ -1241,7 +1240,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) +@@ -1241,7 +1231,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) if (index < 0) return EOS_DROPPED; @@ -428,7 +456,7 @@ index 633e333..09b7772 100644 return result; #else -@@ -1541,3 +1540,131 @@ void CDVDPlayerVideo::CalcFrameRate() +@@ -1541,3 +1531,124 @@ void CDVDPlayerVideo::CalcFrameRate() m_iFrameRateCount = 0; } } @@ -466,13 +494,6 @@ index 633e333..09b7772 100644 + + iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; + -+ m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval; -+ -+ if (m_stalled) -+ m_iCurrentPts = DVD_NOPTS_VALUE; -+ else -+ m_iCurrentPts = iRenderPts - max(0.0, iSleepTime); -+ + if (m_droppingStats.m_lastDecoderPts > 0 + && bNewFrame + && m_bAllowDrop) @@ -561,7 +582,7 @@ index 633e333..09b7772 100644 + m_totalGain += frametime; +} diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index 296cae6..328edbf 100644 +index 296cae6..4795ca0 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h @@ -37,6 +37,24 @@ class CDVDOverlayCodecCC; @@ -597,7 +618,15 @@ index 296cae6..328edbf 100644 void AutoCrop(DVDVideoPicture* pPicture); void AutoCrop(DVDVideoPicture *pPicture, RECT &crop); -@@ -131,6 +150,7 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer +@@ -119,7 +138,6 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer + CDVDMessageQueue m_messageQueue; + CDVDMessageQueue& m_messageParent; + +- double m_iCurrentPts; // last pts displayed + double m_iVideoDelay; + double m_iSubtitleDelay; + double m_FlipTimeStamp; // time stamp of last flippage. used to play at a forced framerate +@@ -131,6 +149,7 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer void ResetFrameRateCalc(); void CalcFrameRate(); @@ -605,7 +634,7 @@ index 296cae6..328edbf 100644 double m_fFrameRate; //framerate of the video currently playing bool m_bCalcFrameRate; //if we should calculate the framerate from the timestamps -@@ -184,5 +204,7 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer +@@ -184,5 +203,7 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer CPullupCorrection m_pullupCorrection; std::list m_packets; @@ -617,10 +646,10 @@ index 296cae6..328edbf 100644 1.9.3 -From 2efc326a47e290a801cd835296b6045e72d0e212 Mon Sep 17 00:00:00 2001 +From 61b70c09a08ade5130304a6497a59195c0ce9a93 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 2 Sep 2012 16:05:21 +0200 -Subject: [PATCH 10/35] video player: present correct pts to user for a/v sync +Subject: [PATCH 02/22] video player: present correct pts to user for a/v sync (after buffering in renderer) --- @@ -629,10 +658,10 @@ Subject: [PATCH 10/35] video player: present correct pts to user for a/v sync 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 09b7772..24282cc 100644 +index 2950930..1e5a890 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1460,6 +1460,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc() +@@ -1451,6 +1451,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc() g_advancedSettings.m_videoFpsDetect == 0; } @@ -656,7 +685,7 @@ index 09b7772..24282cc 100644 #define MAXFRAMESERR 1000 diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index 328edbf..1cca436 100644 +index 4795ca0..b60a0ee 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h @@ -100,7 +100,7 @@ class CDVDPlayerVideo : public CThread, public IDVDStreamPlayer @@ -672,10 +701,10 @@ index 328edbf..1cca436 100644 1.9.3 -From 5f08b21d01b7c74e78024485a2b2d5874804b5f7 Mon Sep 17 00:00:00 2001 +From 319de4fbc9a7fb22cc787b5305e10c0d118d1443 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 1 Jun 2013 11:21:19 +0200 -Subject: [PATCH 11/35] renderer: bump buffers to 5 +Subject: [PATCH 03/22] renderer: bump buffers to 5 --- xbmc/cores/VideoRenderers/BaseRenderer.h | 2 +- @@ -698,10 +727,10 @@ index fb41ccf..f5e5677 100644 1.9.3 -From 5e1bf08878926117994fc7e4ef011b0592bdd309 Mon Sep 17 00:00:00 2001 +From 972d17df30bd2e8944ce1cb9ffda97fce7d1ce41 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:41:31 +0200 -Subject: [PATCH 12/35] videoplayer: update frametime, it might change due to +Subject: [PATCH 04/22] videoplayer: update frametime, it might change due to fps detection --- @@ -709,10 +738,10 @@ Subject: [PATCH 12/35] videoplayer: update frametime, it might change due to 1 file changed, 2 insertions(+) diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 24282cc..5c219d6 100644 +index 1e5a890..4c3e608 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -708,6 +708,8 @@ void CDVDPlayerVideo::Process() +@@ -706,6 +706,8 @@ void CDVDPlayerVideo::Process() int iResult = OutputPicture(&picture, pts); @@ -725,10 +754,10 @@ index 24282cc..5c219d6 100644 1.9.3 -From a4f5190b81b1e1f46771282f4520e50256fc67c5 Mon Sep 17 00:00:00 2001 +From 129564a444948768d5af752cf1178ebc389dd656 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:43:06 +0200 -Subject: [PATCH 13/35] videoplayer: give streams with invalid fps a chance for +Subject: [PATCH 05/22] videoplayer: give streams with invalid fps a chance for fps detection --- @@ -736,10 +765,10 @@ Subject: [PATCH 13/35] videoplayer: give streams with invalid fps a chance for 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 5c219d6..767f6bd 100644 +index 4c3e608..4e91ff2 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1502,7 +1502,7 @@ void CDVDPlayerVideo::CalcFrameRate() +@@ -1493,7 +1493,7 @@ void CDVDPlayerVideo::CalcFrameRate() double frameduration = m_pullupCorrection.GetFrameDuration(); if (frameduration == DVD_NOPTS_VALUE || @@ -752,10 +781,10 @@ index 5c219d6..767f6bd 100644 1.9.3 -From 6706086f632fb0a291e007851bedb8a1673c3cdb Mon Sep 17 00:00:00 2001 +From 9b5f3ecef25b629f72e41d617c22cbf47a9375f8 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:49:05 +0200 -Subject: [PATCH 14/35] dvdplayer: allow rewinding at end of stream, do a seek +Subject: [PATCH 06/22] dvdplayer: allow rewinding at end of stream, do a seek after rewind --- @@ -763,10 +792,10 @@ Subject: [PATCH 14/35] dvdplayer: allow rewinding at end of stream, do a seek 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 85b9f1c..1b2f820 100644 +index af0e493..ae000a7 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -1595,7 +1595,7 @@ void CDVDPlayer::HandlePlaySpeed() +@@ -1587,7 +1587,7 @@ void CDVDPlayer::HandlePlaySpeed() } else if (m_CurrentVideo.id >= 0 @@ -775,7 +804,7 @@ index 85b9f1c..1b2f820 100644 && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() && m_SpeedState.lasttime != GetTime()) { -@@ -2219,6 +2219,12 @@ void CDVDPlayer::HandleMessages() +@@ -2213,6 +2213,12 @@ void CDVDPlayer::HandleMessages() pvrinputstream->Pause( speed == 0 ); } @@ -792,10 +821,10 @@ index 85b9f1c..1b2f820 100644 1.9.3 -From ece66466f1d6666816db1631a5be2b4c505fa926 Mon Sep 17 00:00:00 2001 +From ad6a18699cf116823cd291597b5c301f295676c7 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 20 Aug 2012 16:06:39 +0200 -Subject: [PATCH 15/35] dvdplayer: observe pts counter overflow +Subject: [PATCH 07/22] dvdplayer: observe pts counter overflow --- .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 197 ++++++++++++++++++++- @@ -803,7 +832,7 @@ Subject: [PATCH 15/35] dvdplayer: observe pts counter overflow 2 files changed, 200 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 710482f..49eff5c 100644 +index 7ef23f3..25940e6 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -18,7 +18,6 @@ @@ -1054,10 +1083,10 @@ index 710482f..49eff5c 100644 { CSingleLock lock(m_critSection); diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -index 44e101c..3b0f615 100644 +index 3fd011e..980d01e 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -@@ -99,6 +99,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux +@@ -100,6 +100,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux DemuxPacket* Read(); bool SeekTime(int time, bool backwords = false, double* startpts = NULL); @@ -1065,7 +1094,7 @@ index 44e101c..3b0f615 100644 bool SeekByte(int64_t pos); int GetStreamLength(); CDemuxStream* GetStream(int iStreamId); -@@ -153,5 +154,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux +@@ -154,5 +155,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux AVPacket pkt; // packet ffmpeg returned int result; // result from av_read_packet }m_pkt; @@ -1078,10 +1107,10 @@ index 44e101c..3b0f615 100644 1.9.3 -From d976c334c57f17e91c35a43af189ee43ffcfb56a Mon Sep 17 00:00:00 2001 +From c3a82b97175d13c0999106ac6cb3fccb62d00b0e Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 2 Oct 2012 13:02:10 +0200 -Subject: [PATCH 16/35] dvdplayer: avoid short screen flicker caused by +Subject: [PATCH 08/22] dvdplayer: avoid short screen flicker caused by unnecessary reconfigure of renderer --- @@ -1089,10 +1118,10 @@ Subject: [PATCH 16/35] dvdplayer: avoid short screen flicker caused by 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 767f6bd..f905008 100644 +index 4e91ff2..07615a0 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1054,13 +1054,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) +@@ -1052,13 +1052,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) #ifdef HAS_VIDEO_PLAYBACK double config_framerate = m_bFpsInvalid ? 0.0 : m_fFrameRate; @@ -1114,10 +1143,10 @@ index 767f6bd..f905008 100644 1.9.3 -From abb0d4888fd5467b44e67d2050d06f33eb7bb2f3 Mon Sep 17 00:00:00 2001 +From 1b24eb3159c29cd3908b66f7af90993381be26e1 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 11 Oct 2012 12:05:50 +0200 -Subject: [PATCH 17/35] vdpau: advanced settings for auto deinterlacing +Subject: [PATCH 09/22] vdpau: advanced settings for auto deinterlacing --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- @@ -1145,10 +1174,10 @@ index e58681b..3f87a7d 100644 if (deint != -1) { diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 6835504..7d50649 100644 +index 59b4d9e..d839d96 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp -@@ -157,6 +157,8 @@ void CAdvancedSettings::Initialize() +@@ -156,6 +156,8 @@ void CAdvancedSettings::Initialize() m_videoAutoScaleMaxFps = 30.0f; m_videoDisableBackgroundDeinterlace = false; m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect @@ -1157,7 +1186,7 @@ index 6835504..7d50649 100644 m_videoVDPAUtelecine = false; m_videoVDPAUdeintSkipChromaHD = false; m_DXVACheckCompatibility = false; -@@ -596,6 +598,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) +@@ -590,6 +592,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) XMLUtils::GetBoolean(pElement,"disableswmultithreading",m_videoDisableSWMultithreading); XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); @@ -1167,10 +1196,10 @@ index 6835504..7d50649 100644 XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index c57a9fb..6c505a8 100644 +index 7e50a63..980138e 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h -@@ -163,6 +163,8 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler +@@ -162,6 +162,8 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler int m_videoPercentSeekBackwardBig; CStdString m_videoPPFFmpegDeint; CStdString m_videoPPFFmpegPostProc; @@ -1183,10 +1212,10 @@ index c57a9fb..6c505a8 100644 1.9.3 -From 4c23dd583f32e1e9a4327ccc910873163628cb9e Mon Sep 17 00:00:00 2001 +From 8b0b22b220709dc29f31ec3dfac24c0a38784c00 Mon Sep 17 00:00:00 2001 From: xbmc Date: Fri, 2 Nov 2012 13:20:03 +0100 -Subject: [PATCH 18/35] player: fix rewind +Subject: [PATCH 10/22] player: fix rewind --- xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- @@ -1197,10 +1226,10 @@ Subject: [PATCH 18/35] player: fix rewind 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h -index be6603a..6ff2400 100644 +index a7fbe08..9ce9b16 100644 --- a/xbmc/cores/dvdplayer/DVDMessage.h +++ b/xbmc/cores/dvdplayer/DVDMessage.h -@@ -220,7 +220,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg +@@ -212,7 +212,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg class CDVDMsgPlayerSeek : public CDVDMsg { public: @@ -1209,7 +1238,7 @@ index be6603a..6ff2400 100644 : CDVDMsg(PLAYER_SEEK) , m_time(time) , m_backward(backward) -@@ -228,6 +228,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg +@@ -220,6 +220,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg , m_accurate(accurate) , m_restore(restore) , m_trickplay(trickplay) @@ -1217,7 +1246,7 @@ index be6603a..6ff2400 100644 {} int GetTime() { return m_time; } bool GetBackward() { return m_backward; } -@@ -235,6 +236,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg +@@ -227,6 +228,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg bool GetAccurate() { return m_accurate; } bool GetRestore() { return m_restore; } bool GetTrickPlay() { return m_trickplay; } @@ -1225,7 +1254,7 @@ index be6603a..6ff2400 100644 private: int m_time; bool m_backward; -@@ -242,6 +244,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg +@@ -234,6 +236,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg bool m_accurate; bool m_restore; // whether to restore any EDL cut time bool m_trickplay; @@ -1234,10 +1263,10 @@ index be6603a..6ff2400 100644 class CDVDMsgPlayerSeekChapter : public CDVDMsg diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 1b2f820..018f4f7 100644 +index ae000a7..4534429 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -1596,11 +1596,13 @@ void CDVDPlayer::HandlePlaySpeed() +@@ -1588,11 +1588,13 @@ void CDVDPlayer::HandlePlaySpeed() } else if (m_CurrentVideo.id >= 0 && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file @@ -1252,7 +1281,7 @@ index 1b2f820..018f4f7 100644 // check how much off clock video is when ff/rw:ing // a problem here is that seeking isn't very accurate // and since the clock will be resynced after seek -@@ -1619,7 +1621,7 @@ void CDVDPlayer::HandlePlaySpeed() +@@ -1611,7 +1613,7 @@ void CDVDPlayer::HandlePlaySpeed() { CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up"); int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL); @@ -1261,7 +1290,7 @@ index 1b2f820..018f4f7 100644 } } } -@@ -2068,7 +2070,7 @@ void CDVDPlayer::HandleMessages() +@@ -2062,7 +2064,7 @@ void CDVDPlayer::HandleMessages() else m_StateInput.dts = start; @@ -1270,7 +1299,7 @@ index 1b2f820..018f4f7 100644 } else CLog::Log(LOGWARNING, "error while seeking"); -@@ -2204,9 +2206,10 @@ void CDVDPlayer::HandleMessages() +@@ -2198,9 +2200,10 @@ void CDVDPlayer::HandleMessages() double offset; offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; @@ -1282,7 +1311,7 @@ index 1b2f820..018f4f7 100644 m_State.timestamp = CDVDClock::GetAbsoluteClock(); } -@@ -2222,7 +2225,8 @@ void CDVDPlayer::HandleMessages() +@@ -2216,7 +2219,8 @@ void CDVDPlayer::HandleMessages() // do a seek after rewind, clock is not in sync with current pts if (m_playSpeed < 0 && speed >= 0) { @@ -1292,7 +1321,7 @@ index 1b2f820..018f4f7 100644 } // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE -@@ -3120,7 +3124,7 @@ void CDVDPlayer::UpdateClockMaster() +@@ -3112,7 +3116,7 @@ void CDVDPlayer::UpdateClockMaster() } } @@ -1301,7 +1330,7 @@ index 1b2f820..018f4f7 100644 { double startpts; if(accurate) -@@ -3132,19 +3136,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) +@@ -3124,19 +3128,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) if(startpts != DVD_NOPTS_VALUE) startpts -= m_offset_pts; @@ -1329,7 +1358,7 @@ index 1b2f820..018f4f7 100644 m_CurrentTeletext.dts = DVD_NOPTS_VALUE; m_CurrentTeletext.startpts = startpts; -@@ -3188,7 +3196,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) +@@ -3180,7 +3188,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) m_CurrentTeletext.started = false; } @@ -1364,10 +1393,10 @@ index bf73d27..91f63c0 100644 int m_errorCount; diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index f905008..3eb6315 100644 +index 07615a0..29ffb19 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1475,7 +1475,7 @@ double CDVDPlayerVideo::GetCurrentPts() +@@ -1466,7 +1466,7 @@ double CDVDPlayerVideo::GetCurrentPts() if( m_stalled ) iRenderPts = DVD_NOPTS_VALUE; @@ -1376,7 +1405,7 @@ index f905008..3eb6315 100644 iRenderPts = iRenderPts - max(0.0, iSleepTime); return iRenderPts; -@@ -1574,6 +1574,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) +@@ -1565,6 +1565,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) int iDroppedPics = -1; int iBufferLevel; @@ -1386,7 +1415,7 @@ index f905008..3eb6315 100644 if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iDroppedPics)) iDecoderPts = pts; diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index 1cca436..e8e382a 100644 +index b60a0ee..ecd2d20 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h @@ -51,6 +51,7 @@ class CDroppingStats @@ -1401,20 +1430,20 @@ index 1cca436..e8e382a 100644 1.9.3 -From bb97ddfbeecb72e6067b13bce8f517819cfbe8a3 Mon Sep 17 00:00:00 2001 +From c12c250c1fdcb7dbc8a9eeb50e69e6a9fe17e7cf Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 28 Mar 2013 15:18:53 +0100 -Subject: [PATCH 19/35] OMXPlayer: some caching fixes for pvr +Subject: [PATCH 11/22] OMXPlayer: some caching fixes for pvr --- xbmc/cores/omxplayer/OMXPlayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 80fe7c1..31b432f 100644 +index a4cfa1f..f65e51f 100644 --- a/xbmc/cores/omxplayer/OMXPlayer.cpp +++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -2548,7 +2548,8 @@ void COMXPlayer::HandleMessages() +@@ -2540,7 +2540,8 @@ void COMXPlayer::HandleMessages() m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), (speed < 0), true, false, false, true)); m_playSpeed = speed; @@ -1428,20 +1457,20 @@ index 80fe7c1..31b432f 100644 1.9.3 -From 337b26bc138f08f17481b4c299d95dfc25a08eb9 Mon Sep 17 00:00:00 2001 +From c9fc7f5fbf9eab3d805bd31430e37ff5548c92f3 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 28 Mar 2013 20:50:59 +0100 -Subject: [PATCH 20/35] fix incorrect display of fps when dr kicks in +Subject: [PATCH 12/22] fix incorrect display of fps when dr kicks in --- xbmc/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 748b529..bb28233 100644 +index c9690fc..063a11f 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp -@@ -2299,10 +2299,11 @@ void CApplication::Render() +@@ -2314,10 +2314,11 @@ void CApplication::Render() if (frameTime < singleFrameTime) Sleep(singleFrameTime - frameTime); } @@ -1458,80 +1487,17 @@ index 748b529..bb28233 100644 1.9.3 -From 02b1fb56e7a8c2ccd2ad9ae141bd8ec94cfe1240 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Tue, 11 Jun 2013 16:20:29 +0200 -Subject: [PATCH 21/35] renderer: allow some lateness within vblank interval - ---- - xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++++++++++-- - xbmc/cores/VideoRenderers/RenderManager.h | 1 + - 2 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index f4b381e..5e9f666 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -380,6 +380,8 @@ void CXBMCRenderManager::FrameFinish() - if(g_graphicsContext.IsFullScreenVideo()) - WaitPresentTime(m.timestamp); - -+ m_clock_framefinish = GetPresentTime(); -+ - { CSingleLock lock(m_presentlock); - - if(m_presentstep == PRESENT_FRAME) -@@ -1032,6 +1034,12 @@ void CXBMCRenderManager::PrepareNextRender() - - double clocktime = GetPresentTime(); - double frametime = 1.0 / GetMaximumFPS(); -+ double correction = 0.0; -+ int fps = g_VideoReferenceClock.GetRefreshRate(); -+ if((fps > 0) && g_graphicsContext.IsFullScreenVideo() && (clocktime != m_clock_framefinish)) -+ { -+ correction = frametime; -+ } - - /* see if any future queued frames are already due */ - std::deque::reverse_iterator curr, prev; -@@ -1040,8 +1048,8 @@ void CXBMCRenderManager::PrepareNextRender() - ++prev; - while (prev != m_queued.rend()) - { -- if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */ -- && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */ -+ if(clocktime > m_Queue[*prev].timestamp + correction /* previous frame is late */ -+ && clocktime > m_Queue[*curr].timestamp - frametime + correction) /* selected frame is close to it's display time */ - break; - ++curr; - ++prev; -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 949c652b..d84ff6c 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -252,6 +252,7 @@ class CXBMCRenderManager - XbmcThreads::ConditionVariable m_presentevent; - CCriticalSection m_presentlock; - CEvent m_flushEvent; -+ double m_clock_framefinish; - - - OVERLAY::CRenderer m_overlays; --- -1.9.3 - - -From d43d32bd23616abac9e76713bf0c4bf71661c9dd Mon Sep 17 00:00:00 2001 +From e068675a02a617286172bb9c608471e42a35206e Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Thu, 25 Jul 2013 17:18:13 +0200 -Subject: [PATCH 22/35] ActiveAE: slightly reduce buffer size +Subject: [PATCH 13/22] ActiveAE: slightly reduce buffer size --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index 2f71051..a824056 100644 +index 4ee53ec..895ab35 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -32,8 +32,8 @@ using namespace ActiveAE; @@ -1549,10 +1515,10 @@ index 2f71051..a824056 100644 1.9.3 -From b32c6b6c720383e8f87137508d196fce0ebbe058 Mon Sep 17 00:00:00 2001 +From 2e73121ce35406a561db0d7766a3b082abbb30fa Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 4 Aug 2013 10:11:16 +0200 -Subject: [PATCH 23/35] Revert "vdpau: comment some features that will be added +Subject: [PATCH 14/22] Revert "vdpau: comment some features that will be added later" This reverts commit e00b4f65864d623ab4d2e9e5c06db138e661f1cf. @@ -1608,21 +1574,21 @@ index 3f87a7d..f7418e8 100644 1.9.3 -From a0300251e43a107fdfac49f59e6456512f0de77a Mon Sep 17 00:00:00 2001 +From 03e5d080264bf4dcb86164a8cb499d2722216a16 Mon Sep 17 00:00:00 2001 From: Marcel Groothuis Date: Thu, 5 Dec 2013 22:02:50 +0100 -Subject: [PATCH 24/35] ffmpeg demuxer: faster channel change for PVR addons +Subject: [PATCH 15/22] ffmpeg demuxer: faster channel change for PVR addons without internal demuxing (such as MediaPortal, ArgusTV, MythTV, NextPVR) Credits: FernetMenta, Davilla, Popcornmix, Whaupt --- - .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 143 ++++++++++++++++++--- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 5 +- + .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 186 +++++++++++++++++++-- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 7 +- .../dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp | 13 +- - 3 files changed, 139 insertions(+), 22 deletions(-) + 3 files changed, 184 insertions(+), 22 deletions(-) diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 49eff5c..4d4be02 100644 +index 25940e6..8c19fc8 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -52,6 +52,8 @@ @@ -1634,15 +1600,16 @@ index 49eff5c..4d4be02 100644 void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo) { if(!m_stream) return; -@@ -153,6 +155,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() +@@ -153,6 +155,8 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() m_program = UINT_MAX; m_pkt.result = -1; memset(&m_pkt.pkt, 0, sizeof(AVPacket)); + m_streaminfo = true; /* set to true if we want to look for streams before playback */ ++ m_checkvideo = false; } CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg() -@@ -173,10 +176,11 @@ bool CDVDDemuxFFmpeg::Aborted() +@@ -173,10 +177,11 @@ bool CDVDDemuxFFmpeg::Aborted() return false; } @@ -1655,7 +1622,7 @@ index 49eff5c..4d4be02 100644 m_iCurrentPts = DVD_NOPTS_VALUE; m_speed = DVD_PLAYSPEED_NORMAL; m_program = UINT_MAX; -@@ -187,8 +191,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) +@@ -187,8 +192,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) m_pInput = pInput; strFile = m_pInput->GetFileName(); @@ -1664,7 +1631,17 @@ index 49eff5c..4d4be02 100644 if( m_pInput->GetContent().length() > 0 ) { std::string content = m_pInput->GetContent(); -@@ -388,13 +390,12 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) +@@ -384,17 +387,22 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) + m_pFormatContext->max_analyze_duration = 500000; + ++ if (iformat && (strcmp(iformat->name, "mpegts") == 0)) ++ { ++ m_pFormatContext->max_analyze_duration = 500000; ++ m_checkvideo = true; ++ } ++ + // we need to know if this is matroska or avi later m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; @@ -1680,17 +1657,27 @@ index 49eff5c..4d4be02 100644 CLog::Log(LOGDEBUG, "%s - avformat_find_stream_info starting", __FUNCTION__); int iErr = avformat_find_stream_info(m_pFormatContext, NULL); if (iErr < 0) -@@ -414,6 +415,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) +@@ -413,7 +421,19 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + } } CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__); ++ ++ if (m_checkvideo) ++ { ++ // make sure we start video with an i-frame ++ ResetVideoStreams(); ++ } } + else ++ { + m_program = 0; ++ m_checkvideo = true; ++ } + // reset any timeout m_timeout.SetInfinite(); -@@ -467,7 +471,7 @@ void CDVDDemuxFFmpeg::Reset() +@@ -467,7 +487,7 @@ void CDVDDemuxFFmpeg::Reset() { CDVDInputStream* pInputStream = m_pInput; Dispose(); @@ -1699,7 +1686,7 @@ index 49eff5c..4d4be02 100644 } void CDVDDemuxFFmpeg::Flush() -@@ -662,25 +666,32 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() +@@ -662,25 +682,32 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() } else { @@ -1742,7 +1729,7 @@ index 49eff5c..4d4be02 100644 if (pPacket) { -@@ -1623,3 +1634,101 @@ bool CDVDDemuxFFmpeg::IsProgramChange() +@@ -1623,3 +1650,128 @@ bool CDVDDemuxFFmpeg::IsProgramChange() } return false; } @@ -1782,7 +1769,7 @@ index 49eff5c..4d4be02 100644 + } + + // for video we need a decoder to get desired information into codec context -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec->extradata && + (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) + { + // open a decoder, it will be cleared down by ffmpeg on closing the stream @@ -1821,15 +1808,23 @@ index 49eff5c..4d4be02 100644 +bool CDVDDemuxFFmpeg::IsVideoReady() +{ + AVStream *st; ++ bool hasVideo = false; ++ ++ if(!m_checkvideo) ++ return true; ++ + if(m_program != UINT_MAX) + { + for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) + { + int idx = m_pFormatContext->programs[m_program]->stream_index[i]; + st = m_pFormatContext->streams[idx]; -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && -+ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) -+ return false; ++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ++ { ++ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE) ++ return true; ++ hasVideo = true; ++ } + } + } + else @@ -1837,18 +1832,37 @@ index 49eff5c..4d4be02 100644 + for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) + { + st = m_pFormatContext->streams[i]; -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && -+ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) -+ return false; ++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ++ { ++ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE) ++ return true; ++ hasVideo = true; ++ } ++ } ++ } ++ return !hasVideo; ++} ++ ++void CDVDDemuxFFmpeg::ResetVideoStreams() ++{ ++ AVStream *st; ++ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) ++ { ++ st = m_pFormatContext->streams[i]; ++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ++ { ++ if (st->codec->extradata) ++ av_free(st->codec->extradata); ++ st->codec->extradata = NULL; ++ st->codec->width = 0; + } + } -+ return true; +} diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -index 3b0f615..083182e 100644 +index 980d01e..3f97392 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -@@ -88,7 +88,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux +@@ -89,7 +89,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux CDVDDemuxFFmpeg(); virtual ~CDVDDemuxFFmpeg(); @@ -1857,20 +1871,22 @@ index 3b0f615..083182e 100644 void Dispose(); void Reset(); void Flush(); -@@ -127,6 +127,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux +@@ -128,6 +128,9 @@ class CDVDDemuxFFmpeg : public CDVDDemux CDemuxStream* GetStreamInternal(int iStreamId); void CreateStreams(unsigned int program = UINT_MAX); void DisposeStreams(); + void ParsePacket(AVPacket *pkt); + bool IsVideoReady(); ++ void ResetVideoStreams(); AVDictionary *GetFFMpegOptionsFromURL(const CURL &url); double ConvertTimestamp(int64_t pts, int den, int num); -@@ -157,5 +159,6 @@ class CDVDDemuxFFmpeg : public CDVDDemux +@@ -158,5 +161,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux bool m_bPtsWrap, m_bPtsWrapChecked; int64_t m_iStartTime, m_iMaxTime, m_iEndTime; + bool m_streaminfo; ++ bool m_checkvideo; }; diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp @@ -1925,97 +1941,10 @@ index ca689d0..f383563 100644 1.9.3 -From cffbdb13512718b083e6e49d7625efefcff1dc7c Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Thu, 14 Nov 2013 20:35:04 +0100 -Subject: [PATCH 25/35] ffmpeg demuxer: make sure we start mpegts video with an - i-frame - ---- - .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 31 +++++++++++++++++++++- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 1 + - 2 files changed, 31 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 4d4be02..56eaccc 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -386,6 +386,13 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo) - if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) - m_pFormatContext->max_analyze_duration = 500000; - -+ bool short_analyze = false; -+ if (iformat && (strcmp(iformat->name, "mpegts") == 0)) -+ { -+ m_pFormatContext->max_analyze_duration = 500000; -+ short_analyze = true; -+ } -+ - // we need to know if this is matroska or avi later - m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" - m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; -@@ -414,6 +421,12 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo) - } - } - CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__); -+ -+ if (short_analyze) -+ { -+ // make sure we start video with an i-frame -+ ResetVideoStreams(); -+ } - } - else - m_program = 0; -@@ -1670,7 +1683,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt) - } - - // for video we need a decoder to get desired information into codec context -- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec->extradata && - (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) - { - // open a decoder, it will be cleared down by ffmpeg on closing the stream -@@ -1732,3 +1745,19 @@ bool CDVDDemuxFFmpeg::IsVideoReady() - } - return true; - } -+ -+void CDVDDemuxFFmpeg::ResetVideoStreams() -+{ -+ AVStream *st; -+ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) -+ { -+ st = m_pFormatContext->streams[i]; -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -+ { -+ if (st->codec->extradata) -+ m_dllAvUtil.av_free(st->codec->extradata); -+ st->codec->extradata = NULL; -+ st->codec->width = 0; -+ } -+ } -+} -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -index 083182e..26ee264 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -@@ -129,6 +129,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux - void DisposeStreams(); - void ParsePacket(AVPacket *pkt); - bool IsVideoReady(); -+ void ResetVideoStreams(); - - AVDictionary *GetFFMpegOptionsFromURL(const CURL &url); - double ConvertTimestamp(int64_t pts, int den, int num); --- -1.9.3 - - -From 6db875e37a4c23952ed114482ab4ec1e57941ba5 Mon Sep 17 00:00:00 2001 +From 8e115633a5cf586a20ad64e1751d63a35d496bf4 Mon Sep 17 00:00:00 2001 From: Wolfgang Haupt Date: Thu, 5 Dec 2013 22:11:57 +0100 -Subject: [PATCH 26/35] DVDFactoryDemuxer: skip streaminfo for udp tcp and +Subject: [PATCH 16/22] DVDFactoryDemuxer: skip streaminfo for udp tcp and pvr-channels --- @@ -2064,11 +1993,11 @@ index f383563..d6580fd 100644 if(demuxer->Open(pInputStream, streaminfo)) return demuxer.release(); diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp -index fd2eb5a..22932b7 100644 +index 8278867..8040591 100644 --- a/xbmc/utils/URIUtils.cpp +++ b/xbmc/utils/URIUtils.cpp -@@ -788,6 +788,36 @@ bool URIUtils::IsFTP(const CStdString& strFile) - StringUtils::StartsWithNoCase(strFile2, "ftps:"); +@@ -814,6 +814,36 @@ bool URIUtils::IsFTP(const CStdString& strFile) + IsProtocol(strFile2, "ftps"); } +bool URIUtils::IsUDP(const CStdString& strFile) @@ -2104,7 +2033,7 @@ index fd2eb5a..22932b7 100644 bool URIUtils::IsDAV(const CStdString& strFile) { CStdString strFile2(strFile); -@@ -1284,3 +1314,8 @@ bool URIUtils::UpdateUrlEncoding(std::string &strFilename) +@@ -1296,3 +1326,8 @@ bool URIUtils::UpdateUrlEncoding(std::string &strFilename) strFilename = newFilename; return true; } @@ -2114,10 +2043,10 @@ index fd2eb5a..22932b7 100644 + return IsUDP(strFile) || IsTCP(strFile) || IsPVRChannel(strFile); +} diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h -index b94e94c..b45630f 100644 +index 667f6d3..0094709 100644 --- a/xbmc/utils/URIUtils.h +++ b/xbmc/utils/URIUtils.h -@@ -88,6 +88,8 @@ class URIUtils +@@ -119,6 +119,8 @@ class URIUtils static bool IsDOSPath(const CStdString &path); static bool IsDVD(const CStdString& strFile); static bool IsFTP(const CStdString& strFile); @@ -2126,7 +2055,7 @@ index b94e94c..b45630f 100644 static bool IsHD(const CStdString& strFileName); static bool IsHDHomeRun(const CStdString& strFile); static bool IsSlingbox(const CStdString& strFile); -@@ -127,6 +129,8 @@ class URIUtils +@@ -159,6 +161,8 @@ class URIUtils static bool IsAndroidApp(const CStdString& strFile); static bool IsLibraryFolder(const CStdString& strFile); static bool IsLibraryContent(const std::string& strFile); @@ -2139,159 +2068,10 @@ index b94e94c..b45630f 100644 1.9.3 -From 9ab279173cd4b4b750028f2ef3f4bd1a61a38bf5 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Tue, 28 Jan 2014 08:43:29 +0100 -Subject: [PATCH 27/35] squash fast switch - ---- - .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 23 ++++++++++++++-------- - 1 file changed, 15 insertions(+), 8 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 56eaccc..d0f13a1 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -1722,15 +1722,19 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt) - bool CDVDDemuxFFmpeg::IsVideoReady() - { - AVStream *st; -+ bool hasVideo = false; - if(m_program != UINT_MAX) - { - for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) - { - int idx = m_pFormatContext->programs[m_program]->stream_index[i]; - st = m_pFormatContext->streams[idx]; -- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && -- (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) -- return false; -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -+ { -+ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE) -+ return true; -+ hasVideo = true; -+ } - } - } - else -@@ -1738,12 +1742,15 @@ bool CDVDDemuxFFmpeg::IsVideoReady() - for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) - { - st = m_pFormatContext->streams[i]; -- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && -- (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE)) -- return false; -+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -+ { -+ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE) -+ return true; -+ hasVideo = true; -+ } - } - } -- return true; -+ return !hasVideo; - } - - void CDVDDemuxFFmpeg::ResetVideoStreams() -@@ -1755,7 +1762,7 @@ void CDVDDemuxFFmpeg::ResetVideoStreams() - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) - { - if (st->codec->extradata) -- m_dllAvUtil.av_free(st->codec->extradata); -+ av_free(st->codec->extradata); - st->codec->extradata = NULL; - st->codec->width = 0; - } --- -1.9.3 - - -From 08634b062976edb8f7740b364e66017a1870756d Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Sun, 13 Apr 2014 10:52:26 +0200 -Subject: [PATCH 28/35] squash fast channel - ---- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 13 ++++++++++--- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 1 + - 2 files changed, 11 insertions(+), 3 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index d0f13a1..1aeae2b 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -156,6 +156,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() - m_pkt.result = -1; - memset(&m_pkt.pkt, 0, sizeof(AVPacket)); - m_streaminfo = true; /* set to true if we want to look for streams before playback */ -+ m_checkvideo = false; - } - - CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg() -@@ -386,11 +387,10 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo) - if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) - m_pFormatContext->max_analyze_duration = 500000; - -- bool short_analyze = false; - if (iformat && (strcmp(iformat->name, "mpegts") == 0)) - { - m_pFormatContext->max_analyze_duration = 500000; -- short_analyze = true; -+ m_checkvideo = true; - } - - // we need to know if this is matroska or avi later -@@ -422,14 +422,17 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo) - } - CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__); - -- if (short_analyze) -+ if (m_checkvideo) - { - // make sure we start video with an i-frame - ResetVideoStreams(); - } - } - else -+ { - m_program = 0; -+ m_checkvideo = true; -+ } - - // reset any timeout - m_timeout.SetInfinite(); -@@ -1723,6 +1726,10 @@ bool CDVDDemuxFFmpeg::IsVideoReady() - { - AVStream *st; - bool hasVideo = false; -+ -+ if(!m_checkvideo) -+ return true; -+ - if(m_program != UINT_MAX) - { - for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++) -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -index 26ee264..322a3b8 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -@@ -161,5 +161,6 @@ class CDVDDemuxFFmpeg : public CDVDDemux - bool m_bPtsWrap, m_bPtsWrapChecked; - int64_t m_iStartTime, m_iMaxTime, m_iEndTime; - bool m_streaminfo; -+ bool m_checkvideo; - }; - --- -1.9.3 - - -From 7110f52260049d39134a6d5e102b67803994371d Mon Sep 17 00:00:00 2001 +From 93945087cddece4748c01f9ad7ce97da02259f42 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 22 Dec 2013 14:52:29 +0100 -Subject: [PATCH 29/35] linux: add shared lib for sse4 operations +Subject: [PATCH 17/22] linux: add shared lib for sse4 operations --- Makefile.in | 8 ++- @@ -2306,10 +2086,10 @@ Subject: [PATCH 29/35] linux: add shared lib for sse4 operations create mode 100644 xbmc/linux/sse4/Makefile.in diff --git a/Makefile.in b/Makefile.in -index 8642922..0988e60 100644 +index a8024e2..1bbac63 100644 --- a/Makefile.in +++ b/Makefile.in -@@ -314,6 +314,12 @@ CHECK_LIBADD=@WAYLAND_TEST_LIBS@ +@@ -316,6 +316,12 @@ CHECK_LIBADD=@WAYLAND_TEST_LIBS@ endif endif @@ -2322,7 +2102,7 @@ index 8642922..0988e60 100644 CHECK_PROGRAMS = xbmc-test CLEAN_FILES += $(CHECK_PROGRAMS) $(CHECK_EXTENSIONS) -@@ -441,7 +447,7 @@ endif +@@ -443,7 +449,7 @@ endif codecs: papcodecs dvdpcodecs dvdpextcodecs @@ -2332,10 +2112,10 @@ index 8642922..0988e60 100644 externals: codecs libs visualizations screensavers libaddon pvraddons diff --git a/configure.in b/configure.in -index 1766ce1..abbfcdf 100644 +index efd0574..81c5ca5 100644 --- a/configure.in +++ b/configure.in -@@ -832,6 +832,19 @@ elif test "$use_arch" = "arm"; then +@@ -853,6 +853,19 @@ elif test "$use_arch" = "arm"; then fi fi @@ -2355,7 +2135,7 @@ index 1766ce1..abbfcdf 100644 # Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_CHOWN -@@ -2583,6 +2596,10 @@ if test "$use_codec_libstagefright" = "yes"; then +@@ -2608,6 +2621,10 @@ if test "$use_codec_libstagefright" = "yes"; then OUTPUT_FILES="$OUTPUT_FILES xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile" fi @@ -2366,7 +2146,7 @@ index 1766ce1..abbfcdf 100644 OUTPUT_FILES="$OUTPUT_FILES \ xbmc/interfaces/python/Makefile \ xbmc/interfaces/python/test/Makefile" -@@ -2661,6 +2678,7 @@ AC_SUBST(GTEST_CONFIGURED) +@@ -2686,6 +2703,7 @@ AC_SUBST(GTEST_CONFIGURED) AC_SUBST(USE_DOXYGEN) AC_SUBST(USE_PVR_ADDONS) AC_SUBST(UPNP_DEFINES) @@ -2586,675 +2366,20 @@ index 0000000..45aa826 1.9.3 -From 1cb3a7dbbf78eb6c7967700fc33806e33265ff6f Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Thu, 19 Dec 2013 15:36:11 +0100 -Subject: [PATCH 30/35] vaapi: option to enable sw filters - ---- - language/English/strings.po | 17 ++- - system/settings/settings.xml | 15 ++ - xbmc/cores/VideoRenderers/RenderManager.cpp | 4 +- - xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp | 1 + - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 2 + - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 71 ++++++++-- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 4 + - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 152 +++++++++++++++++++++ - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 31 +++++ - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 30 ++-- - 10 files changed, 290 insertions(+), 37 deletions(-) - -diff --git a/language/English/strings.po b/language/English/strings.po -index fb26ead..c6822b1 100755 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -6162,7 +6162,13 @@ msgctxt "#13456" - msgid "Hardware accelerated" - msgstr "" - --#empty strings from id 13457 to 13499 -+#. Option for video related setting #13454: sw filter -+#: system/settings/settings.xml -+msgctxt "#13457" -+msgid "Use SW Filter for VAAPI" -+msgstr "" -+ -+#empty strings from id 13458 to 13499 - - #: system/settings/settings.xml - msgctxt "#13500" -@@ -15279,7 +15285,14 @@ msgctxt "#36431" - msgid "Defines whether video decoding should be performed in software (requires more CPU) or with hardware acceleration where possible." - msgstr "" - --#empty strings from id 36432 to 36499 -+#. Description for video related setting #13457: vaapi sw filter -+#: system/settings/settings.xml -+msgctxt "#36432" -+msgid "This option enables the deinterlacing methods available for software decoding. It gives the possiblity to use high quality deinterlacers in combination with VAAPI." -+msgstr "" -+ -+#empty strings from id 36433 to 36499 -+ - #end reservation - - #: system/settings/settings.xml -diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index 391bcee..c0f64ab 100644 ---- a/system/settings/settings.xml -+++ b/system/settings/settings.xml -@@ -715,6 +715,21 @@ - false - - -+ -+ HAVE_LIBVA -+ -+ -+ -+ true -+ 1 -+ -+ -+ true -+ -+ 3 -+ false -+ -+ - - HasDXVA2 - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 5e9f666..32ce5bb 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -988,10 +988,10 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO - if (mInt == VS_INTERLACEMETHOD_NONE) - return VS_INTERLACEMETHOD_NONE; - -- if(!m_pRenderer->Supports(mInt)) -+ if(m_pRenderer && !m_pRenderer->Supports(mInt)) - mInt = VS_INTERLACEMETHOD_AUTO; - -- if (mInt == VS_INTERLACEMETHOD_AUTO) -+ if (m_pRenderer && mInt == VS_INTERLACEMETHOD_AUTO) - return m_pRenderer->AutoInterlaceMethod(); - - return mInt; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp -index 2958d43..06e0010 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp -@@ -464,6 +464,7 @@ static const EFormatMap g_format_map[] = { - , { PIX_FMT_YUV420P16, RENDER_FMT_YUV420P16 } - , { PIX_FMT_UYVY422, RENDER_FMT_UYVY422 } - , { PIX_FMT_YUYV422, RENDER_FMT_YUYV422 } -+, { PIX_FMT_NV12, RENDER_FMT_NV12 } - , { PIX_FMT_VAAPI_VLD, RENDER_FMT_VAAPI } - , { PIX_FMT_DXVA2_VLD, RENDER_FMT_DXVA } - , { PIX_FMT_NONE , RENDER_FMT_NONE } -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index c5b24d6..3efc007 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -323,4 +323,6 @@ class CDVDVideoCodec - * - */ - virtual void SetCodecControl(int flags) {} -+ -+ virtual bool IsInterlaced() { return false; } - }; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index c48108f..3b70aa0 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -38,6 +38,7 @@ - #include "utils/log.h" - #include "boost/shared_ptr.hpp" - #include "threads/Atomics.h" -+#include "settings/MediaSettings.h" - - #ifndef TARGET_POSIX - #define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5))) -@@ -168,6 +169,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec() - m_dts = DVD_NOPTS_VALUE; - m_started = false; - m_decoderPts = DVD_NOPTS_VALUE; -+ m_interlace = false; - } - - CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() -@@ -375,7 +377,7 @@ unsigned int CDVDVideoCodecFFmpeg::SetFilters(unsigned int flags) - { - m_filters_next.clear(); - -- if(m_pHardware) -+ if(m_pHardware && !m_pHardware->UseFilter()) - return 0; - - if(flags & FILTER_ROTATE) -@@ -449,10 +451,10 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p - if(section) - lock = shared_ptr(new CSingleLock(*section)); - -- int result; -+ int result = 0; - if(pData) - result = m_pHardware->Check(m_pCodecContext); -- else -+ else if (!m_pHardware->UseFilter()) - result = m_pHardware->Decode(m_pCodecContext, NULL); - - if(result) -@@ -507,19 +509,60 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p - || m_pCodecContext->codec_id == AV_CODEC_ID_SVQ3) - m_started = true; - -- if(m_pHardware == NULL) -+ m_interlace = m_pFrame->interlaced_frame; -+ -+ if(m_pHardware == NULL || m_pHardware->UseFilter()) - { -+ if (m_pHardware) -+ { -+ m_pFrame->pkt_dts = pts_dtoi(m_dts); -+ int result = m_pHardware->Decode(m_pCodecContext, m_pFrame); -+ if (result == VC_BUFFER || result == VC_ERROR) -+ return result; -+ m_pHardware->MapFrame(m_pCodecContext, m_pFrame); -+ m_dts = pts_itod(m_pFrame->pkt_dts); -+ m_pFrame->pkt_dts = 0; -+ } -+ - bool need_scale = std::find( m_formats.begin() - , m_formats.end() -- , m_pCodecContext->pix_fmt) == m_formats.end(); -+ , m_pFrame->format) == m_formats.end(); - - bool need_reopen = false; -+ -+ -+ // ask codec to do deinterlacing if possible -+ EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); -+ -+ unsigned int mFilters = 0; -+ -+ if (mDeintMode != VS_DEINTERLACEMODE_OFF) -+ { -+ if (mDeintMode == VS_DEINTERLACEMODE_FORCE || -+ m_pFrame->interlaced_frame) -+ { -+ if (mInt == VS_INTERLACEMETHOD_DEINTERLACE) -+ mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY; -+ else if(mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF) -+ mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY | CDVDVideoCodec::FILTER_DEINTERLACE_HALFED; -+ -+ if (mDeintMode == VS_DEINTERLACEMODE_AUTO && mFilters) -+ mFilters |= CDVDVideoCodec::FILTER_DEINTERLACE_FLAGGED; -+ } -+ } -+ -+ if (!g_renderManager.Supports(RENDERFEATURE_ROTATION)) -+ mFilters |= CDVDVideoCodec::FILTER_ROTATE; -+ -+ SetFilters(mFilters); -+ - if(!m_filters.Equals(m_filters_next)) - need_reopen = true; - - if(m_pFilterIn) - { -- if(m_pFilterIn->outputs[0]->format != m_pCodecContext->pix_fmt -+ if(m_pFilterIn->outputs[0]->format != m_pFrame->format - || m_pFilterIn->outputs[0]->w != m_pCodecContext->width - || m_pFilterIn->outputs[0]->h != m_pCodecContext->height) - need_reopen = true; -@@ -536,7 +579,7 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p - } - - int result; -- if(m_pHardware) -+ if(m_pHardware && !m_pHardware->UseFilter()) - result = m_pHardware->Decode(m_pCodecContext, m_pFrame); - else if(m_pFilterGraph) - result = FilterProcess(m_pFrame); -@@ -620,6 +663,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - pDvdVideoPicture->chroma_position = m_pCodecContext->chroma_sample_location; - pDvdVideoPicture->color_primaries = m_pCodecContext->color_primaries; - pDvdVideoPicture->color_transfer = m_pCodecContext->color_trc; -+ pDvdVideoPicture->color_matrix = m_pCodecContext->colorspace; - if(m_pCodecContext->color_range == AVCOL_RANGE_JPEG - || m_pCodecContext->pix_fmt == PIX_FMT_YUVJ420P) - pDvdVideoPicture->color_range = 1; -@@ -643,7 +687,11 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - pDvdVideoPicture->qscale_type = DVP_QSCALE_UNKNOWN; - } - -- pDvdVideoPicture->dts = m_dts; -+ if (pDvdVideoPicture->iRepeatPicture) -+ pDvdVideoPicture->dts = DVD_NOPTS_VALUE; -+ else -+ pDvdVideoPicture->dts = m_dts; -+ - m_dts = DVD_NOPTS_VALUE; - if (m_pFrame->reordered_opaque) - pDvdVideoPicture->pts = pts_itod(m_pFrame->reordered_opaque); -@@ -674,7 +722,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - - bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) - { -- if(m_pHardware) -+ if(m_pHardware && !m_pHardware->UseFilter()) - return m_pHardware->GetPicture(m_pCodecContext, m_pFrame, pDvdVideoPicture); - - if(!GetPictureCommon(pDvdVideoPicture)) -@@ -694,6 +742,7 @@ bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) - pix_fmt = (PixelFormat)m_pFrame->format; - - pDvdVideoPicture->format = CDVDCodecUtils::EFormatFromPixfmt(pix_fmt); -+ - return true; - } - -@@ -707,7 +756,7 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const CStdString& filters, bool scale) - if (filters.empty() && !scale) - return 0; - -- if (m_pHardware) -+ if (m_pHardware && !m_pHardware->UseFilter()) - { - CLog::Log(LOGWARNING, "CDVDVideoCodecFFmpeg::FilterOpen - skipped opening filters on hardware decode"); - return 0; -@@ -725,7 +774,7 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const CStdString& filters, bool scale) - CStdString args = StringUtils::Format("%d:%d:%d:%d:%d:%d:%d", - m_pCodecContext->width, - m_pCodecContext->height, -- m_pCodecContext->pix_fmt, -+ m_pFrame->format, - m_pCodecContext->time_base.num, - m_pCodecContext->time_base.den, - m_pCodecContext->sample_aspect_ratio.num, -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 1a80a48..25f1d25 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -53,6 +53,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - virtual bool CanSkipDeint() {return false; } - virtual const std::string Name() = 0; - virtual CCriticalSection* Section() { return NULL; } -+ virtual bool UseFilter() { return false; } -+ virtual bool MapFrame(AVCodecContext* avctx, AVFrame* frame) { return false; } - }; - - CDVDVideoCodecFFmpeg(); -@@ -70,6 +72,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - virtual unsigned GetAllowedReferences(); - virtual bool GetCodecStats(double &pts, int &droppedPics); - virtual void SetCodecControl(int flags); -+ virtual bool IsInterlaced() { return m_interlace; } - - bool IsHardwareAllowed() { return !m_bSoftware; } - IHardwareDecoder * GetHardware() { return m_pHardware; }; -@@ -129,4 +132,5 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - int m_skippedDeint; - bool m_requestSkipDeint; - int m_codecControlFlags; -+ bool m_interlace; - }; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -index 386d50a..315f3ca 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -@@ -26,6 +26,15 @@ - #include - #include "utils/log.h" - #include "threads/SingleLock.h" -+#include "XMemUtils.h" -+#include "utils/CPUInfo.h" -+#include "settings/Settings.h" -+ -+extern "C" { -+#include "libavutil/avutil.h" -+} -+ -+#define CACHED_BUFFER_SIZE 4096 - - #define CHECK(a) \ - do { \ -@@ -168,12 +177,17 @@ CDecoder::CDecoder() - m_context = 0; - m_hwaccel = (vaapi_context*)calloc(1, sizeof(vaapi_context)); - memset(m_surfaces, 0, sizeof(*m_surfaces)); -+ m_frame_buffer = NULL; -+ m_cache = NULL; - } - - CDecoder::~CDecoder() - { - Close(); - free(m_hwaccel); -+ _aligned_free(m_frame_buffer); -+ _aligned_free(m_cache); -+ m_dllSSE4.Unload(); - } - - void CDecoder::RelBuffer(uint8_t *data) -@@ -393,6 +407,11 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su - if (!EnsureContext(avctx)) - return false; - -+ if (avctx->width <= 1920 && avctx->height <= 1088) -+ CheckUseFilter(); -+ else -+ m_use_filter = false; -+ - m_hwaccel->display = m_display->get(); - - avctx->hwaccel_context = m_hwaccel; -@@ -475,7 +494,35 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) - return status; - - if(frame) -+ { -+ if (m_use_filter) -+ { -+ VASurfaceID surface = GetSurfaceID(frame); -+ std::list::iterator it; -+ for(it = m_surfaces_used.begin(); it != m_surfaces_used.end(); ++it) -+ { -+ if((*it)->m_id == surface) -+ { -+ m_holder.surface = *it; -+ break; -+ } -+ } -+ if (it == m_surfaces_used.end()) -+ { -+ CLog::Log(LOGERROR, "VAAPI::Decode - surface not found"); -+ return VC_ERROR; -+ } -+ CProcPic pic; -+ memset(&pic.frame, 0, sizeof(AVFrame)); -+ av_frame_ref(&pic.frame, frame); -+ pic.surface = *it; -+ m_surfaces_proc.push_back(pic); -+ if (m_surfaces_proc.size() < m_renderbuffers_count) -+ return VC_BUFFER; -+ } -+ - return VC_BUFFER | VC_PICTURE; -+ } - else - return VC_BUFFER; - } -@@ -553,4 +600,109 @@ unsigned CDecoder::GetAllowedReferences() - return m_renderbuffers_count; - } - -+void CDecoder::Reset() -+{ -+ m_surfaces_proc.clear(); -+} -+ -+void CDecoder::CheckUseFilter() -+{ -+ m_use_filter = true; -+ _aligned_free(m_frame_buffer); -+ _aligned_free(m_cache); -+ if (CSettings::Get().GetBool("videoplayer.usevaapiswfilter")) -+ { -+ if (!(g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_SSE4)) -+ { -+ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter cpu does not support SSE4"); -+ m_use_filter = false; -+ return; -+ } -+ if (!m_dllSSE4.Load()) -+ { -+ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter failed loading sse4 lib"); -+ m_use_filter = false; -+ return; -+ } -+ VAImage image; -+ VASurfaceID surface = m_surfaces_free.front()->m_id; -+ VAStatus status = vaDeriveImage(m_display->get(), surface, &image); -+ m_use_filter = true; -+ if (status != VA_STATUS_SUCCESS) -+ { -+ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter vaDeriveImage not supported"); -+ m_use_filter = false; -+ } -+ if (image.format.fourcc != VA_FOURCC_NV12) -+ { -+ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter image format not NV12"); -+ m_use_filter = false; -+ } -+ if ((image.pitches[0] % 64) || (image.pitches[1] % 64)) -+ { -+ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter patches no multiple of 64"); -+ m_use_filter = false; -+ } -+ if (m_use_filter) -+ { -+ m_frame_buffer = (uint8_t*)_aligned_malloc(image.height*image.width*2 + 256, 64); -+ m_cache = (uint8_t*)_aligned_malloc(CACHED_BUFFER_SIZE, 64); -+ } -+ vaDestroyImage(m_display->get(),image.image_id); -+ } -+ else -+ { -+ m_use_filter = false; -+ } -+} -+ -+bool CDecoder::MapFrame(AVCodecContext* avctx, AVFrame* frame) -+{ -+ if (m_surfaces_proc.empty()) -+ { -+ return false; -+ } -+ if(frame) -+ { -+ CProcPic pic = m_surfaces_proc.front(); -+ m_surfaces_proc.pop_front(); -+ VASurfaceID surface = pic.surface->m_id; -+ VASurfaceStatus surf_status; -+ VAImage image; -+ uint8_t *buf; -+ CHECK(vaQuerySurfaceStatus(m_display->get(), surface, &surf_status)) -+ while (surf_status != VASurfaceReady) -+ { -+ Sleep(1); -+ CHECK(vaQuerySurfaceStatus(m_display->get(), surface, &surf_status)) -+ } -+ CHECK(vaDeriveImage(m_display->get(), surface, &image)); -+ CHECK(vaMapBuffer(m_display->get(), image.buf, (void**)&buf)) -+ -+ uint8_t *src, *dst; -+ src = buf + image.offsets[0]; -+ dst = m_frame_buffer + image.offsets[0]; -+ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height, image.pitches[0]); -+ src = buf + image.offsets[1]; -+ dst = m_frame_buffer + image.offsets[1]; -+ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height/2, image.pitches[1]); -+ -+ av_frame_unref(frame); -+ av_frame_move_ref(frame, &pic.frame); -+ -+ frame->format = AV_PIX_FMT_NV12; -+ frame->data[0] = m_frame_buffer + image.offsets[0]; -+ frame->linesize[0] = image.pitches[0]; -+ frame->data[1] = m_frame_buffer + image.offsets[1]; -+ frame->linesize[1] = image.pitches[1]; -+ frame->data[2] = NULL; -+ frame->data[3] = NULL; -+ frame->pkt_size = image.data_size; -+ -+ CHECK(vaUnmapBuffer(m_display->get(), image.buf)) -+ CHECK(vaDestroyImage(m_display->get(),image.image_id)) -+ } -+ return true; -+} -+ - #endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -index ec99162..616b124 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -@@ -27,9 +27,11 @@ - #include - #include - #include -+#include "linux/sse4/DllLibSSE4.h" - - extern "C" { - #include "libavcodec/vaapi.h" -+#include "libavcodec/avcodec.h" - } - - namespace VAAPI { -@@ -102,11 +104,31 @@ struct CHolder - {} - }; - -+struct CProcPic -+{ -+ AVFrame frame; -+ CSurfacePtr surface; -+ CProcPic() -+ {} -+ CProcPic(const CProcPic &other) -+ { -+ memcpy(&this->frame, &other.frame, sizeof(AVFrame)); -+ surface = other.surface; -+ } -+ CProcPic & operator= (const CProcPic &other) -+ { -+ memcpy(&this->frame, &other.frame, sizeof(AVFrame)); -+ surface = other.surface; -+ return *this; -+ } -+}; -+ - class CDecoder - : public CDVDVideoCodecFFmpeg::IHardwareDecoder - { - bool EnsureContext(AVCodecContext *avctx); - bool EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count); -+ void CheckUseFilter(); - public: - CDecoder(); - ~CDecoder(); -@@ -115,9 +137,12 @@ class CDecoder - virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); - virtual int Check (AVCodecContext* avctx); - virtual void Close(); -+ virtual void Reset(); - 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 UseFilter() { return m_use_filter; } -+ virtual bool MapFrame(AVCodecContext* avctx, AVFrame* frame); - - int GetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags); - void RelBuffer(uint8_t *data); -@@ -133,14 +158,20 @@ class CDecoder - int m_refs; - std::list m_surfaces_used; - std::list m_surfaces_free; -+ std::list m_surfaces_proc; - - CDisplayPtr m_display; - VAConfigID m_config; - VAContextID m_context; -+ bool m_use_filter; -+ uint8_t *m_frame_buffer; -+ uint8_t *m_cache; - - vaapi_context *m_hwaccel; - - CHolder m_holder; // silly struct to pass data to renderer -+ -+ DllLibSSE4 m_dllSSE4; - }; - - } -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 3eb6315..e17c712 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -554,28 +554,6 @@ void CDVDPlayerVideo::Process() - // decoder still needs to provide an empty image structure, with correct flags - m_pVideoCodec->SetDropState(bRequestDrop); - -- // ask codec to do deinterlacing if possible -- EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -- EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); -- -- unsigned int mFilters = 0; -- -- if (mDeintMode != VS_DEINTERLACEMODE_OFF) -- { -- if (mInt == VS_INTERLACEMETHOD_DEINTERLACE) -- mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY; -- else if(mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF) -- mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY | CDVDVideoCodec::FILTER_DEINTERLACE_HALFED; -- -- if (mDeintMode == VS_DEINTERLACEMODE_AUTO && mFilters) -- mFilters |= CDVDVideoCodec::FILTER_DEINTERLACE_FLAGGED; -- } -- -- if (!g_renderManager.Supports(RENDERFEATURE_ROTATION)) -- mFilters |= CDVDVideoCodec::FILTER_ROTATE; -- -- mFilters = m_pVideoCodec->SetFilters(mFilters); -- - int iDecoderState = m_pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); - - // buffer packets so we can recover should decoder flush for some reason -@@ -662,6 +640,8 @@ void CDVDPlayerVideo::Process() - - //Deinterlace if codec said format was interlaced or if we have selected we want to deinterlace - //this video -+ EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); - if ((mDeintMode == VS_DEINTERLACEMODE_AUTO && (picture.iFlags & DVP_FLAG_INTERLACED)) || mDeintMode == VS_DEINTERLACEMODE_FORCE) - { - if(mInt == VS_INTERLACEMETHOD_SW_BLEND) -@@ -704,7 +684,13 @@ void CDVDPlayerVideo::Process() - } - - if (picture.iRepeatPicture) -+ { -+ bool deint = m_pVideoCodec->IsInterlaced(); -+ picture.iDuration = frametime; -+ if (deint && (frametime <= 0.02*DVD_TIME_BASE)) -+ picture.iDuration *= 2; - picture.iDuration *= picture.iRepeatPicture + 1; -+ } - - int iResult = OutputPicture(&picture, pts); - --- -1.9.3 - - -From 9cca95f06d9c4416b6d6aa99c4be3edf049bb16d Mon Sep 17 00:00:00 2001 +From 4d30dfcf8491331e8a9fdff99677511625bcf30a Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Tue, 28 Jan 2014 10:05:26 +0100 -Subject: [PATCH 31/35] xbmc pr 3080 +Subject: [PATCH 18/22] xbmc pr 3080 --- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 8 ++++++++ + 1 file changed, 8 insertions(+) diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 3b70aa0..80915d4 100644 +index c48108f..0bbca2a 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -477,6 +477,14 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p +@@ -475,6 +475,14 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p av_init_packet(&avpkt); avpkt.data = pData; avpkt.size = iSize; @@ -3269,67 +2394,21 @@ index 3b70aa0..80915d4 100644 /* We lie, but this flag is only used by pngdec.c. * Setting it correctly would allow CorePNG decoding. */ avpkt.flags = AV_PKT_FLAG_KEY; -@@ -693,8 +701,10 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - pDvdVideoPicture->dts = m_dts; - - m_dts = DVD_NOPTS_VALUE; -- if (m_pFrame->reordered_opaque) -- pDvdVideoPicture->pts = pts_itod(m_pFrame->reordered_opaque); -+ -+ int64_t bpts = av_frame_get_best_effort_timestamp(m_pFrame); -+ if(bpts != AV_NOPTS_VALUE) -+ pDvdVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE; - else - pDvdVideoPicture->pts = DVD_NOPTS_VALUE; - -- 1.9.3 -From c72261a920896f3df7bd50464f696e4d2e74d850 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Tue, 28 Jan 2014 17:24:58 +0100 -Subject: [PATCH 32/35] set preatpicture if pts is equal to last frame - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 80915d4..ab36704 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -704,7 +704,15 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - - int64_t bpts = av_frame_get_best_effort_timestamp(m_pFrame); - if(bpts != AV_NOPTS_VALUE) -+ { - pDvdVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE; -+ if (pDvdVideoPicture->pts == m_decoderPts) -+ { -+ pDvdVideoPicture->iRepeatPicture = -0.5; -+ pDvdVideoPicture->pts = DVD_NOPTS_VALUE; -+ pDvdVideoPicture->dts = DVD_NOPTS_VALUE; -+ } -+ } - else - pDvdVideoPicture->pts = DVD_NOPTS_VALUE; - --- -1.9.3 - - -From d8f5bf2f3100616d3c47c4e17c8598318d9cb501 Mon Sep 17 00:00:00 2001 +From 10b293f04bb90ae8cadc75b11cd7dc3f7aa1f6e8 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Tue, 11 Feb 2014 18:15:06 +0100 -Subject: [PATCH 33/35] ActiveAE: add some debug logging +Subject: [PATCH 19/22] ActiveAE: add some debug logging --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -index ce67a31..58c8776 100644 +index c61e9175..99c2faf 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp @@ -263,7 +263,13 @@ unsigned int CActiveAEStream::AddData(uint8_t* const *data, unsigned int offset, @@ -3350,71 +2429,4850 @@ index ce67a31..58c8776 100644 1.9.3 -From a9d54ec6a768420d9582784bfeb39e72c1e9f774 Mon Sep 17 00:00:00 2001 +From cdfe2b5fd66d09e83e2abf00885627bac8bf3744 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker -Date: Sun, 25 May 2014 21:25:31 +0200 -Subject: [PATCH 34/35] squash swfilter +Date: Fri, 13 Jun 2014 14:37:16 +0200 +Subject: [PATCH 20/22] vaapi - postprocessing --- - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 2 ++ - 1 file changed, 2 insertions(+) + configure.in | 16 +- + language/English/strings.po | 34 +- + system/settings/settings.xml | 15 + + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 262 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 9 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 15 +- + .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 5 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 21 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 3212 +++++++++++++++++--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 539 +++- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + + xbmc/settings/VideoSettings.h | 4 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 3 + + 15 files changed, 3466 insertions(+), 675 deletions(-) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -index 315f3ca..4452cfb 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -@@ -519,6 +519,8 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) - m_surfaces_proc.push_back(pic); - if (m_surfaces_proc.size() < m_renderbuffers_count) - return VC_BUFFER; -+ -+ return VC_PICTURE; - } - - return VC_BUFFER | VC_PICTURE; --- -1.9.3 - - -From d69f623bea5e2b08ff0ad02fe573188842258164 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Mon, 26 May 2014 08:07:39 +0200 -Subject: [PATCH 35/35] swfilter, squash me too - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -index 4452cfb..befb6d6 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -@@ -517,7 +517,7 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) - av_frame_ref(&pic.frame, frame); - pic.surface = *it; - m_surfaces_proc.push_back(pic); -- if (m_surfaces_proc.size() < m_renderbuffers_count) -+ if (m_surfaces_proc.size() < m_renderbuffers_count + 1) - return VC_BUFFER; - - return VC_PICTURE; -@@ -526,7 +526,15 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) - return VC_BUFFER | VC_PICTURE; - } +diff --git a/configure.in b/configure.in +index 81c5ca5..e39c863 100644 +--- a/configure.in ++++ b/configure.in +@@ -1901,21 +1901,15 @@ if test "x$use_vaapi" != "xno"; then + USE_VAAPI=0 else -- return VC_BUFFER; -+ { -+ if (m_use_filter) -+ { -+ if (m_surfaces_proc.size() < m_renderbuffers_count + 1) -+ return VC_BUFFER; -+ } + initial_val=$use_vaapi +- AC_CHECK_LIB([va], main, :, use_vaapi=no) + if test "x$use_vaapi" != "xno"; then +- AC_CHECK_LIB([va-glx], main, LIBS="-lva -lva-glx $LIBS", use_vaapi=no, -lva) +- fi +- +- if test "x$use_vaapi" = "xno"; then ++ PKG_CHECK_MODULES([LIBVA], [libva libva-x11], ++ [INCLUDES="$INCLUDES $LIBVA_CFLAGS"; LIBS="$LIBS $LIBVA_LIBS"; USE_VAAPI=1; ++ AC_DEFINE([HAVE_LIBVA], [1], [Define to 1 if you have the 'vaapi' libraries])], ++ [use_vaapi="no"; USE_VAAPI=0; AC_MSG_RESULT($vaapi_not_found)]) + else -+ return VC_BUFFER; + if test "x$initial_val" = "xyes"; then + AC_MSG_ERROR($vaapi_not_found) +- else +- AC_MSG_RESULT($vaapi_not_found) + fi +- USE_VAAPI=0 +- else +- AC_DEFINE([HAVE_LIBVA], [1], [Define to 1 if you have the 'vaapi' libraries (-lva AND -lva-glx)]) +- USE_VAAPI=1 + fi + fi + else +diff --git a/language/English/strings.po b/language/English/strings.po +index d386f68..33894d8 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -6180,7 +6180,13 @@ msgctxt "#13456" + msgid "Hardware accelerated" + msgstr "" + +-#empty strings from id 13457 to 13499 ++#. Option for video related setting #13454: sw filter ++#: system/settings/settings.xml ++msgctxt "#13457" ++msgid "Prefer VAAPI render method" ++msgstr "" ++ ++#empty strings from id 13458 to 13499 + + #: system/settings/settings.xml + msgctxt "#13500" +@@ -7344,7 +7350,22 @@ msgctxt "#16326" + msgid "DXVA-HD" + msgstr "" + +-#empty strings from id 16327 to 16399 ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16327" ++msgid "VAAPI Bob" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16328" ++msgid "VAAPI Motion Adaptive" ++msgstr "" ++ ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16329" ++msgid "VAAPI Motion Compensated" ++msgstr "" ++ ++#empty strings from id 16330 to 16399 + + #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp + msgctxt "#16400" +@@ -15333,7 +15354,14 @@ msgctxt "#36431" + msgid "Defines whether video decoding should be performed in software (requires more CPU) or with hardware acceleration where possible." + msgstr "" + +-#empty strings from id 36432 to 36499 ++#. Description for video related setting #13457: vaapi sw filter ++#: system/settings/settings.xml ++msgctxt "#36432" ++msgid "If enabled VAAPI render method is prefered. This puts less load on the CPU but driver may hang!" ++msgstr "" ++ ++#empty strings from id 36433 to 36499 ++ + #end reservation + + #: system/settings/settings.xml +diff --git a/system/settings/settings.xml b/system/settings/settings.xml +index 7d1d51f..8167f9f 100644 +--- a/system/settings/settings.xml ++++ b/system/settings/settings.xml +@@ -715,6 +715,21 @@ + false + + ++ ++ HAVE_LIBVA ++ ++ ++ ++ true ++ 1 ++ ++ ++ true ++ ++ 3 ++ true ++ ++ + + HasDXVA2 + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 73eb193..56b114e 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -62,13 +62,6 @@ extern "C" { + #include + #include "cores/dvdplayer/DVDCodecs/Video/VAAPI.h" + +-#define USE_VAAPI_GLX_BIND \ +- (VA_MAJOR_VERSION == 0 && \ +- ((VA_MINOR_VERSION == 30 && \ +- VA_MICRO_VERSION == 4 && VA_SDS_VERSION >= 5) || \ +- (VA_MINOR_VERSION == 31 && \ +- VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) +- + #endif + + #ifdef TARGET_DARWIN +@@ -128,9 +121,6 @@ static const GLubyte stipple_weave[] = { + }; + + CLinuxRendererGL::YUVBUFFER::YUVBUFFER() +-#ifdef HAVE_LIBVA +- : vaapi(*(new VAAPI::CHolder())) +-#endif + { + memset(&fields, 0, sizeof(fields)); + memset(&image , 0, sizeof(image)); +@@ -139,6 +129,9 @@ CLinuxRendererGL::YUVBUFFER::YUVBUFFER() + #ifdef HAVE_LIBVDPAU + vdpau = NULL; + #endif ++#ifdef HAVE_LIBVA ++ vaapi = NULL; ++#endif + #ifdef TARGET_DARWIN_OSX + cvBufferRef = NULL; + #endif +@@ -146,9 +139,6 @@ CLinuxRendererGL::YUVBUFFER::YUVBUFFER() + + CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() + { +-#ifdef HAVE_LIBVA +- delete &vaapi; +-#endif + #ifdef TARGET_DARWIN_OSX + if (cvBufferRef) + CVBufferRelease(cvBufferRef); +@@ -573,7 +563,7 @@ void CLinuxRendererGL::ReleaseBuffer(int idx) + SAFE_RELEASE(buf.vdpau); + #endif + #ifdef HAVE_LIBVA +- buf.vaapi.surface.reset(); ++ SAFE_RELEASE(buf.vaapi); + #endif + #ifdef TARGET_DARWIN + if (buf.cvBufferRef) +@@ -1056,7 +1046,8 @@ void CLinuxRendererGL::LoadShaders(int field) + m_pboUsed = false; + + // Now that we now the render method, setup texture function handlers +- if (m_format == RENDER_FMT_NV12) ++ if (m_format == RENDER_FMT_NV12 || ++ m_format == RENDER_FMT_VAAPINV12) + { + m_textureUpload = &CLinuxRendererGL::UploadNV12Texture; + m_textureCreate = &CLinuxRendererGL::CreateNV12Texture; +@@ -1193,14 +1184,14 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + else if (m_renderMethod & RENDER_VDPAU) + { + UpdateVideoFilter(); +- RenderVDPAU(renderBuffer, m_currentField); ++ RenderRGB(renderBuffer, m_currentField); + } + #endif + #ifdef HAVE_LIBVA + else if (m_renderMethod & RENDER_VAAPI) + { + UpdateVideoFilter(); +- RenderVAAPI(renderBuffer, m_currentField); ++ RenderRGB(renderBuffer, m_currentField); + } + #endif + else +@@ -1220,6 +1211,16 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + } + } + #endif ++#ifdef HAVE_LIBVA ++ if (m_format == RENDER_FMT_VAAPI) ++ { ++ YUVBUFFER &buf = m_buffers[renderBuffer]; ++ if (buf.vaapi) ++ { ++ buf.vaapi->Sync(); ++ } ++ } ++#endif + } + + void CLinuxRendererGL::RenderSinglePass(int index, int field) +@@ -1562,9 +1563,9 @@ void CLinuxRendererGL::RenderProgressiveWeave(int index, int field) + } + } + +-void CLinuxRendererGL::RenderVDPAU(int index, int field) ++void CLinuxRendererGL::RenderRGB(int index, int field) + { +-#ifdef HAVE_LIBVDPAU ++#if defined(HAVE_LIBVDPAU) || defined(HAVE_LIBVA) + YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0]; + + glEnable(m_textureTarget); +@@ -1636,99 +1637,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field) + #endif + } + +-void CLinuxRendererGL::RenderVAAPI(int index, int field) +-{ +-#ifdef HAVE_LIBVA +- YUVPLANE &plane = m_buffers[index].fields[0][0]; +- VAAPI::CHolder &va = m_buffers[index].vaapi; +- +- if(!va.surface) +- { +- CLog::Log(LOGINFO, "CLinuxRendererGL::RenderVAAPI - no vaapi object"); +- return; +- } +- VAAPI::CDisplayPtr& display(va.surface->m_display); +- CSingleLock lock(*display); +- +- glEnable(m_textureTarget); +- glActiveTextureARB(GL_TEXTURE0); +- glBindTexture(m_textureTarget, plane.id); +- +-#if USE_VAAPI_GLX_BIND +- VAStatus status; +- status = vaBeginRenderSurfaceGLX(display->get(), va.surfglx->m_id); +- if(status != VA_STATUS_SUCCESS) +- { +- CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaBeginRenderSurfaceGLX failed (%d)", status); +- return; +- } +-#endif +- +- // make sure we know the correct texture size +- GetPlaneTextureSize(plane); +- CalculateTextureSourceRects(index, 1); +- +- // Try some clamping or wrapping +- glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +- glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +- +- if (m_pVideoFilterShader) +- { +- GLint filter; +- if (!m_pVideoFilterShader->GetTextureFilter(filter)) +- filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; +- +- glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); +- glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); +- m_pVideoFilterShader->SetSourceTexture(0); +- m_pVideoFilterShader->SetWidth(m_sourceWidth); +- m_pVideoFilterShader->SetHeight(m_sourceHeight); +- +- //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer +- //having non-linear stretch on breaks the alignment +- if (g_application.m_pPlayer->IsInMenu()) +- m_pVideoFilterShader->SetNonLinStretch(1.0); +- else +- m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio)); +- +- m_pVideoFilterShader->Enable(); +- } +- else +- { +- GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; +- glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); +- glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); +- } +- +- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +- VerifyGLState(); +- +- glBegin(GL_QUADS); +- glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y); +- glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y); +- glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y); +- glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y); +- glEnd(); +- +- VerifyGLState(); +- +- if (m_pVideoFilterShader) +- m_pVideoFilterShader->Disable(); +- +-#if USE_VAAPI_GLX_BIND +- status = vaEndRenderSurfaceGLX(display->get(), va.surfglx->m_id); +- if(status != VA_STATUS_SUCCESS) +- { +- CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaEndRenderSurfaceGLX failed (%d)", status); +- return; +- } +-#endif +- +- glBindTexture (m_textureTarget, 0); +- glDisable(m_textureTarget); +-#endif +-} +- + void CLinuxRendererGL::RenderSoftware(int index, int field) + { + // used for textues uploaded from rgba or CVPixelBuffers. +@@ -2594,17 +2502,9 @@ bool CLinuxRendererGL::UploadVDPAUTexture420(int index) + void CLinuxRendererGL::DeleteVAAPITexture(int index) + { + #ifdef HAVE_LIBVA +- YUVPLANE &plane = m_buffers[index].fields[0][0]; +- VAAPI::CHolder &va = m_buffers[index].vaapi; +- +- va.display.reset(); +- va.surface.reset(); +- va.surfglx.reset(); +- +- if(plane.id && glIsTexture(plane.id)) +- glDeleteTextures(1, &plane.id); ++ YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0]; ++ SAFE_RELEASE(m_buffers[index].vaapi); + plane.id = 0; +- + #endif + } + +@@ -2654,83 +2554,44 @@ bool CLinuxRendererGL::CreateVAAPITexture(int index) + bool CLinuxRendererGL::UploadVAAPITexture(int index) + { + #ifdef HAVE_LIBVA +- YUVPLANE &plane = m_buffers[index].fields[0][0]; +- VAAPI::CHolder &va = m_buffers[index].vaapi; +- VAStatus status; ++ VAAPI::CVaapiRenderPicture *vaapi = m_buffers[index].vaapi; + +- if(!va.surface) +- return false; ++ YV12Image &im = m_buffers[index].image; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[FIELD_FULL][0]; + +- if(va.display && va.surface->m_display != va.display) ++ if (!vaapi || !vaapi->valid) + { +- CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - context changed %d", index); +- va.surfglx.reset(); ++ return false; + } +- va.display = va.surface->m_display; +- +- CSingleLock lock(*va.display); + +- if(va.display->lost()) +- return false; ++ plane.id = vaapi->texture; + +- if(!va.surfglx) +- { +- CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - creating vaapi surface for texture %d", index); +- void* surface; +- status = vaCreateSurfaceGLX(va.display->get() +- , m_textureTarget +- , plane.id +- , &surface); +- if(status != VA_STATUS_SUCCESS) +- { +- CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to create vaapi glx surface (%d)", status); +- return false; +- } +- va.surfglx = VAAPI::CSurfaceGLPtr(new VAAPI::CSurfaceGL(surface, va.display)); +- } +- int colorspace; +- if(CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT709) +- colorspace = VA_SRC_BT709; +- else +- colorspace = VA_SRC_BT601; ++ // in stereoscopic mode sourceRect may only ++ // be a part of the source video surface ++ plane.rect = m_sourceRect; + +- int field; +- if (m_currentField == FIELD_TOP) +- field = VA_TOP_FIELD; +- else if (m_currentField == FIELD_BOT) +- field = VA_BOTTOM_FIELD; +- else +- field = VA_FRAME_PICTURE; +- +-#if USE_VAAPI_GLX_BIND +- status = vaAssociateSurfaceGLX(va.display->get() +- , va.surfglx->m_id +- , va.surface->m_id +- , field | colorspace); +-#else +- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +- status = vaCopySurfaceGLX(va.display->get() +- , va.surfglx->m_id +- , va.surface->m_id +- , field | colorspace); +-#endif ++ // clip rect ++ if (vaapi->crop.x1 > plane.rect.x1) ++ plane.rect.x1 = vaapi->crop.x1; ++ if (vaapi->crop.x2 < plane.rect.x2) ++ plane.rect.x2 = vaapi->crop.x2; ++ if (vaapi->crop.y1 > plane.rect.y1) ++ plane.rect.y1 = vaapi->crop.y1; ++ if (vaapi->crop.y2 < plane.rect.y2) ++ plane.rect.y2 = vaapi->crop.y2; ++ ++ plane.texheight = vaapi->texHeight; ++ plane.texwidth = vaapi->texWidth; + +- // when a vaapi backend is lost (vdpau), we start getting these errors +- if(status == VA_STATUS_ERROR_INVALID_SURFACE +- || status == VA_STATUS_ERROR_INVALID_DISPLAY) ++ if (m_textureTarget == GL_TEXTURE_2D) + { +- va.display->lost(true); +- for(int i = 0; i < m_NumYV12Buffers; i++) +- { +- m_buffers[i].vaapi.display.reset(); +- m_buffers[i].vaapi.surface.reset(); +- m_buffers[i].vaapi.surfglx.reset(); +- } ++ plane.rect.y1 /= plane.texheight; ++ plane.rect.y2 /= plane.texheight; ++ plane.rect.x1 /= plane.texwidth; ++ plane.rect.x2 /= plane.texwidth; + } + +- if(status != VA_STATUS_SUCCESS) +- CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to copy surface to glx %d - %s", status, vaErrorStr(status)); +- + #endif + return true; + } +@@ -3528,21 +3389,13 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + return false; + } + +- if(m_renderMethod & RENDER_VAAPI) ++ if(m_format == RENDER_FMT_VAAPI || ++ m_format == RENDER_FMT_VAAPINV12) + { + #ifdef HAVE_LIBVA +- VAAPI::CDisplayPtr disp = m_buffers[m_iYV12RenderBuffer].vaapi.display; +- if(disp) +- { +- CSingleLock lock(*disp); +- +- if(disp->support_deinterlace()) +- { +- if( method == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED +- || method == VS_INTERLACEMETHOD_RENDER_BOB ) +- return true; +- } +- } ++ VAAPI::CVaapiRenderPicture *vaapiPic = m_buffers[m_iYV12RenderBuffer].vaapi; ++ if(vaapiPic && vaapiPic->vaapi) ++ return vaapiPic->vaapi->Supports(method); + #endif + return false; + } +@@ -3663,6 +3516,7 @@ unsigned int CLinuxRendererGL::GetProcessorSize() + if(m_format == RENDER_FMT_VDPAU + || m_format == RENDER_FMT_VDPAU_420 + || m_format == RENDER_FMT_VAAPI ++ || m_format == RENDER_FMT_VAAPINV12 + || m_format == RENDER_FMT_CVBREF) + return 1; + else +@@ -3680,10 +3534,12 @@ void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index + #endif + + #ifdef HAVE_LIBVA +-void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index) ++void CLinuxRendererGL::AddProcessor(VAAPI::CVaapiRenderPicture *vaapi, int index) + { + YUVBUFFER &buf = m_buffers[index]; +- buf.vaapi.surface = holder.surface; ++ VAAPI::CVaapiRenderPicture *pic = vaapi->Acquire(); ++ SAFE_RELEASE(buf.vaapi); ++ buf.vaapi = pic; + } + #endif + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 304017f..1e46940 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -41,7 +41,7 @@ class CRenderCapture; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } +-namespace VAAPI { struct CHolder; } ++namespace VAAPI { class CVaapiRenderPicture; } + namespace VDPAU { class CVdpauRenderPicture; } + + #undef ALIGN +@@ -142,7 +142,7 @@ class CLinuxRendererGL : public CBaseRenderer + virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index); + #endif + #ifdef HAVE_LIBVA +- virtual void AddProcessor(VAAPI::CHolder& holder, int index); ++ virtual void AddProcessor(VAAPI::CVaapiRenderPicture* vaapi, int index); + #endif + #ifdef TARGET_DARWIN + virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); +@@ -218,9 +218,8 @@ class CLinuxRendererGL : public CBaseRenderer + void RenderFromFBO(); + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer + void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer +- void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware ++ void RenderRGB(int renderBuffer, int field); // render using vdpau/vaapi hardware + void RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware +- void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware + + struct + { +@@ -282,7 +281,7 @@ class CLinuxRendererGL : public CBaseRenderer + VDPAU::CVdpauRenderPicture *vdpau; + #endif + #ifdef HAVE_LIBVA +- VAAPI::CHolder& vaapi; ++ VAAPI::CVaapiRenderPicture *vaapi; + #endif + #ifdef TARGET_DARWIN_OSX + struct __CVBuffer *cvBufferRef; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index f15e80d..15e1d76 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -32,6 +32,7 @@ enum ERenderFormat { + RENDER_FMT_YUYV422, + RENDER_FMT_DXVA, + RENDER_FMT_VAAPI, ++ RENDER_FMT_VAAPINV12, + RENDER_FMT_OMXEGL, + RENDER_FMT_CVBREF, + RENDER_FMT_BYPASS, +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 85467d2..ee1675b 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -56,6 +56,10 @@ + #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h" + #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h" + ++#ifdef HAVE_LIBVA ++ #include "../dvdplayer/DVDCodecs/Video/VAAPI.h" ++#endif ++ + #define MAXPRESENTDELAY 0.500 + + /* at any point we want an exclusive lock on rendermanager */ +@@ -925,7 +929,12 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + #endif + #ifdef HAVE_LIBVA + else if(pic.format == RENDER_FMT_VAAPI) +- m_pRenderer->AddProcessor(*pic.vaapi, index); ++ m_pRenderer->AddProcessor(pic.vaapi, index); ++ else if(pic.format == RENDER_FMT_VAAPINV12) ++ { ++ m_pRenderer->AddProcessor(pic.vaapi, index); ++ CDVDCodecUtils::CopyNV12Picture(&image, &pic.vaapi->DVDPic); ++ } + #endif + #ifdef HAS_LIBSTAGEFRIGHT + else if(pic.format == RENDER_FMT_EGLIMG) +@@ -988,10 +997,10 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + if (mInt == VS_INTERLACEMETHOD_NONE) + return VS_INTERLACEMETHOD_NONE; + +- if(!m_pRenderer->Supports(mInt)) ++ if(m_pRenderer && !m_pRenderer->Supports(mInt)) + mInt = VS_INTERLACEMETHOD_AUTO; + +- if (mInt == VS_INTERLACEMETHOD_AUTO) ++ if (m_pRenderer && mInt == VS_INTERLACEMETHOD_AUTO) + return m_pRenderer->AutoInterlaceMethod(); + + return mInt; +diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +index 21a4ee2..b675995 100644 +--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ++++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +@@ -208,13 +208,14 @@ BaseYUV2RGBGLSLShader::BaseYUV2RGBGLSLShader(bool rect, unsigned flags, ERenderF + m_format == RENDER_FMT_YUV420P10 || + m_format == RENDER_FMT_YUV420P16) + m_defines += "#define XBMC_YV12\n"; +- else if (m_format == RENDER_FMT_NV12) ++ else if (m_format == RENDER_FMT_NV12 || ++ m_format == RENDER_FMT_VAAPINV12) + m_defines += "#define XBMC_NV12\n"; + else if (m_format == RENDER_FMT_YUYV422) + m_defines += "#define XBMC_YUY2\n"; + else if (m_format == RENDER_FMT_UYVY422) + m_defines += "#define XBMC_UYVY\n"; +- else if (RENDER_FMT_VDPAU_420) ++ else if (m_format == RENDER_FMT_VDPAU_420) + m_defines += "#define XBMC_VDPAU_NV12\n"; + else + CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index c5b24d6..69ff8c9 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -46,7 +46,7 @@ struct DVDCodecAvailableType + #define FRAME_TYPE_D 4 + + namespace DXVA { class CSurfaceContext; } +-namespace VAAPI { struct CHolder; } ++namespace VAAPI { class CVaapiRenderPicture; } + namespace VDPAU { class CVdpauRenderPicture; } + class COpenMax; + class COpenMaxVideo; +@@ -75,7 +75,7 @@ struct DVDVideoPicture + VDPAU::CVdpauRenderPicture* vdpau; + }; + struct { +- VAAPI::CHolder* vaapi; ++ VAAPI::CVaapiRenderPicture* vaapi; + }; + + struct { +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 0bbca2a..9ac307a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -628,6 +628,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->chroma_position = m_pCodecContext->chroma_sample_location; + pDvdVideoPicture->color_primaries = m_pCodecContext->color_primaries; + pDvdVideoPicture->color_transfer = m_pCodecContext->color_trc; ++ pDvdVideoPicture->color_matrix = m_pCodecContext->colorspace; + if(m_pCodecContext->color_range == AVCOL_RANGE_JPEG + || m_pCodecContext->pix_fmt == PIX_FMT_YUVJ420P) + pDvdVideoPicture->color_range = 1; +@@ -651,10 +652,24 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->qscale_type = DVP_QSCALE_UNKNOWN; + } + +- pDvdVideoPicture->dts = m_dts; ++ if (pDvdVideoPicture->iRepeatPicture) ++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE; ++ else ++ pDvdVideoPicture->dts = m_dts; ++ + m_dts = DVD_NOPTS_VALUE; +- if (m_pFrame->reordered_opaque) +- pDvdVideoPicture->pts = pts_itod(m_pFrame->reordered_opaque); ++ ++ int64_t bpts = av_frame_get_best_effort_timestamp(m_pFrame); ++ if(bpts != AV_NOPTS_VALUE) ++ { ++ pDvdVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE; ++ if (pDvdVideoPicture->pts == m_decoderPts) ++ { ++ pDvdVideoPicture->iRepeatPicture = -0.5; ++ pDvdVideoPicture->pts = DVD_NOPTS_VALUE; ++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE; ++ } ++ } + else + pDvdVideoPicture->pts = DVD_NOPTS_VALUE; + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index a788abd..93be338 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -22,535 +22,3011 @@ + #include "windowing/WindowingFactory.h" + #include "VAAPI.h" + #include "DVDVideoCodec.h" +-#include +-#include ++#include "cores/dvdplayer/DVDCodecs/DVDCodecUtils.h" ++#include "cores/dvdplayer/DVDClock.h" + #include "utils/log.h" ++#include "utils/StringUtils.h" + #include "threads/SingleLock.h" +- +-#define CHECK(a) \ +-do { \ +- VAStatus res = a; \ +- if(res != VA_STATUS_SUCCESS) \ +- { \ +- CLog::Log(LOGERROR, "VAAPI - failed executing "#a" at line %d with error %x:%s", __LINE__, res, vaErrorStr(res)); \ +- return false; \ +- } \ +-} while(0); +- +-#define WARN(a) \ +-do { \ +- VAStatus res = a; \ +- if(res != VA_STATUS_SUCCESS) \ +- CLog::Log(LOGWARNING, "VAAPI - failed executing "#a" at line %d with error %x:%s", __LINE__, res, vaErrorStr(res)); \ +-} while(0); ++#include "settings/Settings.h" ++#include "guilib/GraphicContext.h" ++#include "settings/MediaSettings.h" ++#include ++ ++extern "C" { ++#include "libavutil/avutil.h" ++#include "libavutil/opt.h" ++#include "libavfilter/buffersink.h" ++#include "libavfilter/buffersrc.h" ++} + + #ifndef VA_SURFACE_ATTRIB_SETTABLE + #define vaCreateSurfaces(d, f, w, h, s, ns, a, na) \ +- vaCreateSurfaces(d, w, h, f, ns, s) ++vaCreateSurfaces(d, w, h, f, ns, s) ++#endif ++ ++#if VA_CHECK_VERSION(0,34,0) ++#include ++#define HAVE_VPP 1 + #endif + +-using namespace std; +-using namespace boost; + using namespace VAAPI; ++#define NUM_RENDER_PICS 7 + +-// settings codecs mapping +-DVDCodecAvailableType g_vaapi_available[] = { +- { AV_CODEC_ID_H263, "videoplayer.usevaapimpeg4" }, +- { AV_CODEC_ID_MPEG4, "videoplayer.usevaapimpeg4" }, +- { AV_CODEC_ID_WMV3, "videoplayer.usevaapivc1" }, +- { AV_CODEC_ID_VC1, "videoplayer.usevaapivc1" }, +- { AV_CODEC_ID_MPEG2VIDEO, "videoplayer.usevaapimpeg2" }, +-}; +-const size_t settings_count = sizeof(g_vaapi_available) / sizeof(DVDCodecAvailableType); ++//----------------------------------------------------------------------------- ++//----------------------------------------------------------------------------- ++ ++CVAAPIContext *CVAAPIContext::m_context = 0; ++CCriticalSection CVAAPIContext::m_section; ++Display *CVAAPIContext::m_X11dpy = 0; + +-static int compare_version(int major_l, int minor_l, int micro_l, int major_r, int minor_r, int micro_r) ++CVAAPIContext::CVAAPIContext() + { +- if(major_l < major_r) return -1; +- if(major_l > major_r) return 1; +- if(minor_l < minor_r) return -1; +- if(minor_l > minor_r) return 1; +- if(micro_l < micro_r) return -1; +- if(micro_l > micro_r) return 1; +- return 0; ++ m_context = 0; ++ m_refCount = 0; ++ m_attributes = NULL; ++ m_profiles = NULL; ++ m_display = NULL; + } + +-static void RelBufferS(void *opaque, uint8_t *data) +-{ ((CDecoder*)((CDVDVideoCodecFFmpeg*)opaque)->GetHardware())->RelBuffer(data); } ++void CVAAPIContext::Release(CDecoder *decoder) ++{ ++ CSingleLock lock(m_section); ++ ++ std::vector::iterator it; ++ it = find(m_decoders.begin(), m_decoders.end(), decoder); ++ if (it != m_decoders.end()) ++ m_decoders.erase(it); + +-static int GetBufferS(AVCodecContext *avctx, AVFrame *pic, int flags) +-{ return ((CDecoder*)((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetHardware())->GetBuffer(avctx, pic, flags); } ++ m_refCount--; ++ if (m_refCount <= 0) ++ { ++ Close(); ++ delete this; ++ m_context = 0; ++ } ++} + +-static inline VASurfaceID GetSurfaceID(AVFrame *pic) +-{ return (VASurfaceID)(uintptr_t)pic->data[3]; } ++void CVAAPIContext::Close() ++{ ++ CLog::Log(LOGNOTICE, "VAAPI::Close - closing decoder context"); ++ DestroyContext(); ++} + +-static CDisplayPtr GetGlobalDisplay() ++bool CVAAPIContext::EnsureContext(CVAAPIContext **ctx, CDecoder *decoder) + { +- static boost::weak_ptr display_global; ++ CSingleLock lock(m_section); + +- CDisplayPtr display(display_global.lock()); +- if(display) ++ if (m_context) + { +- if(display->lost()) ++ m_context->m_refCount++; ++ *ctx = m_context; ++ if (!m_context->IsValidDecoder(decoder)) ++ m_context->m_decoders.push_back(decoder); ++ return true; ++ } ++ ++ m_context = new CVAAPIContext(); ++ *ctx = m_context; ++ { ++ CSingleLock gLock(g_graphicsContext); ++ if (!m_context->CreateContext()) + { +- CLog::Log(LOGERROR, "VAAPI - vaapi display is in lost state"); +- display.reset(); +- } +- return display; ++ delete m_context; ++ m_context = 0; ++ *ctx = NULL; ++ return false; ++ } ++ } ++ ++ m_context->m_refCount++; ++ ++ if (!m_context->IsValidDecoder(decoder)) ++ m_context->m_decoders.push_back(decoder); ++ *ctx = m_context; ++ return true; ++} ++ ++bool CVAAPIContext::CreateContext() ++{ ++ { CSingleLock lock(g_graphicsContext); ++ if (!m_X11dpy) ++ m_X11dpy = XOpenDisplay(NULL); + } + +- VADisplay disp; +- disp = vaGetDisplayGLX(g_Windowing.GetDisplay()); ++ m_display = vaGetDisplay(m_X11dpy); + + int major_version, minor_version; +- VAStatus res = vaInitialize(disp, &major_version, &minor_version); ++ if (!CheckSuccess(vaInitialize(m_display, &major_version, &minor_version))) ++ { ++ m_display = NULL; ++ return false; ++ } + + CLog::Log(LOGDEBUG, "VAAPI - initialize version %d.%d", major_version, minor_version); + +- if(res != VA_STATUS_SUCCESS) ++ ++ QueryCaps(); ++ if (!m_profileCount || !m_attributeCount) ++ return false; ++ ++ return true; ++} ++ ++void CVAAPIContext::DestroyContext() ++{ ++ delete[] m_attributes; ++ delete[] m_profiles; ++ if (m_display) ++ CheckSuccess(vaTerminate(m_display)); ++} ++ ++void CVAAPIContext::QueryCaps() ++{ ++ m_attributeCount = 0; ++ m_profileCount = 0; ++ ++ int max_attributes = vaMaxNumDisplayAttributes(m_display); ++ m_attributes = new VADisplayAttribute[max_attributes]; ++ ++ if (!CheckSuccess(vaQueryDisplayAttributes(m_display, m_attributes, &m_attributeCount))) ++ return; ++ ++ for(int i = 0; i < m_attributeCount; i++) + { +- CLog::Log(LOGERROR, "VAAPI - unable to initialize display %d - %s", res, vaErrorStr(res)); +- return display; ++ VADisplayAttribute * const display_attr = &m_attributes[i]; ++ CLog::Log(LOGDEBUG, "VAAPI - attrib %d (%s/%s) min %d max %d value 0x%x\n" ++ , display_attr->type ++ ,(display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---" ++ ,(display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---" ++ , display_attr->min_value ++ , display_attr->max_value ++ , display_attr->value); + } + +- const char* vendor = vaQueryVendorString(disp); +- CLog::Log(LOGDEBUG, "VAAPI - vendor: %s", vendor); ++ int max_profiles = vaMaxNumProfiles(m_display); ++ m_profiles = new VAProfile[max_profiles]; ++ ++ if (!CheckSuccess(vaQueryConfigProfiles(m_display, m_profiles, &m_profileCount))) ++ return; ++ ++ for(int i = 0; i < m_profileCount; i++) ++ CLog::Log(LOGDEBUG, "VAAPI - profile %d", m_profiles[i]); ++} ++ ++VAConfigAttrib CVAAPIContext::GetAttrib(VAProfile profile) ++{ ++ CSingleLock lock(m_section); ++ ++ VAConfigAttrib attrib; ++ attrib.type = VAConfigAttribRTFormat; ++ CheckSuccess(vaGetConfigAttributes(m_display, profile, VAEntrypointVLD, &attrib, 1)); ++ ++ return attrib; ++} ++ ++bool CVAAPIContext::SupportsProfile(VAProfile profile) ++{ ++ CSingleLock lock(m_section); + +- bool deinterlace = true; +- int major, minor, micro; +- bool support_4k = true; +- if(sscanf(vendor, "Intel i965 driver - %d.%d.%d", &major, &minor, µ) == 3) ++ for (int i=0; isupport_4k(support_4k); +- display_global = display; +- return display; ++ VAConfigID config = VA_INVALID_ID; ++ CheckSuccess(vaCreateConfig(m_display, profile, VAEntrypointVLD, &attrib, 1, &config)); ++ ++ return config; + } + +-CDisplay::~CDisplay() ++bool CVAAPIContext::CheckSuccess(VAStatus status) + { +- CLog::Log(LOGDEBUG, "VAAPI - destroying display %p", m_display); +- WARN(vaTerminate(m_display)) ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI error: %s", vaErrorStr(status)); ++ return false; ++ } ++ return true; + } + +-CSurface::~CSurface() ++VADisplay CVAAPIContext::GetDisplay() + { +- CLog::Log(LOGDEBUG, "VAAPI - destroying surface 0x%x", (int)m_id); +- CSingleLock lock(*m_display); +- WARN(vaDestroySurfaces(m_display->get(), &m_id, 1)) ++ return m_display; + } + +-CSurfaceGL::~CSurfaceGL() ++bool CVAAPIContext::IsValidDecoder(CDecoder *decoder) + { +- CLog::Log(LOGDEBUG, "VAAPI - destroying glx surface %p", m_id); +- CSingleLock lock(*m_display); +- WARN(vaDestroySurfaceGLX(m_display->get(), m_id)) ++ std::vector::iterator it; ++ it = find(m_decoders.begin(), m_decoders.end(), decoder); ++ if (it != m_decoders.end()) ++ return true; ++ ++ return false; + } + +-CDecoder::CDecoder() ++void CVAAPIContext::FFReleaseBuffer(void *opaque, uint8_t *data) + { +- m_refs = 0; +- m_surfaces_count = 0; +- m_config = 0; +- m_context = 0; +- m_hwaccel = (vaapi_context*)calloc(1, sizeof(vaapi_context)); +- memset(m_surfaces, 0, sizeof(*m_surfaces)); ++ CDecoder *va = (CDecoder*)opaque; ++ if (m_context && m_context->IsValidDecoder(va)) ++ { ++ va->FFReleaseBuffer(data); + } } - bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) +-CDecoder::~CDecoder() ++//----------------------------------------------------------------------------- ++// VAAPI Video Surface states ++//----------------------------------------------------------------------------- ++ ++#define SURFACE_USED_FOR_REFERENCE 0x01 ++#define SURFACE_USED_FOR_RENDER 0x02 ++ ++void CVideoSurfaces::AddSurface(VASurfaceID surf) + { +- Close(); +- free(m_hwaccel); ++ CSingleLock lock(m_section); ++ m_state[surf] = 0; ++ m_freeSurfaces.push_back(surf); + } + +-void CDecoder::RelBuffer(uint8_t *data) ++void CVideoSurfaces::ClearReference(VASurfaceID surf) + { +- VASurfaceID surface = (VASurfaceID)(uintptr_t)data; ++ CSingleLock lock(m_section); ++ if (m_state.find(surf) == m_state.end()) ++ { ++ CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid"); ++ return; ++ } ++ m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE; ++ if (m_state[surf] == 0) ++ { ++ m_freeSurfaces.push_back(surf); ++ } ++} + +- 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); +- m_surfaces_used.erase(it); +- break; +- } ++bool CVideoSurfaces::MarkRender(VASurfaceID surf) ++{ ++ CSingleLock lock(m_section); ++ if (m_state.find(surf) == m_state.end()) ++ { ++ CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid"); ++ return false; + } ++ std::list::iterator it; ++ it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf); ++ if (it != m_freeSurfaces.end()) ++ { ++ m_freeSurfaces.erase(it); ++ } ++ m_state[surf] |= SURFACE_USED_FOR_RENDER; ++ return true; ++} ++ ++void CVideoSurfaces::ClearRender(VASurfaceID surf) ++{ ++ CSingleLock lock(m_section); ++ if (m_state.find(surf) == m_state.end()) ++ { ++ CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid"); ++ return; ++ } ++ m_state[surf] &= ~SURFACE_USED_FOR_RENDER; ++ if (m_state[surf] == 0) ++ { ++ m_freeSurfaces.push_back(surf); ++ } ++} ++ ++bool CVideoSurfaces::IsValid(VASurfaceID surf) ++{ ++ CSingleLock lock(m_section); ++ if (m_state.find(surf) != m_state.end()) ++ return true; ++ else ++ return false; + } + +-int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) ++VASurfaceID CVideoSurfaces::GetFree(VASurfaceID surf) + { +- VASurfaceID surface = GetSurfaceID(pic); +- CSurface* wrapper = NULL; +- std::list::iterator it = m_surfaces_free.begin(); +- if(surface) ++ CSingleLock lock(m_section); ++ if (m_state.find(surf) != m_state.end()) + { +- /* reget call */ +- for(; it != m_surfaces_free.end(); ++it) ++ std::list::iterator it; ++ it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf); ++ if (it == m_freeSurfaces.end()) + { +- if((*it)->m_id == surface) +- { +- wrapper = it->get(); +- m_surfaces_used.push_back(*it); +- m_surfaces_free.erase(it); +- break; +- } ++ CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free"); + } +- if(!wrapper) ++ else + { +- CLog::Log(LOGERROR, "VAAPI - unable to find requested surface"); +- return -1; ++ m_freeSurfaces.erase(it); ++ m_state[surf] = SURFACE_USED_FOR_REFERENCE; ++ return surf; + } + } +- else ++ ++ if (!m_freeSurfaces.empty()) + { +- // 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) {} ++ VASurfaceID freeSurf = m_freeSurfaces.front(); ++ m_freeSurfaces.pop_front(); ++ m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE; ++ return freeSurf; ++ } + +- // 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"); +- 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()) +- { +- CLog::Log(LOGERROR, "VAAPI - unable to find free surface"); +- return -1; +- } +- // Set itarator position to the newly allocated surface (end-1) +- it = m_surfaces_free.end(); --it; +- } +- /* getbuffer call */ +- wrapper = it->get(); +- surface = wrapper->m_id; +- m_surfaces_used.push_back(*it); +- m_surfaces_free.erase(it); +- } +- +- pic->data[0] = (uint8_t*)wrapper; +- pic->data[1] = NULL; +- pic->data[2] = NULL; +- pic->data[3] = (uint8_t*)(uintptr_t)surface; +- pic->linesize[0] = 0; +- pic->linesize[1] = 0; +- pic->linesize[2] = 0; +- pic->linesize[3] = 0; +- pic->reordered_opaque= avctx->reordered_opaque; ++ return VA_INVALID_SURFACE; ++} + +- AVBufferRef *buffer = av_buffer_create(pic->data[3], 0, RelBufferS, avctx->opaque, 0); +- if (!buffer) ++VASurfaceID CVideoSurfaces::GetAtIndex(int idx) ++{ ++ if (idx >= m_state.size()) ++ return VA_INVALID_SURFACE; ++ ++ std::map::iterator it = m_state.begin(); ++ for(int i = 0; i < idx; i++) ++ ++it; ++ return it->first; ++} ++ ++VASurfaceID CVideoSurfaces::RemoveNext(bool skiprender) ++{ ++ CSingleLock lock(m_section); ++ VASurfaceID surf; ++ std::map::iterator it; ++ for(it = m_state.begin(); it != m_state.end(); ++it) + { +- CLog::Log(LOGERROR, "VAAPI::%s - error creating buffer", __FUNCTION__); +- return -1; ++ if (skiprender && it->second & SURFACE_USED_FOR_RENDER) ++ continue; ++ surf = it->first; ++ m_state.erase(surf); ++ ++ std::list::iterator it2; ++ it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf); ++ if (it2 != m_freeSurfaces.end()) ++ m_freeSurfaces.erase(it2); ++ return surf; + } +- pic->buf[0] = buffer; +- return 0; ++ return VA_INVALID_SURFACE; + } + +-void CDecoder::Close() +-{ +- if(m_context) +- WARN(vaDestroyContext(m_display->get(), m_context)) +- m_context = 0; ++void CVideoSurfaces::Reset() ++{ ++ CSingleLock lock(m_section); ++ m_freeSurfaces.clear(); ++ m_state.clear(); ++} ++ ++int CVideoSurfaces::Size() ++{ ++ CSingleLock lock(m_section); ++ return m_state.size(); ++} ++ ++bool CVideoSurfaces::HasFree() ++{ ++ CSingleLock lock(m_section); ++ return !m_freeSurfaces.empty(); ++} + +- 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; +- m_refs = 0; +- memset(m_hwaccel , 0, sizeof(*m_hwaccel)); +- memset(m_surfaces, 0, sizeof(*m_surfaces)); +- m_display.reset(); +- m_holder.surface.reset(); ++//----------------------------------------------------------------------------- ++// VAAPI ++//----------------------------------------------------------------------------- ++ ++// settings codecs mapping ++DVDCodecAvailableType g_vaapi_available[] = { ++ { AV_CODEC_ID_H263, "videoplayer.usevaapimpeg4" }, ++ { AV_CODEC_ID_MPEG4, "videoplayer.usevaapimpeg4" }, ++ { AV_CODEC_ID_WMV3, "videoplayer.usevaapivc1" }, ++ { AV_CODEC_ID_VC1, "videoplayer.usevaapivc1" }, ++ { AV_CODEC_ID_MPEG2VIDEO, "videoplayer.usevaapimpeg2" }, ++}; ++const size_t settings_count = sizeof(g_vaapi_available) / sizeof(DVDCodecAvailableType); ++ ++CDecoder::CDecoder() : m_vaapiOutput(&m_inMsgEvent) ++{ ++ m_vaapiConfig.videoSurfaces = &m_videoSurfaces; ++ ++ m_vaapiConfigured = false; ++ m_DisplayState = VAAPI_OPEN; ++ m_vaapiConfig.context = 0; ++ m_vaapiConfig.contextId = VA_INVALID_ID; ++ m_vaapiConfig.configId = VA_INVALID_ID; ++} ++ ++CDecoder::~CDecoder() ++{ ++ Close(); + } + +-bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces) ++bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces) + { ++ // don't support broken wrappers ++ // nvidia cards with a vaapi to vdpau wrapper ++ // fglrx cards with xvba-va-driver ++ std::string gpuvendor = g_Windowing.GetRenderVendor(); ++ std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower); ++ if (gpuvendor.compare(0, 5, "intel") != 0) ++ { ++ CLog::Log(LOGNOTICE, "VAAPI is not correctly supported on your hardware - will close the decoder."); ++ return false; ++ } ++ + // check if user wants to decode this format with VAAPI + if (CDVDVideoCodec::IsCodecDisabled(g_vaapi_available, settings_count, avctx->codec_id)) + return false; + +- VAEntrypoint entrypoint = VAEntrypointVLD; +- VAProfile profile; ++ CLog::Log(LOGDEBUG,"VAAPI - open decoder"); + +- CLog::Log(LOGDEBUG, "VAAPI - attempting to open codec %d with profile %d at level %d with %d reference frames", avctx->codec_id, avctx->profile, avctx->level, avctx->refs); ++ if (!CVAAPIContext::EnsureContext(&m_vaapiConfig.context, this)) ++ return false; + +- vector accepted; +- switch (avctx->codec_id) { ++ m_vaapiConfig.vidWidth = avctx->width; ++ m_vaapiConfig.vidHeight = avctx->height; ++ m_vaapiConfig.outWidth = avctx->width; ++ m_vaapiConfig.outHeight = avctx->height; ++ m_vaapiConfig.surfaceWidth = avctx->width; ++ m_vaapiConfig.surfaceHeight = avctx->height; ++ m_vaapiConfig.aspect = avctx->sample_aspect_ratio; ++ m_vaapiConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); ++ m_DisplayState = VAAPI_OPEN; ++ m_vaapiConfigured = false; ++ m_presentPicture = 0; ++ ++ VAProfile profile; ++ switch (avctx->codec_id) ++ { + case AV_CODEC_ID_MPEG2VIDEO: +- accepted.push_back(VAProfileMPEG2Main); ++ profile = VAProfileMPEG2Main; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; + break; + case AV_CODEC_ID_MPEG4: + case AV_CODEC_ID_H263: +- accepted.push_back(VAProfileMPEG4AdvancedSimple); ++ profile = VAProfileMPEG4AdvancedSimple; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; + break; + case AV_CODEC_ID_H264: + { +-#ifdef FF_PROFILE_H264_BASELINE +- if (avctx->profile == FF_PROFILE_H264_BASELINE) +- accepted.push_back(VAProfileH264Baseline); ++ if (avctx->profile == FF_PROFILE_H264_BASELINE) ++ { ++ profile = VAProfileH264Baseline; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; ++ } + else + { + if(avctx->profile == FF_PROFILE_H264_MAIN) +- accepted.push_back(VAProfileH264Main); +-#else +- { +- // fallback to high profile if libavcodec is too old to export +- // profile information; it will likely work +-#endif +- // fallback to high profile if main profile is not available +- accepted.push_back(VAProfileH264High); ++ { ++ profile = VAProfileH264Main; ++ if (m_vaapiConfig.context->SupportsProfile(profile)) ++ break; ++ } ++ profile = VAProfileH264High; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; + } + break; + } + case AV_CODEC_ID_WMV3: +- accepted.push_back(VAProfileVC1Main); ++ profile = VAProfileVC1Main; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; + break; + case AV_CODEC_ID_VC1: +- accepted.push_back(VAProfileVC1Advanced); ++ profile = VAProfileVC1Advanced; ++ if (!m_vaapiConfig.context->SupportsProfile(profile)) ++ return false; + break; + default: + return false; + } + +- m_display = GetGlobalDisplay(); +- if(!m_display) +- return false; +- +- if(!m_display->support_4k() && (avctx->width > 1920 || avctx->height > 1088)) ++ m_vaapiConfig.profile = profile; ++ m_vaapiConfig.attrib = m_vaapiConfig.context->GetAttrib(profile); ++ if ((m_vaapiConfig.attrib.value & VA_RT_FORMAT_YUV420) == 0) + { +- CLog::Log(LOGDEBUG, "VAAPI - frame size (%dx%d) too large - disallowing", avctx->width, avctx->height); ++ CLog::Log(LOGERROR, "VAAPI - invalid yuv format %x", m_vaapiConfig.attrib.value); + return false; + } + +- int num_display_attrs = 0; +- scoped_array display_attrs(new VADisplayAttribute[vaMaxNumDisplayAttributes(m_display->get())]); +- +- CHECK(vaQueryDisplayAttributes(m_display->get(), display_attrs.get(), &num_display_attrs)) +- +- for(int i = 0; i < num_display_attrs; i++) ++ if(avctx->codec_id == AV_CODEC_ID_H264) + { +- VADisplayAttribute * const display_attr = &display_attrs[i]; +- CLog::Log(LOGDEBUG, "VAAPI - attrib %d (%s/%s) min %d max %d value 0x%x\n" +- , display_attr->type +- ,(display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---" +- ,(display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---" +- , display_attr->min_value +- , display_attr->max_value +- , display_attr->value); ++ m_vaapiConfig.maxReferences = avctx->refs; ++ if (m_vaapiConfig.maxReferences > 16) ++ m_vaapiConfig.maxReferences = 16; ++ if (m_vaapiConfig.maxReferences < 5) ++ m_vaapiConfig.maxReferences = 5; + } ++ else ++ m_vaapiConfig.maxReferences = 2; + +- int num_profiles = 0; +- scoped_array profiles(new VAProfile[vaMaxNumProfiles(m_display->get())]); +- CHECK(vaQueryConfigProfiles(m_display->get(), profiles.get(), &num_profiles)) +- +- for(int i = 0; i < num_profiles; i++) +- CLog::Log(LOGDEBUG, "VAAPI - profile %d", profiles[i]); ++ m_vaapiConfig.maxReferences += surfaces; + +- vector::iterator selected = find_first_of(accepted.begin() +- , accepted.end() +- , profiles.get() +- , profiles.get()+num_profiles); +- if(selected == accepted.end()) ++ if (!ConfigVAAPI()) + { +- CLog::Log(LOGDEBUG, "VAAPI - unable to find a suitable profile"); + return false; + } + +- profile = *selected; +- +- VAConfigAttrib attrib; +- attrib.type = VAConfigAttribRTFormat; +- CHECK(vaGetConfigAttributes(m_display->get(), profile, entrypoint, &attrib, 1)) +- +- if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) +- { +- CLog::Log(LOGERROR, "VAAPI - invalid yuv format %x", attrib.value); +- return false; +- } ++ avctx->hwaccel_context = &m_hwContext; ++ avctx->thread_count = 1; ++ avctx->get_buffer2 = CDecoder::FFGetBuffer; ++ avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; ++ return true; ++} + +- CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id)) +- m_config = m_hwaccel->config_id; ++void CDecoder::Close() ++{ ++ CLog::Log(LOGNOTICE, "VAAPI::%s", __FUNCTION__); + +- m_renderbuffers_count = surfaces; +- if (!EnsureContext(avctx)) +- return false; ++ CSingleLock lock(m_DecoderSection); + +- m_hwaccel->display = m_display->get(); ++ FiniVAAPIOutput(); + +- avctx->hwaccel_context = m_hwaccel; +- avctx->thread_count = 1; +- avctx->get_buffer2 = GetBufferS; +- avctx->draw_horiz_band = NULL; +- avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; +- return true; ++ if (m_vaapiConfig.context) ++ m_vaapiConfig.context->Release(this); ++ m_vaapiConfig.context = 0; + } + +-bool CDecoder::EnsureContext(AVCodecContext *avctx) ++long CDecoder::Release() + { +- if(avctx->refs && avctx->refs <= m_refs) +- return true; +- +- if(m_refs > 0) +- CLog::Log(LOGWARNING, "VAAPI - reference frame count increasing, reiniting decoder"); +- +- m_refs = avctx->refs; +- if(m_refs == 0) ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_vaapiConfigured == true) + { +- if(avctx->codec_id == AV_CODEC_ID_H264) +- m_refs = 16; ++ CSingleLock lock(m_DecoderSection); ++ CLog::Log(LOGNOTICE,"VAAPI::Release pre-cleanup"); ++ ++ Message *reply; ++ if (m_vaapiOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - pre-cleanup returned error", __FUNCTION__); ++ m_DisplayState = VAAPI_ERROR; ++ } ++ } + else +- m_refs = 2; ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - pre-cleanup timed out", __FUNCTION__); ++ m_DisplayState = VAAPI_ERROR; ++ } ++ ++ VASurfaceID surf; ++ while((surf = m_videoSurfaces.RemoveNext(true)) != VA_INVALID_SURFACE) ++ { ++ CheckSuccess(vaDestroySurfaces(m_vaapiConfig.dpy, &surf, 1)); ++ } + } +- return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1); ++ return IHardwareDecoder::Release(); + } + +-bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) ++long CDecoder::ReleasePicReference() + { +- CLog::Log(LOGDEBUG, "VAAPI - making sure %d surfaces are allocated for given %d references", n_surfaces_count, avctx->refs); +- +- if(n_surfaces_count > m_surfaces_max) +- { +- CLog::Log(LOGERROR, "VAAPI - Failed to ensure surfaces! Requested %d surfaces. Maximum possible count is %d!", n_surfaces_count, m_surfaces_max); +- return false; +- } ++ return IHardwareDecoder::Release(); ++} + +- if(n_surfaces_count <= m_surfaces_count) +- return true; ++int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) ++{ ++ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; ++ CDecoder* va = (CDecoder*)ctx->GetHardware(); + +- const unsigned old_surfaces_count = m_surfaces_count; +- m_surfaces_count = n_surfaces_count; ++ // while we are waiting to recover we can't do anything ++ CSingleLock lock(va->m_DecoderSection); + +- CHECK(vaCreateSurfaces(m_display->get() +- , VA_RT_FORMAT_YUV420 +- , avctx->width +- , avctx->height +- , &m_surfaces[old_surfaces_count] +- , m_surfaces_count - old_surfaces_count +- , NULL +- , 0)) ++ if(va->m_DisplayState != VAAPI_OPEN) ++ { ++ CLog::Log(LOGWARNING, "VAAPI::FFGetBuffer - returning due to awaiting recovery"); ++ return -1; ++ } + +- for(unsigned i = old_surfaces_count; i < m_surfaces_count; i++) +- m_surfaces_free.push_back(CSurfacePtr(new CSurface(m_surfaces[i], m_display))); ++ VASurfaceID surf = (VASurfaceID)(uintptr_t)pic->data[3]; ++ surf = va->m_videoSurfaces.GetFree(surf != 0 ? surf : VA_INVALID_SURFACE); + +- //shared_ptr test = VASurfaceIDPtr(m_surfaces[0], m_display); ++ if (surf == VA_INVALID_SURFACE) ++ { ++ uint16_t decoded, processed, render; ++ va->m_bufferStats.Get(decoded, processed, render); ++ CLog::Log(LOGERROR, "VAAPI::FFGetBuffer - no surface available - dec: %d, render: %d", ++ decoded, render); ++ return -1; ++ } + +- if(m_context) +- WARN(vaDestroyContext(m_display->get(), m_context)) +- m_context = 0; ++ pic->data[1] = pic->data[2] = NULL; ++ pic->data[0] = (uint8_t*)(uintptr_t)surf; ++ pic->data[3] = (uint8_t*)(uintptr_t)surf; ++ pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0; ++ AVBufferRef *buffer = av_buffer_create(pic->data[3], 0, CVAAPIContext::FFReleaseBuffer, va, 0); ++ if (!buffer) ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - error creating buffer", __FUNCTION__); ++ return -1; ++ } ++ pic->buf[0] = buffer; + +- CHECK(vaCreateContext(m_display->get() +- , m_config +- , avctx->width +- , avctx->height +- , VA_PROGRESSIVE +- , m_surfaces +- , m_surfaces_count +- , &m_hwaccel->context_id)) +- m_context = m_hwaccel->context_id; +- return true; ++ pic->reordered_opaque= avctx->reordered_opaque; ++ return 0; + } + +-int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) ++void CDecoder::FFReleaseBuffer(uint8_t *data) + { +- int status = Check(avctx); +- if(status) +- return status; ++ VASurfaceID surf; ++ unsigned int i; + +- if(frame) +- return VC_BUFFER | VC_PICTURE; +- else +- return VC_BUFFER; ++ CSingleLock lock(m_DecoderSection); ++ ++ surf = (VASurfaceID)(uintptr_t)data; ++ m_videoSurfaces.ClearReference(surf); + } + +-bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++int CDecoder::Decode(AVCodecContext* avctx, AVFrame* pFrame) + { +- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(picture); +- VASurfaceID surface = GetSurfaceID(frame); ++ int result = Check(avctx); ++ if (result) ++ return result; ++ ++ CSingleLock lock(m_DecoderSection); + ++ if (!m_vaapiConfigured) ++ return VC_ERROR; + +- m_holder.surface.reset(); ++ if(pFrame) ++ { // we have a new frame from decoder + +- std::list::iterator it; +- for(it = m_surfaces_used.begin(); it != m_surfaces_used.end() && !m_holder.surface; ++it) +- { +- if((*it)->m_id == surface) ++ VASurfaceID surf = (VASurfaceID)(uintptr_t)pFrame->data[3]; ++ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid ++ if (!m_videoSurfaces.IsValid(surf)) + { +- m_holder.surface = *it; +- break; ++ CLog::Log(LOGWARNING, "VAAPI::Decode - ignoring invalid buffer"); ++ return VC_BUFFER; + } ++ m_videoSurfaces.MarkRender(surf); ++ ++ // send frame to output for processing ++ CVaapiDecodedPicture pic; ++ memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); ++ pic.videoSurface = surf; ++ pic.DVDPic.color_matrix = avctx->colorspace; ++ m_bufferStats.IncDecoded(); ++ m_vaapiOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); ++ ++// m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC); + } + +- for(it = m_surfaces_free.begin(); it != m_surfaces_free.end() && !m_holder.surface; ++it) +- { +- if((*it)->m_id == surface) ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_vaapiOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) + { +- m_holder.surface = *it; +- break; ++ m_DisplayState = VAAPI_ERROR; ++ retval |= VC_ERROR; + } +- } +- if(!m_holder.surface) +- { +- CLog::Log(LOGERROR, "VAAPI - Unable to find surface"); +- return false; ++ msg->Release(); + } + +- picture->format = RENDER_FMT_VAAPI; +- picture->vaapi = &m_holder; +- return true; +-} ++ m_bufferStats.Get(decoded, processed, render); + +-int CDecoder::Check(AVCodecContext* avctx) +-{ +- if (m_display == NULL) ++ bool hasfree = m_videoSurfaces.HasFree(); ++ while (!retval) + { +- if(!Open(avctx, avctx->pix_fmt)) ++ // first fill the buffers to keep vaapi busy ++ if (decoded < 3 && processed < 3 && m_videoSurfaces.HasFree()) + { +- CLog::Log(LOGERROR, "VAAPI - Unable to recover device after display was closed"); +- Close(); +- return VC_ERROR; ++ retval |= VC_BUFFER; + } +- } +- +- if (m_display->lost()) +- { +- Close(); +- if(!Open(avctx, avctx->pix_fmt)) ++ else if (m_vaapiOutput.m_dataPort.ReceiveInMessage(&msg)) + { +- CLog::Log(LOGERROR, "VAAPI - Unable to recover device after display was lost"); +- Close(); +- return VC_ERROR; ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ if (m_presentPicture) ++ { ++ m_presentPicture->ReturnUnused(); ++ m_presentPicture = 0; ++ } ++ ++ m_presentPicture = *(CVaapiRenderPicture**)msg->data; ++ m_presentPicture->vaapi = this; ++ m_bufferStats.DecRender(); ++ m_bufferStats.Get(decoded, processed, render); ++ retval |= VC_PICTURE; ++ msg->Release(); ++ break; ++ } ++ msg->Release(); + } +- return VC_FLUSHED; +- } +- +- if (!EnsureContext(avctx)) +- return VC_ERROR; +- +- m_holder.surface.reset(); ++ else if (m_vaapiOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::STATS) ++ { ++ m_bufferStats.Get(decoded, processed, render); ++ } ++ else ++ { ++ m_DisplayState = VAAPI_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ if (decoded < 3 && processed < 3 && m_videoSurfaces.HasFree()) ++ { ++ retval |= VC_BUFFER; ++ } ++ ++ if (!retval && !m_inMsgEvent.WaitMSec(2000)) ++ break; ++ } ++ if (retval & VC_PICTURE) ++ { ++ m_bufferStats.SetParams(0, m_codecControl); ++ } ++ ++ if (!retval) ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - timed out waiting for output message - decoded: %d, proc: %d, has free surface: %s", ++ __FUNCTION__, decoded, processed, m_videoSurfaces.HasFree() ? "yes" : "no"); ++ m_DisplayState = VAAPI_ERROR; ++ retval |= VC_ERROR; ++ } ++ ++ return retval; ++} ++ ++int CDecoder::Check(AVCodecContext* avctx) ++{ ++ EDisplayState state; ++ ++ { CSingleLock lock(m_DecoderSection); ++ state = m_DisplayState; ++ } ++ ++ if (state == VAAPI_LOST) ++ { ++ CLog::Log(LOGNOTICE,"VAAPI::Check waiting for display reset event"); ++ if (!m_DisplayEvent.WaitMSec(4000)) ++ { ++ CLog::Log(LOGERROR, "VAAPI::Check - device didn't reset in reasonable time"); ++ state = VAAPI_RESET; ++ } ++ else ++ { ++ CSingleLock lock(m_DecoderSection); ++ state = m_DisplayState; ++ } ++ } ++ if (state == VAAPI_RESET || state == VAAPI_ERROR) ++ { ++ CSingleLock lock(m_DecoderSection); ++ ++ avcodec_flush_buffers(avctx); ++ FiniVAAPIOutput(); ++ if (m_vaapiConfig.context) ++ m_vaapiConfig.context->Release(this); ++ m_vaapiConfig.context = 0; ++ ++ if (CVAAPIContext::EnsureContext(&m_vaapiConfig.context, this) && ConfigVAAPI()) ++ { ++ m_DisplayState = VAAPI_OPEN; ++ } ++ ++ if (state == VAAPI_RESET) ++ return VC_FLUSHED; ++ else ++ return VC_ERROR; ++ } + return 0; + } + +-unsigned CDecoder::GetAllowedReferences() ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ CSingleLock lock(m_DecoderSection); ++ ++ if (m_DisplayState != VAAPI_OPEN) ++ return false; ++ ++ *picture = m_presentPicture->DVDPic; ++ picture->vaapi = m_presentPicture; ++ ++ return true; ++} ++ ++void CDecoder::Reset() ++{ ++ CSingleLock lock(m_DecoderSection); ++ ++ if (!m_vaapiConfigured) ++ return; ++ ++ Message *reply; ++ if (m_vaapiOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - flush returned error", __FUNCTION__); ++ m_DisplayState = VAAPI_ERROR; ++ } ++ else ++ m_bufferStats.Reset(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - flush timed out", __FUNCTION__); ++ m_DisplayState = VAAPI_ERROR; ++ } ++} ++ ++bool CDecoder::CanSkipDeint() ++{ ++ return m_bufferStats.CanSkipDeint(); ++} ++ ++bool CDecoder::CheckSuccess(VAStatus status) ++{ ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI - error: %s", vaErrorStr(status)); ++ m_ErrorCount++; ++ ++ if(m_DisplayState == VAAPI_OPEN) ++ { ++ if (m_ErrorCount > 2) ++ m_DisplayState = VAAPI_ERROR; ++ } ++ return false; ++ } ++ m_ErrorCount = 0; ++ return true; ++} ++ ++bool CDecoder::Supports(EINTERLACEMETHOD method) ++{ ++ if(method == VS_INTERLACEMETHOD_AUTO) ++ return true; ++ ++ for (int i=0; iGetDisplay(); ++ m_vaapiConfig.attrib = m_vaapiConfig.context->GetAttrib(m_vaapiConfig.profile); ++ if ((m_vaapiConfig.attrib.value & VA_RT_FORMAT_YUV420) == 0) ++ { ++ CLog::Log(LOGERROR, "VAAPI - invalid yuv format %x", m_vaapiConfig.attrib.value); ++ return false; ++ } ++ ++ m_vaapiConfig.configId = m_vaapiConfig.context->CreateConfig(m_vaapiConfig.profile, ++ m_vaapiConfig.attrib); ++ if (m_vaapiConfig.configId == VA_INVALID_ID) ++ return false; ++ ++ // create surfaces ++ VASurfaceID surfaces[32]; ++ int nb_surfaces = m_vaapiConfig.maxReferences; ++ if (!CheckSuccess(vaCreateSurfaces(m_vaapiConfig.dpy, ++ VA_RT_FORMAT_YUV420, ++ m_vaapiConfig.surfaceWidth, ++ m_vaapiConfig.surfaceHeight, ++ surfaces, ++ nb_surfaces, ++ NULL, 0))) ++ { ++ return false; ++ } ++ for (int i=0; isignal == COutputControlProtocol::ACC ? true : false; ++ if (!success) ++ { ++ reply->Release(); ++ CLog::Log(LOGERROR, "VAAPI::%s - vaapi output returned error", __FUNCTION__); ++ m_vaapiOutput.Dispose(); ++ return false; ++ } ++ SDiMethods *diMethods = NULL; ++ diMethods = (SDiMethods*)reply->data; ++ if (diMethods) ++ { ++ m_diMethods.clear(); ++ for (int i=0; inumDiMethods; i++) ++ { ++ m_diMethods.push_back(diMethods->diMethods[i]); ++ } ++ } ++ reply->Release(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VAAPI::%s - failed to init output", __FUNCTION__); ++ m_vaapiOutput.Dispose(); ++ return false; ++ } ++ ++ ++ m_hwContext.config_id = m_vaapiConfig.configId; ++ m_hwContext.context_id = m_vaapiConfig.contextId; ++ m_hwContext.display = m_vaapiConfig.dpy; ++ ++ m_inMsgEvent.Reset(); ++ m_vaapiConfigured = true; ++ m_ErrorCount = 0; ++ ++ return true; ++} ++ ++void CDecoder::FiniVAAPIOutput() ++{ ++ if (!m_vaapiConfigured) ++ return; ++ ++ memset(&m_hwContext, 0, sizeof(vaapi_context)); ++ ++ // uninit output ++ m_vaapiOutput.Dispose(); ++ m_vaapiConfigured = false; ++ ++ VAStatus status; ++ ++ // destroy decoder context ++ if (m_vaapiConfig.contextId != VA_INVALID_ID) ++ CheckSuccess(vaDestroyContext(m_vaapiConfig.dpy, m_vaapiConfig.contextId)); ++ m_vaapiConfig.contextId = VA_INVALID_ID; ++ ++ // detroy surfaces ++ CLog::Log(LOGDEBUG, "VAAPI::FiniVAAPIOutput destroying %d video surfaces", m_videoSurfaces.Size()); ++ VASurfaceID surf; ++ while((surf = m_videoSurfaces.RemoveNext()) != VA_INVALID_SURFACE) ++ { ++ CheckSuccess(vaDestroySurfaces(m_vaapiConfig.dpy, &surf, 1)); ++ } ++ m_videoSurfaces.Reset(); ++ ++ // destroy vaapi config ++ if (m_vaapiConfig.configId != VA_INVALID_ID) ++ CheckSuccess(vaDestroyConfig(m_vaapiConfig.dpy, m_vaapiConfig.configId)); ++ m_vaapiConfig.configId = VA_INVALID_ID; ++} ++ ++void CDecoder::ReturnRenderPicture(CVaapiRenderPicture *renderPic) ++{ ++ m_vaapiOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic)); ++} ++ ++ ++//----------------------------------------------------------------------------- ++// RenderPicture ++//----------------------------------------------------------------------------- ++ ++CVaapiRenderPicture* CVaapiRenderPicture::Acquire() ++{ ++ CSingleLock lock(renderPicSection); ++ ++ if (refCount == 0) ++ vaapi->Acquire(); ++ ++ refCount++; ++ return this; ++} ++ ++long CVaapiRenderPicture::Release() ++{ ++ CSingleLock lock(renderPicSection); ++ ++ refCount--; ++ if (refCount > 0) ++ return refCount; ++ ++ lock.Leave(); ++ vaapi->ReturnRenderPicture(this); ++ vaapi->ReleasePicReference(); ++ ++ return refCount; ++} ++ ++void CVaapiRenderPicture::ReturnUnused() ++{ ++ { CSingleLock lock(renderPicSection); ++ if (refCount > 0) ++ return; ++ } ++ if (vaapi) ++ vaapi->ReturnRenderPicture(this); ++} ++ ++void CVaapiRenderPicture::Sync() ++{ ++#ifdef GL_ARB_sync ++ CSingleLock lock(renderPicSection); ++ if (usefence) ++ { ++ if(glIsSync(fence)) ++ { ++ glDeleteSync(fence); ++ fence = None; ++ } ++ fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); ++ } ++#endif ++} ++ ++//----------------------------------------------------------------------------- ++// Buffer Pool ++//----------------------------------------------------------------------------- ++ ++VaapiBufferPool::VaapiBufferPool() ++{ ++ CVaapiRenderPicture *pic; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ pic = new CVaapiRenderPicture(renderPicSec); ++ allRenderPics.push_back(pic); ++ } ++} ++ ++VaapiBufferPool::~VaapiBufferPool() ++{ ++ CVaapiRenderPicture *pic; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ pic = allRenderPics[i]; ++ delete pic; ++ } ++ allRenderPics.clear(); ++} ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++COutput::COutput(CEvent *inMsgEvent) : ++ CThread("Vaapi-Output"), ++ m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i) ++ { ++ m_bufferPool.freeRenderPics.push_back(i); ++ } ++} ++ ++void COutput::Start() ++{ ++ Create(); ++} ++ ++COutput::~COutput() ++{ ++ Dispose(); ++ ++ m_bufferPool.freeRenderPics.clear(); ++ m_bufferPool.usedRenderPics.clear(); ++} ++ ++void COutput::Dispose() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void COutput::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created"); ++} ++ ++void COutput::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated"); ++} ++ ++enum OUTPUT_STATES ++{ ++ O_TOP = 0, // 0 ++ O_TOP_ERROR, // 1 ++ O_TOP_UNCONFIGURED, // 2 ++ O_TOP_CONFIGURED, // 3 ++ O_TOP_CONFIGURED_IDLE, // 4 ++ O_TOP_CONFIGURED_WORK, // 5 ++ O_TOP_CONFIGURED_STEP1, // 6 ++ O_TOP_CONFIGURED_STEP2, // 7 ++ O_TOP_CONFIGURED_OUTPUT, // 8 ++}; ++ ++int VAAPI_OUTPUT_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_IDLE ++ 3, //TOP_CONFIGURED_WORK ++ 3, //TOP_CONFIGURED_STEP1 ++ 3, //TOP_CONFIGURED_STEP2 ++ 3, //TOP_CONFIGURED_OUTPUT ++}; ++ ++void COutput::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = VAAPI_OUTPUT_parentStates[state]) ++ { ++ switch (state) ++ { ++ case O_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::RETURNPIC: ++ CVaapiRenderPicture *pic; ++ pic = *((CVaapiRenderPicture**)msg->data); ++ QueueReturnPicture(pic); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case O_TOP_ERROR: ++ break; ++ ++ case O_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::INIT: ++ CVaapiConfig *data; ++ data = (CVaapiConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ ++ // set initial number of ++ EnsureBufferPool(); ++ if (!m_vaError) ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ msg->Reply(COutputControlProtocol::ACC, &m_diMethods, sizeof(m_diMethods)); ++ } ++ else ++ { ++ m_state = O_TOP_ERROR; ++ msg->Reply(COutputControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ Flush(); ++ ReleaseBufferPool(true); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::NEWFRAME: ++ CVaapiDecodedPicture *frame; ++ frame = (CVaapiDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_bufferPool.decodedPics.push_back(*frame); ++ m_extTimeout = 0; ++ } ++ return; ++ case COutputDataProtocol::RETURNPIC: ++ CVaapiRenderPicture *pic; ++ pic = *((CVaapiRenderPicture**)msg->data); ++ QueueReturnPicture(pic); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ ++ case O_TOP_CONFIGURED_IDLE: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (ProcessSyncPicture()) ++ m_extTimeout = 10; ++ else ++ m_extTimeout = 100; ++ if (HasWork()) ++ { ++ m_state = O_TOP_CONFIGURED_WORK; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WORK: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (!m_bufferPool.decodedPics.empty() && ++ m_bufferPool.processedPics.size() < 4) ++ { ++ m_currentPicture = m_bufferPool.decodedPics.front(); ++ m_bufferPool.decodedPics.pop_front(); ++ InitCycle(); ++ m_state = O_TOP_CONFIGURED_STEP1; ++ m_extTimeout = 0; ++ return; ++ } ++ else if (!m_bufferPool.freeRenderPics.empty() && ++ !m_bufferPool.processedPics.empty()) ++ { ++ m_state = O_TOP_CONFIGURED_OUTPUT; ++ m_extTimeout = 0; ++ return; ++ } ++ else ++ m_state = O_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 100; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ m_pp->AddPicture(m_currentPicture); ++ CVaapiProcessedPicture outPic; ++ if (m_pp->Filter(outPic)) ++ { ++ m_config.stats->IncProcessed(); ++ m_bufferPool.processedPics.push_back(outPic); ++ m_state = O_TOP_CONFIGURED_STEP2; ++ } ++ else ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ } ++ m_config.stats->DecDecoded(); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ CVaapiProcessedPicture outPic; ++ if (m_pp->Filter(outPic)) ++ { ++ m_bufferPool.processedPics.push_back(outPic); ++ m_config.stats->IncProcessed(); ++ m_extTimeout = 0; ++ return; ++ } ++ m_state = O_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_OUTPUT: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (!m_bufferPool.processedPics.empty()) ++ { ++ CVaapiRenderPicture *outPic; ++ CVaapiProcessedPicture procPic; ++ procPic = m_bufferPool.processedPics.front(); ++ m_config.stats->DecProcessed(); ++ m_bufferPool.processedPics.pop_front(); ++ outPic = ProcessPicture(procPic); ++ ReleaseProcessedPicture(procPic); ++ if (outPic) ++ { ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &outPic, sizeof(outPic)); ++ } ++ if (m_vaError) ++ { ++ m_state = O_TOP_ERROR; ++ return; ++ } ++ } ++ m_state = O_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void COutput::Process() + { +- return m_renderbuffers_count; ++ Message *msg = NULL; ++ Protocol *port = NULL; ++ bool gotMsg; ++ ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = COutputControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Flush(); ++ Uninit(); ++} ++ ++bool COutput::Init() ++{ ++ if (!CreateGlxContext()) ++ return false; ++ ++ if (!GLInit()) ++ return false; ++ ++ m_diMethods.numDiMethods = 0; ++ ++ m_pp = new CFFmpegPostproc(); ++ m_pp->PreInit(m_config, &m_diMethods); ++ delete m_pp; ++ ++ m_pp = new CVppPostproc(); ++ m_pp->PreInit(m_config, &m_diMethods); ++ delete m_pp; ++ ++ m_pp = NULL; ++ ++ m_vaError = false; ++ ++ return true; ++} ++ ++bool COutput::Uninit() ++{ ++ glFlush(); ++ while(ProcessSyncPicture()) ++ { ++ Sleep(10); ++ } ++ ReleaseBufferPool(); ++ delete m_pp; ++ m_pp = NULL; ++ DestroyGlxContext(); ++ return true; ++} ++ ++void COutput::Flush() ++{ ++ Message *msg; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::NEWFRAME) ++ { ++ CVaapiDecodedPicture pic = *(CVaapiDecodedPicture*)msg->data; ++ m_config.videoSurfaces->ClearRender(pic.videoSurface); ++ } ++ else if (msg->signal == COutputDataProtocol::RETURNPIC) ++ { ++ CVaapiRenderPicture *pic; ++ pic = *((CVaapiRenderPicture**)msg->data); ++ QueueReturnPicture(pic); ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ CVaapiRenderPicture *pic; ++ pic = *((CVaapiRenderPicture**)msg->data); ++ QueueReturnPicture(pic); ++ } ++ } ++ ++ for (unsigned int i = 0; i < m_bufferPool.decodedPics.size(); i++) ++ { ++ m_config.videoSurfaces->ClearRender(m_bufferPool.decodedPics[i].videoSurface); ++ } ++ m_bufferPool.decodedPics.clear(); ++ ++ for (unsigned int i = 0; i < m_bufferPool.processedPics.size(); i++) ++ { ++ ReleaseProcessedPicture(m_bufferPool.processedPics[i]); ++ } ++ m_bufferPool.processedPics.clear(); ++ ++ if (m_pp) ++ m_pp->Flush(); ++} ++ ++bool COutput::HasWork() ++{ ++ if ((!m_bufferPool.freeRenderPics.empty() && !m_bufferPool.processedPics.empty()) || ++ !m_bufferPool.decodedPics.empty()) ++ return true; ++ ++ return false; ++} ++ ++void COutput::InitCycle() ++{ ++ uint64_t latency; ++ int speed; ++ m_config.stats->GetParams(latency, speed); ++ ++ m_config.stats->SetCanSkipDeint(false); ++ ++ EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; ++ bool interlaced = m_currentPicture.DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ if ((mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced))) ++ { ++ if((method == VS_INTERLACEMETHOD_AUTO && interlaced) ++ || method == VS_INTERLACEMETHOD_VAAPI_BOB ++ || method == VS_INTERLACEMETHOD_VAAPI_MADI ++ || method == VS_INTERLACEMETHOD_VAAPI_MACI ++ || method == VS_INTERLACEMETHOD_DEINTERLACE ++ || method == VS_INTERLACEMETHOD_RENDER_BOB) ++ { ++ if (method == VS_INTERLACEMETHOD_AUTO) ++ method = VS_INTERLACEMETHOD_RENDER_BOB; ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG,"VAAPI - deinterlace method not supported, falling back to BOB"); ++ method = VS_INTERLACEMETHOD_RENDER_BOB; ++ } ++ ++ if (m_pp && (method != m_currentDiMethod || !m_pp->Compatible(method))) ++ { ++ delete m_pp; ++ m_pp = NULL; ++ DropVppProcessedPictures(); ++ } ++ if (!m_pp) ++ { ++ if (method == VS_INTERLACEMETHOD_DEINTERLACE || ++ method == VS_INTERLACEMETHOD_RENDER_BOB) ++ m_pp = new CFFmpegPostproc(); ++ else ++ m_pp = new CVppPostproc(); ++ if (m_pp->PreInit(m_config)) ++ { ++ m_pp->Init(method); ++ m_currentDiMethod = method; ++ } ++ } ++ } ++ // progressive ++ else ++ { ++ if (m_pp && !m_pp->Compatible(VS_INTERLACEMETHOD_NONE)) ++ { ++ delete m_pp; ++ m_pp = NULL; ++ DropVppProcessedPictures(); ++ } ++ if (!m_pp) ++ { ++ if (CSettings::Get().GetBool("videoplayer.prefervaapirender")) ++ m_pp = new CSkipPostproc(); ++ else ++ m_pp = new CFFmpegPostproc(); ++ if (m_pp->PreInit(m_config)) ++ { ++ m_pp->Init(VS_INTERLACEMETHOD_NONE); ++ } ++ } ++ } ++} ++ ++CVaapiRenderPicture* COutput::ProcessPicture(CVaapiProcessedPicture &pic) ++{ ++ CVaapiRenderPicture *retPic; ++ int idx = m_bufferPool.freeRenderPics.front(); ++ retPic = m_bufferPool.allRenderPics[idx]; ++ retPic->DVDPic = pic.DVDPic; ++ ++ if (pic.source == CVaapiProcessedPicture::SKIP_SRC || ++ pic.source == CVaapiProcessedPicture::VPP_SRC) ++ { ++ unsigned int colorStandard; ++ switch(pic.DVDPic.color_matrix) ++ { ++ case AVCOL_SPC_BT709: ++ colorStandard = VA_SRC_BT709; ++ break; ++ case AVCOL_SPC_BT470BG: ++ case AVCOL_SPC_SMPTE170M: ++ colorStandard = VA_SRC_BT601; ++ break; ++ case AVCOL_SPC_SMPTE240M: ++ case AVCOL_SPC_FCC: ++ case AVCOL_SPC_UNSPECIFIED: ++ case AVCOL_SPC_RGB: ++ default: ++ if(m_config.surfaceWidth > 1000) ++ colorStandard = VA_SRC_BT709; ++ else ++ colorStandard = VA_SRC_BT601; ++ } ++ ++ if (!CheckSuccess(vaSyncSurface(m_config.dpy, pic.videoSurface))) ++ return NULL; ++ ++ if (!CheckSuccess(vaPutSurface(m_config.dpy, ++ pic.videoSurface, ++ retPic->pixmap, ++ 0,0, ++ m_config.surfaceWidth, m_config.surfaceHeight, ++ 0,0, ++ m_config.surfaceWidth, m_config.surfaceHeight, ++ NULL,0, ++ VA_FRAME_PICTURE | colorStandard))) ++ { ++ return NULL; ++ } ++ XSync(m_Display, false); ++ glEnable(m_textureTarget); ++ glBindTexture(m_textureTarget, retPic->texture); ++ glXBindTexImageEXT(m_Display, retPic->glPixmap, GLX_FRONT_LEFT_EXT, NULL); ++ glBindTexture(m_textureTarget, 0); ++ glDisable(m_textureTarget); ++ ++ retPic->DVDPic.format = RENDER_FMT_VAAPI; ++ } ++ else if (pic.source == CVaapiProcessedPicture::FFMPEG_SRC) ++ { ++ av_frame_move_ref(retPic->avFrame, pic.frame); ++ av_frame_free(&pic.frame); ++ retPic->DVDPic.format = RENDER_FMT_VAAPINV12; ++ } ++ else ++ return NULL; ++ ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(idx); ++ ++ retPic->DVDPic.dts = DVD_NOPTS_VALUE; ++ retPic->DVDPic.iWidth = m_config.vidWidth; ++ retPic->DVDPic.iHeight = m_config.vidHeight; ++ ++ retPic->valid = true; ++ retPic->texWidth = m_config.outWidth; ++ retPic->texHeight = m_config.outHeight; ++ retPic->crop.x1 = 0; ++ retPic->crop.y1 = 0; ++ retPic->crop.x2 = m_config.outWidth; ++ retPic->crop.y2 = m_config.outHeight; ++ ++ return retPic; ++} ++ ++void COutput::ReleaseProcessedPicture(CVaapiProcessedPicture &pic) ++{ ++ if (pic.source == CVaapiProcessedPicture::VPP_SRC && m_pp) ++ { ++ CVppPostproc *pp = dynamic_cast(m_pp); ++ if (pp) ++ { ++ pp->ClearRef(pic.videoSurface); ++ } ++ } ++ else if (pic.source == CVaapiProcessedPicture::SKIP_SRC) ++ { ++ m_config.videoSurfaces->ClearRender(pic.videoSurface); ++ } ++ else if (pic.source == CVaapiProcessedPicture::FFMPEG_SRC) ++ { ++ av_frame_free(&pic.frame); ++ } ++} ++ ++void COutput::DropVppProcessedPictures() ++{ ++ std::deque::iterator it; ++ it = m_bufferPool.processedPics.begin(); ++ while (it != m_bufferPool.processedPics.end()) ++ { ++ if (it->source == CVaapiProcessedPicture::VPP_SRC) ++ { ++ it = m_bufferPool.processedPics.erase(it); ++ m_config.stats->DecProcessed(); ++ } ++ else ++ ++it; ++ } ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++} ++ ++void COutput::QueueReturnPicture(CVaapiRenderPicture *pic) ++{ ++ std::deque::iterator it; ++ for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it) ++ { ++ if (m_bufferPool.allRenderPics[*it] == pic) ++ { ++ break; ++ } ++ } ++ ++ if (it == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found"); ++ return; ++ } ++ ++ // check if already queued ++ std::deque::iterator it2 = find(m_bufferPool.syncRenderPics.begin(), ++ m_bufferPool.syncRenderPics.end(), ++ *it); ++ if (it2 == m_bufferPool.syncRenderPics.end()) ++ { ++ m_bufferPool.syncRenderPics.push_back(*it); ++ } ++ ++ ProcessSyncPicture(); ++} ++ ++bool COutput::ProcessSyncPicture() ++{ ++ CVaapiRenderPicture *pic; ++ bool busy = false; ++ ++ std::deque::iterator it; ++ for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); ) ++ { ++ pic = m_bufferPool.allRenderPics[*it]; ++ ++#ifdef GL_ARB_sync ++ if (pic->usefence) ++ { ++ if (glIsSync(pic->fence)) ++ { ++ GLint state; ++ GLsizei length; ++ glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state); ++ if(state == GL_SIGNALED) ++ { ++ glDeleteSync(pic->fence); ++ pic->fence = None; ++ } ++ else ++ { ++ busy = true; ++ ++it; ++ continue; ++ } ++ } ++ } ++#endif ++ ++ m_bufferPool.freeRenderPics.push_back(*it); ++ ++ std::deque::iterator it2 = find(m_bufferPool.usedRenderPics.begin(), ++ m_bufferPool.usedRenderPics.end(), ++ *it); ++ if (it2 == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue"); ++ } ++ else ++ { ++ m_bufferPool.usedRenderPics.erase(it2); ++ } ++ it = m_bufferPool.syncRenderPics.erase(it); ++ ++ if (pic->valid) ++ { ++ ProcessReturnPicture(pic); ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__); ++ } ++ } ++ return busy; ++} ++ ++void COutput::ProcessReturnPicture(CVaapiRenderPicture *pic) ++{ ++ if (pic->avFrame) ++ av_frame_unref(pic->avFrame); ++ ++ if (pic->DVDPic.format == RENDER_FMT_VAAPI) ++ { ++ glEnable(m_textureTarget); ++ glBindTexture(m_textureTarget, pic->texture); ++ glXReleaseTexImageEXT(m_Display, pic->glPixmap, GLX_FRONT_LEFT_EXT); ++ glBindTexture(m_textureTarget, 0); ++ glDisable(m_textureTarget); ++ } ++ ++ pic->valid = false; ++} ++ ++bool COutput::EnsureBufferPool() ++{ ++ int fbConfigIndex = 0; ++ int num; ++ ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, g_Windowing.GetWindow(), &wndattribs); ++ ++ int doubleVisAttributes[] = { ++ GLX_RENDER_TYPE, GLX_RGBA_BIT, ++ GLX_RED_SIZE, 8, ++ GLX_GREEN_SIZE, 8, ++ GLX_BLUE_SIZE, 8, ++ GLX_ALPHA_SIZE, 8, ++ GLX_DEPTH_SIZE, 8, ++ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, ++ GLX_BIND_TO_TEXTURE_RGBA_EXT, True, ++ GLX_DOUBLEBUFFER, False, ++ GLX_Y_INVERTED_EXT, True, ++ GLX_X_RENDERABLE, True, ++ None}; ++ ++ int pixmapAttribs[] = { ++ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, ++ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, ++ None}; ++ ++ GLXFBConfig *fbConfigs; ++ fbConfigs = glXChooseFBConfig(m_Display, g_Windowing.GetCurrentScreen(), doubleVisAttributes, &num); ++ if (fbConfigs==NULL) ++ { ++ CLog::Log(LOGERROR, "VAAPI::EnsureBufferPool - No compatible framebuffers found"); ++ return false; ++ } ++ ++ fbConfigIndex = 0; ++ ++ // create glx surfaces and avFrames ++ CVaapiRenderPicture *pic; ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++) ++ { ++ pic = m_bufferPool.allRenderPics[i]; ++ ++ pic->pixmap = XCreatePixmap(m_Display, ++ m_Window, ++ m_config.surfaceWidth, ++ m_config.surfaceHeight, ++ wndattribs.depth); ++ if (!pic->pixmap) ++ { ++ CLog::Log(LOGERROR, "VAAPI::COutput::EnsureBufferPool - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ pic->glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pic->pixmap, pixmapAttribs); ++ ++ if (!pic->glPixmap) ++ { ++ CLog::Log(LOGINFO, "VAAPI::COutput::EnsureBufferPool - Could not create glPixmap"); ++ return false; ++ } ++ ++ glGenTextures(1, &pic->texture); ++ glBindTexture(m_textureTarget, pic->texture); ++ glXBindTexImageEXT(m_Display, pic->glPixmap, GLX_FRONT_LEFT_EXT, NULL); ++ glBindTexture(m_textureTarget, 0); ++ ++ pic->avFrame = av_frame_alloc(); ++ pic->valid = false; ++ } ++ ++ CLog::Log(LOGNOTICE, "VAAPI::COutput::InitBufferPool - Surfaces created"); ++ return true; ++} ++ ++void COutput::ReleaseBufferPool(bool precleanup) ++{ ++ VAStatus status; ++ CVaapiRenderPicture *pic; ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (!precleanup) ++ { ++ // wait for all fences ++ XbmcThreads::EndTime timeout(1000); ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++) ++ { ++ pic = m_bufferPool.allRenderPics[i]; ++ if (pic->usefence) ++ { ++#ifdef GL_ARB_sync ++ while (glIsSync(pic->fence)) ++ { ++ GLint state; ++ GLsizei length; ++ glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state); ++ if(state == GL_SIGNALED || timeout.IsTimePast()) ++ { ++ glDeleteSync(pic->fence); ++ } ++ else ++ { ++ Sleep(5); ++ } ++ } ++ pic->fence = None; ++#endif ++ } ++ } ++ if (timeout.IsTimePast()) ++ { ++ CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__); ++ } ++ } ++ ++ ProcessSyncPicture(); ++ ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++) ++ { ++ pic = m_bufferPool.allRenderPics[i]; ++ ++ if (precleanup && pic->valid) ++ continue; ++ ++ if (glIsTexture(pic->texture)) ++ { ++ glDeleteTextures(1, &pic->texture); ++ glXDestroyPixmap(m_Display, pic->glPixmap); ++ XFreePixmap(m_Display, pic->pixmap); ++ } ++ av_frame_free(&pic->avFrame); ++ pic->valid = false; ++ } ++ ++ for (unsigned int i = 0; i < m_bufferPool.decodedPics.size(); i++) ++ { ++ m_config.videoSurfaces->ClearRender(m_bufferPool.decodedPics[i].videoSurface); ++ } ++ m_bufferPool.decodedPics.clear(); ++ ++ for (unsigned int i = 0; i < m_bufferPool.processedPics.size(); i++) ++ { ++ ReleaseProcessedPicture(m_bufferPool.processedPics[i]); ++ } ++ m_bufferPool.processedPics.clear(); ++} ++ ++bool COutput::GLInit() ++{ ++#ifdef GL_ARB_sync ++ bool hasfence = glewIsSupported("GL_ARB_sync"); ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++) ++ { ++ m_bufferPool.allRenderPics[i]->usefence = hasfence; ++ } ++#endif ++ ++ if (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle")) ++ { ++ m_textureTarget = GL_TEXTURE_RECTANGLE_ARB; ++ } ++ else ++ m_textureTarget = GL_TEXTURE_2D; ++ ++ glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); ++ glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); ++ ++ return true; ++} ++ ++bool COutput::CheckSuccess(VAStatus status) ++{ ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI - Error: %s(%d)", vaErrorStr(status), status); ++ m_vaError = true; ++ return false; ++ } ++ return true; ++} ++ ++bool COutput::CreateGlxContext() ++{ ++ GLXContext glContext; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWindow(); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, m_Window, &wndattribs); ++ ++ // Get visual Info ++ XVisualInfo visInfo; ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "VAAPI::COutput::CreateGlxContext - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ m_pixmap = XCreatePixmap(m_Display, ++ m_Window, ++ 192, ++ 108, ++ visInfo.depth); ++ if (!m_pixmap) ++ { ++ CLog::Log(LOGERROR, "VAAPI::COutput::CreateGlxContext - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap); ++ ++ if (!m_glPixmap) ++ { ++ CLog::Log(LOGINFO, "VAAPI::COutput::CreateGlxContext - Could not create glPixmap"); ++ return false; ++ } ++ ++ m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True); ++ ++ if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext)) ++ { ++ CLog::Log(LOGINFO, "VAAPI::COutput::CreateGlxContext - Could not make Pixmap current"); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE, "VAAPI::COutput::CreateGlxContext - created context"); ++ return true; ++} ++ ++bool COutput::DestroyGlxContext() ++{ ++ if (m_glContext) ++ { ++ glXMakeCurrent(m_Display, None, NULL); ++ glXDestroyContext(m_Display, m_glContext); ++ } ++ m_glContext = 0; ++ ++ if (m_glPixmap) ++ glXDestroyPixmap(m_Display, m_glPixmap); ++ m_glPixmap = 0; ++ ++ if (m_pixmap) ++ XFreePixmap(m_Display, m_pixmap); ++ m_pixmap = 0; ++ ++ return true; ++} ++ ++//----------------------------------------------------------------------------- ++// Postprocessing ++//----------------------------------------------------------------------------- ++ ++bool CSkipPostproc::PreInit(CVaapiConfig &config, SDiMethods *methods) ++{ ++ m_config = config; ++ return true; ++} ++ ++bool CSkipPostproc::Init(EINTERLACEMETHOD method) ++{ ++ return true; ++} ++ ++bool CSkipPostproc::AddPicture(CVaapiDecodedPicture &inPic) ++{ ++ m_pic = inPic; ++ m_step = 0; ++ return true; ++} ++ ++bool CSkipPostproc::Filter(CVaapiProcessedPicture &outPic) ++{ ++ if (m_step>0) ++ return false; ++ outPic.DVDPic = m_pic.DVDPic; ++ outPic.videoSurface = m_pic.videoSurface; ++ outPic.source = CVaapiProcessedPicture::SKIP_SRC; ++ outPic.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ m_step++; ++ return true; ++} ++ ++void CSkipPostproc::ClearRef(VASurfaceID surf) ++{ ++ ++} ++ ++void CSkipPostproc::Flush() ++{ ++ ++} ++ ++bool CSkipPostproc::Compatible(EINTERLACEMETHOD method) ++{ ++ if (method == VS_INTERLACEMETHOD_NONE && ++ CSettings::Get().GetBool("videoplayer.prefervaapirender")) ++ return true; ++ ++ return false; ++} ++ ++//----------------------------------------------------------------------------- ++// VPP Postprocessing ++//----------------------------------------------------------------------------- ++ ++CVppPostproc::CVppPostproc() ++{ ++ m_contextId = VA_INVALID_ID; ++ m_configId = VA_INVALID_ID; ++ m_filter = VA_INVALID_ID; ++} ++ ++CVppPostproc::~CVppPostproc() ++{ ++ Dispose(); ++} ++ ++bool CVppPostproc::PreInit(CVaapiConfig &config, SDiMethods *methods) ++{ ++#if !defined(HAVE_VPP) ++ return false; ++#else ++ ++ m_config = config; ++ ++ // create config ++ if (!CheckSuccess(vaCreateConfig(m_config.dpy, VAProfileNone, VAEntrypointVideoProc, NULL, 0, &m_configId))) ++ { ++ return false; ++ } ++ ++ // create surfaces ++ VASurfaceID surfaces[32]; ++ int nb_surfaces = 5; ++ if (!CheckSuccess(vaCreateSurfaces(m_config.dpy, ++ VA_RT_FORMAT_YUV420, ++ m_config.surfaceWidth, ++ m_config.surfaceHeight, ++ surfaces, ++ nb_surfaces, ++ NULL, 0))) ++ { ++ return false; ++ } ++ for (int i=0; idiMethods[methods->numDiMethods++] = VS_INTERLACEMETHOD_VAAPI_BOB; ++ } ++ else if (deinterlacingCaps[j].type == VAProcDeinterlacingMotionAdaptive) ++ { ++// methods->diMethods[methods->numDiMethods++] = VS_INTERLACEMETHOD_VAAPI_MADI; ++ } ++ else if (deinterlacingCaps[j].type == VAProcDeinterlacingMotionCompensated) ++ { ++// methods->diMethods[methods->numDiMethods++] = VS_INTERLACEMETHOD_VAAPI_MACI; ++ } ++ } ++ } ++ } ++ } ++#endif ++ return true; ++} ++ ++bool CVppPostproc::Init(EINTERLACEMETHOD method) ++{ ++#if !defined(HAVE_VPP) ++ return false; ++#else ++ ++ VAProcDeinterlacingType vppMethod = VAProcDeinterlacingNone; ++ switch (method) ++ { ++ case VS_INTERLACEMETHOD_VAAPI_BOB: ++ vppMethod = VAProcDeinterlacingBob; ++ break; ++ case VS_INTERLACEMETHOD_VAAPI_MADI: ++ vppMethod = VAProcDeinterlacingMotionAdaptive; ++ break; ++ case VS_INTERLACEMETHOD_VAAPI_MACI: ++ vppMethod = VAProcDeinterlacingMotionCompensated; ++ break; ++ default: ++ return false; ++ } ++ ++ VAProcFilterParameterBufferDeinterlacing filterparams; ++ filterparams.type = VAProcFilterDeinterlacing; ++ filterparams.algorithm = vppMethod; ++ filterparams.flags = 0; ++ ++ if (!CheckSuccess(vaCreateBuffer(m_config.dpy, m_contextId, ++ VAProcFilterParameterBufferType, ++ sizeof(filterparams), 1, &filterparams, &m_filter))) ++ { ++ m_filter = VA_INVALID_ID; ++ return false; ++ } ++ ++ VAProcPipelineCaps pplCaps; ++ if (!CheckSuccess(vaQueryVideoProcPipelineCaps(m_config.dpy, m_contextId, ++ &m_filter, 1, &pplCaps))) ++ { ++ return false; ++ } ++ ++ m_forwardRefs = pplCaps.num_forward_references; ++ m_backwardRefs = pplCaps.num_backward_references; ++ m_currentIdx = 0; ++ m_frameCount = 0; ++ ++#endif ++ return true; ++} ++ ++void CVppPostproc::Dispose() ++{ ++ // make sure surfaces are idle ++ for (int i=0; i1) ++ { ++ Advance(); ++ return false; ++ } ++ ++ // we need a free render target ++ VASurfaceID surf = m_videoSurfaces.GetFree(VA_INVALID_SURFACE); ++ if (surf == VA_INVALID_SURFACE) ++ { ++ CLog::Log(LOGERROR, "VAAPI - VPP - no free render target"); ++ return false; ++ } ++ // clear reference in case we return false ++ m_videoSurfaces.ClearReference(surf); ++ ++ // make sure we have all needed forward refs ++ if ((m_currentIdx - m_forwardRefs) < m_decodedPics.back().index) ++ { ++ Advance(); ++ return false; ++ } ++ ++ std::deque::iterator it; ++ for (it=m_decodedPics.begin(); it!=m_decodedPics.end(); ++it) ++ { ++ if (it->index == m_currentIdx) ++ break; ++ } ++ if (it==m_decodedPics.end()) ++ { ++ return false; ++ } ++ outPic.DVDPic = it->DVDPic; ++ ++ // vpp deinterlacing ++ VAProcFilterParameterBufferDeinterlacing *filterParams; ++ VABufferID pipelineBuf; ++ VAProcPipelineParameterBuffer *pipelineParams; ++ VARectangle inputRegion; ++ VARectangle outputRegion; ++ ++ if (!CheckSuccess(vaBeginPicture(m_config.dpy, m_contextId, surf))) ++ { ++ return false; ++ } ++ ++ if (!CheckSuccess(vaCreateBuffer(m_config.dpy, m_contextId, ++ VAProcPipelineParameterBufferType, ++ sizeof(VAProcPipelineParameterBuffer), 1, NULL, &pipelineBuf))) ++ { ++ return false; ++ } ++ if (!CheckSuccess(vaMapBuffer(m_config.dpy, pipelineBuf, (void**)&pipelineParams))) ++ { ++ return false; ++ } ++ memset(pipelineParams, 0, sizeof(VAProcPipelineParameterBuffer)); ++ ++ inputRegion.x = outputRegion.x = 0; ++ inputRegion.y = outputRegion.y = 0; ++ inputRegion.width = outputRegion.width = m_config.surfaceWidth; ++ inputRegion.height = outputRegion.height = m_config.surfaceHeight; ++ ++ pipelineParams->output_region = &outputRegion; ++ pipelineParams->surface_region = &inputRegion; ++ pipelineParams->output_background_color = 0xff000000; ++ ++ VASurfaceID forwardRefs[32]; ++ VASurfaceID backwardRefs[32]; ++ pipelineParams->forward_references = forwardRefs; ++ pipelineParams->backward_references = backwardRefs; ++ pipelineParams->num_forward_references = 0; ++ pipelineParams->num_backward_references = 0; ++ ++ int maxPic = m_currentIdx + m_backwardRefs; ++ int minPic = m_currentIdx - m_forwardRefs; ++ int curPic = m_currentIdx; ++ ++ // deinterlace flag ++ unsigned int flags = 0; ++ if (it->DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ++ flags = 0; ++ else ++ flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD; ++ ++ if (m_step) ++ { ++ if (flags & VA_DEINTERLACING_BOTTOM_FIELD) ++ flags &= ~VA_DEINTERLACING_BOTTOM_FIELD; ++ else ++ flags |= VA_DEINTERLACING_BOTTOM_FIELD; ++ } ++ if (!CheckSuccess(vaMapBuffer(m_config.dpy, m_filter, (void**)&filterParams))) ++ { ++ return false; ++ } ++ filterParams->flags = flags; ++ if (!CheckSuccess(vaUnmapBuffer(m_config.dpy, m_filter))) ++ { ++ return false; ++ } ++ ++ pipelineParams->filter_flags = (flags & VA_DEINTERLACING_BOTTOM_FIELD) ? VA_BOTTOM_FIELD : VA_TOP_FIELD; ++ pipelineParams->filters = &m_filter; ++ pipelineParams->num_filters = 1; ++ ++ // references ++ double pts, ptsLast = DVD_NOPTS_VALUE; ++ pipelineParams->surface = VA_INVALID_SURFACE; ++ for (it=m_decodedPics.begin(); it!=m_decodedPics.end(); ++it) ++ { ++ if (it->index >= minPic && it->index <= maxPic) ++ { ++ if (it->index > curPic) ++ { ++ backwardRefs[(it->index - curPic) - 1] = it->videoSurface; ++ pipelineParams->num_backward_references++; ++ } ++ else if (it->index == curPic) ++ { ++ pipelineParams->surface = it->videoSurface; ++ pts = it->DVDPic.pts; ++ } ++ if (it->index < curPic) ++ { ++ forwardRefs[(curPic - it->index) - 1] = it->videoSurface; ++ pipelineParams->num_forward_references++; ++ if (it->index == curPic - 1) ++ ptsLast = it->DVDPic.pts; ++ } ++ } ++ } ++ ++ // set pts for 2nd frame ++ if (m_step && pts != DVD_NOPTS_VALUE && ptsLast != DVD_NOPTS_VALUE) ++ outPic.DVDPic.pts += (pts-ptsLast)/2; ++ ++ if (pipelineParams->surface == VA_INVALID_SURFACE) ++ return false; ++ ++ if (!CheckSuccess(vaUnmapBuffer(m_config.dpy, pipelineBuf))) ++ { ++ return false; ++ } ++ ++ if (!CheckSuccess(vaRenderPicture(m_config.dpy, m_contextId, ++ &pipelineBuf, 1))) ++ { ++ return false; ++ } ++ ++ if (!CheckSuccess(vaEndPicture(m_config.dpy, m_contextId))) ++ { ++ return false; ++ } ++ ++ if (!CheckSuccess(vaDestroyBuffer(m_config.dpy, pipelineBuf))) ++ { ++ return false; ++ } ++ ++ m_step++; ++ outPic.videoSurface = m_videoSurfaces.GetFree(surf); ++ outPic.source = CVaapiProcessedPicture::VPP_SRC; ++ outPic.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ ++#endif ++ return true; ++} ++ ++void CVppPostproc::Advance() ++{ ++ m_currentIdx++; ++ ++ // release all unneeded refs ++ std::deque::iterator it; ++ it = m_decodedPics.begin(); ++ while (it != m_decodedPics.end()) ++ { ++ if (it->index < m_currentIdx - m_forwardRefs) ++ { ++ m_config.videoSurfaces->ClearRender(it->videoSurface); ++ it = m_decodedPics.erase(it); ++ } ++ else ++ ++it; ++ } ++} ++ ++void CVppPostproc::ClearRef(VASurfaceID surf) ++{ ++ m_videoSurfaces.ClearReference(surf); ++} ++ ++void CVppPostproc::Flush() ++{ ++ // release all decoded pictures ++ std::deque::iterator it; ++ it = m_decodedPics.begin(); ++ while (it != m_decodedPics.end()) ++ { ++ m_config.videoSurfaces->ClearRender(it->videoSurface); ++ it = m_decodedPics.erase(it); ++ } ++} ++ ++bool CVppPostproc::Compatible(EINTERLACEMETHOD method) ++{ ++ if (method == VS_INTERLACEMETHOD_VAAPI_BOB || ++ method == VS_INTERLACEMETHOD_VAAPI_MADI || ++ method == VS_INTERLACEMETHOD_VAAPI_MACI) ++ return true; ++ ++ return false; ++} ++ ++bool CVppPostproc::CheckSuccess(VAStatus status) ++{ ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI - Error: %s(%d)", vaErrorStr(status), status); ++ return false; ++ } ++ return true; ++} ++ ++//----------------------------------------------------------------------------- ++// FFmpeg Postprocessing ++//----------------------------------------------------------------------------- ++ ++#define CACHED_BUFFER_SIZE 4096 ++ ++CFFmpegPostproc::CFFmpegPostproc() ++{ ++ m_cache = NULL; ++ m_pFilterFrameIn = NULL; ++ m_pFilterFrameOut = NULL; ++ m_pFilterGraph = NULL; ++ m_DVDPic.pts = DVD_NOPTS_VALUE; ++ m_frametime = 0; ++ m_lastOutPts = DVD_NOPTS_VALUE; ++} ++ ++CFFmpegPostproc::~CFFmpegPostproc() ++{ ++ Close(); ++ _aligned_free(m_cache); ++ m_dllSSE4.Unload(); ++ av_frame_free(&m_pFilterFrameIn); ++ av_frame_free(&m_pFilterFrameOut); ++} ++ ++bool CFFmpegPostproc::PreInit(CVaapiConfig &config, SDiMethods *methods) ++{ ++ m_config = config; ++ bool use_filter = true; ++ if (!m_dllSSE4.Load()) ++ { ++ CLog::Log(LOGNOTICE,"VAAPI::SupportsFilter failed loading sse4 lib"); ++ return false; ++ } ++ VAImage image; ++ VASurfaceID surface = config.videoSurfaces->GetAtIndex(0); ++ VAStatus status = vaDeriveImage(config.dpy, surface, &image); ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGNOTICE,"VAAPI::SupportsFilter vaDeriveImage not supported"); ++ use_filter = false; ++ } ++ if (image.format.fourcc != VA_FOURCC_NV12) ++ { ++ CLog::Log(LOGNOTICE,"VAAPI::SupportsFilter image format not NV12"); ++ use_filter = false; ++ } ++ if ((image.pitches[0] % 64) || (image.pitches[1] % 64)) ++ { ++ CLog::Log(LOGNOTICE,"VAAPI::SupportsFilter patches no multiple of 64"); ++ use_filter = false; ++ } ++ CheckSuccess(vaDestroyImage(config.dpy,image.image_id)); ++ ++ if (use_filter) ++ { ++ m_cache = (uint8_t*)_aligned_malloc(CACHED_BUFFER_SIZE, 64); ++ if (methods) ++ { ++ methods->diMethods[methods->numDiMethods++] = VS_INTERLACEMETHOD_DEINTERLACE; ++ methods->diMethods[methods->numDiMethods++] = VS_INTERLACEMETHOD_RENDER_BOB; ++ } ++ } ++ return use_filter; ++} ++ ++bool CFFmpegPostproc::Init(EINTERLACEMETHOD method) ++{ ++ if (!(m_pFilterGraph = avfilter_graph_alloc())) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - unable to alloc filter graph"); ++ return false; ++ } ++ ++ AVFilter* srcFilter = avfilter_get_by_name("buffer"); ++ AVFilter* outFilter = avfilter_get_by_name("buffersink"); ++ ++ std::string args = StringUtils::Format("%d:%d:%d:%d:%d:%d:%d", ++ m_config.vidWidth, ++ m_config.vidHeight, ++ AV_PIX_FMT_NV12, ++ 1, ++ 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.num : 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.den : 1); ++ ++ if (avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - avfilter_graph_create_filter: src"); ++ return false; ++ } ++ ++ if (avfilter_graph_create_filter(&m_pFilterOut, outFilter, "out", NULL, NULL, m_pFilterGraph) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - avfilter_graph_create_filter: out"); ++ return false; ++ } ++ ++ enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_NONE }; ++ if (av_opt_set_int_list(m_pFilterOut, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - failed settings pix formats"); ++ return false; ++ } ++ ++ AVFilterInOut* outputs = avfilter_inout_alloc(); ++ AVFilterInOut* inputs = avfilter_inout_alloc(); ++ ++ outputs->name = av_strdup("in"); ++ outputs->filter_ctx = m_pFilterIn; ++ outputs->pad_idx = 0; ++ outputs->next = NULL; ++ ++ inputs->name = av_strdup("out"); ++ inputs->filter_ctx = m_pFilterOut; ++ inputs->pad_idx = 0; ++ inputs->next = NULL; ++ ++ if (method == VS_INTERLACEMETHOD_DEINTERLACE) ++ { ++ std::string filter; ++ ++ filter = "yadif=1:-1"; ++ ++ if (avfilter_graph_parse_ptr(m_pFilterGraph, filter.c_str(), &inputs, &outputs, NULL) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - avfilter_graph_parse"); ++ avfilter_inout_free(&outputs); ++ avfilter_inout_free(&inputs); ++ return false; ++ } ++ ++ avfilter_inout_free(&outputs); ++ avfilter_inout_free(&inputs); ++ ++ if (avfilter_graph_config(m_pFilterGraph, NULL) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Init - avfilter_graph_config"); ++ return false; ++ } ++ } ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB || ++ method == VS_INTERLACEMETHOD_NONE) ++ { ++ CLog::Log(LOGDEBUG, "CFFmpegPostproc::Init - no skip deinterlacing"); ++ } ++ else ++ { ++ avfilter_inout_free(&outputs); ++ avfilter_inout_free(&inputs); ++ return false; ++ } ++ m_diMethod = method; ++ ++ m_pFilterFrameIn = av_frame_alloc(); ++ m_pFilterFrameOut = av_frame_alloc(); ++ return true; ++} ++ ++bool CFFmpegPostproc::AddPicture(CVaapiDecodedPicture &inPic) ++{ ++ VASurfaceID surf = inPic.videoSurface; ++ VASurfaceStatus surf_status; ++ VAImage image; ++ uint8_t *buf; ++ if (m_DVDPic.pts != DVD_NOPTS_VALUE && inPic.DVDPic.pts != DVD_NOPTS_VALUE) ++ { ++ m_frametime = inPic.DVDPic.pts - m_DVDPic.pts; ++ } ++ m_DVDPic = inPic.DVDPic; ++ bool result = false; ++ ++ if (!CheckSuccess(vaSyncSurface(m_config.dpy, surf))) ++ goto error; ++ ++ if (!CheckSuccess(vaDeriveImage(m_config.dpy, surf, &image))) ++ goto error; ++ ++ if (!CheckSuccess(vaMapBuffer(m_config.dpy, image.buf, (void**)&buf))) ++ goto error; ++ ++ m_pFilterFrameIn->format = AV_PIX_FMT_NV12; ++ m_pFilterFrameIn->width = m_config.vidWidth; ++ m_pFilterFrameIn->height = m_config.vidHeight; ++ m_pFilterFrameIn->linesize[0] = image.pitches[0]; ++ m_pFilterFrameIn->linesize[1] = image.pitches[1]; ++ m_pFilterFrameIn->interlaced_frame = (inPic.DVDPic.iFlags & DVP_FLAG_INTERLACED) ? 1 : 0; ++ m_pFilterFrameIn->top_field_first = (inPic.DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ? 1 : 0; ++ ++ if (inPic.DVDPic.pts == DVD_NOPTS_VALUE) ++ m_pFilterFrameIn->pkt_pts = AV_NOPTS_VALUE; ++ else ++ m_pFilterFrameIn->pkt_pts = (inPic.DVDPic.pts / DVD_TIME_BASE) * AV_TIME_BASE; ++ ++ av_frame_get_buffer(m_pFilterFrameIn, 64); ++ ++ uint8_t *src, *dst; ++ src = buf + image.offsets[0]; ++ dst = m_pFilterFrameIn->data[0]; ++ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height, image.pitches[0]); ++ ++ src = buf + image.offsets[1]; ++ dst = m_pFilterFrameIn->data[1]; ++ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height/2, image.pitches[1]); ++ ++ m_pFilterFrameIn->linesize[0] = image.pitches[0]; ++ m_pFilterFrameIn->linesize[1] = image.pitches[1]; ++ m_pFilterFrameIn->data[2] = NULL; ++ m_pFilterFrameIn->data[3] = NULL; ++ m_pFilterFrameIn->pkt_size = image.data_size; ++ ++ CheckSuccess(vaUnmapBuffer(m_config.dpy, image.buf)); ++ CheckSuccess(vaDestroyImage(m_config.dpy,image.image_id)); ++ ++ if (m_diMethod == VS_INTERLACEMETHOD_DEINTERLACE) ++ { ++ if (av_buffersrc_add_frame(m_pFilterIn, m_pFilterFrameIn) < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::AddPicture - av_buffersrc_add_frame"); ++ goto error; ++ } ++ } ++ else if (m_diMethod == VS_INTERLACEMETHOD_RENDER_BOB || ++ m_diMethod == VS_INTERLACEMETHOD_NONE) ++ { ++ av_frame_move_ref(m_pFilterFrameOut, m_pFilterFrameIn); ++ m_step = 0; ++ } ++ av_frame_unref(m_pFilterFrameIn); ++ ++ result = true; ++ ++error: ++ m_config.videoSurfaces->ClearRender(surf); ++ return result; ++} ++ ++bool CFFmpegPostproc::Filter(CVaapiProcessedPicture &outPic) ++{ ++ outPic.DVDPic = m_DVDPic; ++ if (m_diMethod == VS_INTERLACEMETHOD_DEINTERLACE) ++ { ++ int result; ++ result = av_buffersink_get_frame(m_pFilterOut, m_pFilterFrameOut); ++ ++ if(result == AVERROR(EAGAIN) || result == AVERROR_EOF) ++ return false; ++ else if(result < 0) ++ { ++ CLog::Log(LOGERROR, "CFFmpegPostproc::Filter - av_buffersink_get_frame"); ++ return false; ++ } ++ outPic.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ } ++ else if (m_diMethod == VS_INTERLACEMETHOD_RENDER_BOB || ++ m_diMethod == VS_INTERLACEMETHOD_NONE) ++ { ++ if (m_step>0) ++ return false; ++ } ++ ++ m_step++; ++ outPic.frame = av_frame_clone(m_pFilterFrameOut); ++ av_frame_unref(m_pFilterFrameOut); ++ ++ outPic.source = CVaapiProcessedPicture::FFMPEG_SRC; ++ ++ if(outPic.frame->pkt_pts != AV_NOPTS_VALUE) ++ { ++ outPic.DVDPic.pts = (double)outPic.frame->pkt_pts * DVD_TIME_BASE / AV_TIME_BASE; ++ } ++ else ++ outPic.DVDPic.pts = DVD_NOPTS_VALUE; ++ ++ double pts = outPic.DVDPic.pts; ++ if (m_lastOutPts != DVD_NOPTS_VALUE && m_lastOutPts == pts) ++ { ++ outPic.DVDPic.pts += m_frametime/2; ++ } ++ m_lastOutPts = pts; ++ ++ for (int i = 0; i < 4; i++) ++ outPic.DVDPic.data[i] = outPic.frame->data[i]; ++ for (int i = 0; i < 4; i++) ++ outPic.DVDPic.iLineSize[i] = outPic.frame->linesize[i]; ++ ++ return true; ++} ++ ++void CFFmpegPostproc::ClearRef(VASurfaceID surf) ++{ ++ ++} ++ ++void CFFmpegPostproc::Close() ++{ ++ if (m_pFilterGraph) ++ { ++ avfilter_graph_free(&m_pFilterGraph); ++ } ++} ++ ++void CFFmpegPostproc::Flush() ++{ ++ Close(); ++ Init(m_diMethod); ++ m_DVDPic.pts = DVD_NOPTS_VALUE; ++ m_frametime = 0; ++ m_lastOutPts = DVD_NOPTS_VALUE; ++} ++ ++bool CFFmpegPostproc::Compatible(EINTERLACEMETHOD method) ++{ ++ if (method == VS_INTERLACEMETHOD_DEINTERLACE) ++ return true; ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) ++ return true; ++ else if (method == VS_INTERLACEMETHOD_NONE && ++ !CSettings::Get().GetBool("videoplayer.prefervaapirender")) ++ return true; ++ ++ return false; ++} ++ ++bool CFFmpegPostproc::CheckSuccess(VAStatus status) ++{ ++ if (status != VA_STATUS_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "VAAPI - Error: %s(%d)", vaErrorStr(status), status); ++ return false; ++ } ++ return true; + } + + #endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +index ec99162..c6193b7 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +@@ -20,127 +20,516 @@ + #pragma once + + #include "system_gl.h" ++#define GLX_GLXEXT_PROTOTYPES ++#include + ++#include "DVDVideoCodec.h" + #include "DVDVideoCodecFFmpeg.h" +-#include +-#include +-#include ++#include "DVDVideoCodec.h" ++#include "DVDVideoCodecFFmpeg.h" ++#include "settings/VideoSettings.h" ++#include "threads/CriticalSection.h" ++#include "threads/SharedSection.h" ++#include "threads/Event.h" ++#include "threads/Thread.h" ++#include "utils/ActorProtocol.h" + #include +-#include ++#include ++#include ++#include "linux/sse4/DllLibSSE4.h" + + extern "C" { ++#include "libavutil/avutil.h" + #include "libavcodec/vaapi.h" + } + +-namespace VAAPI { ++using namespace Actor; + +-typedef boost::shared_ptr VASurfacePtr; + +-struct CDisplay +- : CCriticalSection ++#define FULLHD_WIDTH 1920 ++ ++namespace VAAPI + { +- CDisplay(VADisplay display, bool deinterlace) +- : m_display(display) +- , m_lost(false) +- , m_deinterlace(deinterlace) +- , m_support_4k(true) +- {} +- ~CDisplay(); + +- VADisplay get() { return m_display; } +- bool lost() { return m_lost; } +- void lost(bool lost) { m_lost = lost; } +- bool support_deinterlace() { return m_deinterlace; }; +- bool support_4k() { return m_support_4k; }; +- void support_4k(bool support_4k) { m_support_4k = support_4k; }; ++//----------------------------------------------------------------------------- ++// VAAPI data structs ++//----------------------------------------------------------------------------- ++ ++class CDecoder; ++ ++/** ++ * Buffer statistics used to control number of frames in queue ++ */ ++ ++class CVaapiBufferStats ++{ ++public: ++ uint16_t decodedPics; ++ uint16_t processedPics; ++ uint16_t renderPics; ++ uint64_t latency; // time decoder has waited for a frame, ideally there is no latency ++ int codecFlags; ++ bool canSkipDeint; ++ int processCmd; ++ ++ void IncDecoded() { CSingleLock l(m_sec); decodedPics++;} ++ void DecDecoded() { CSingleLock l(m_sec); decodedPics--;} ++ void IncProcessed() { CSingleLock l(m_sec); processedPics++;} ++ void DecProcessed() { CSingleLock l(m_sec); processedPics--;} ++ void IncRender() { CSingleLock l(m_sec); renderPics++;} ++ void DecRender() { CSingleLock l(m_sec); renderPics--;} ++ void Reset() { CSingleLock l(m_sec); decodedPics=0; processedPics=0;renderPics=0;latency=0;} ++ void Get(uint16_t &decoded, uint16_t &processed, uint16_t &render) {CSingleLock l(m_sec); decoded = decodedPics, processed=processedPics, render=renderPics;} ++ void SetParams(uint64_t time, int flags) { CSingleLock l(m_sec); latency = time; codecFlags = flags; } ++ void GetParams(uint64_t &lat, int &flags) { CSingleLock l(m_sec); lat = latency; flags = codecFlags; } ++ void SetCmd(int cmd) { CSingleLock l(m_sec); processCmd = cmd; } ++ void GetCmd(int &cmd) { CSingleLock l(m_sec); cmd = processCmd; processCmd = 0; } ++ void SetCanSkipDeint(bool canSkip) { CSingleLock l(m_sec); canSkipDeint = canSkip; } ++ bool CanSkipDeint() { CSingleLock l(m_sec); if (canSkipDeint) return true; else return false;} + private: +- VADisplay m_display; +- bool m_lost; +- bool m_deinterlace; +- bool m_support_4k; ++ CCriticalSection m_sec; + }; + +-typedef boost::shared_ptr CDisplayPtr; ++/** ++ * CVaapiConfig holds all configuration parameters needed by vaapi ++ * The structure is sent to the internal classes CMixer and COutput ++ * for init. ++ */ ++ ++class CVideoSurfaces; ++class CVAAPIContext; + +-struct CSurface ++struct CVaapiConfig + { +- CSurface(VASurfaceID id, CDisplayPtr& display) +- : m_id(id) +- , m_display(display) +- {} ++ int surfaceWidth; ++ int surfaceHeight; ++ int vidWidth; ++ int vidHeight; ++ int outWidth; ++ int outHeight; ++ AVRational aspect; ++ VAConfigID configId; ++ VAContextID contextId; ++ CVaapiBufferStats *stats; ++ CDecoder *vaapi; ++ int upscale; ++ CVideoSurfaces *videoSurfaces; ++ int numRenderBuffers; ++ uint32_t maxReferences; ++ bool useInteropYuv; ++ CVAAPIContext *context; ++ VADisplay dpy; ++ VAProfile profile; ++ VAConfigAttrib attrib; ++}; + +- ~CSurface(); ++/** ++ * Holds a decoded frame ++ * Input to COutput for further processing ++ */ ++struct CVaapiDecodedPicture ++{ ++ DVDVideoPicture DVDPic; ++ VASurfaceID videoSurface; ++ int index; ++}; + +- VASurfaceID m_id; +- CDisplayPtr m_display; ++/** ++ * Frame after having been processed by vpp ++ */ ++struct CVaapiProcessedPicture ++{ ++ DVDVideoPicture DVDPic; ++ VASurfaceID videoSurface; ++ AVFrame *frame; ++ enum ++ { ++ VPP_SRC, ++ FFMPEG_SRC, ++ SKIP_SRC ++ }source; ++ bool crop; + }; + +-typedef boost::shared_ptr CSurfacePtr; ++/** ++ * Ready to render textures ++ * Sent from COutput back to CDecoder ++ * Objects are referenced by DVDVideoPicture and are sent ++ * to renderer ++ */ ++class CVaapiRenderPicture ++{ ++ friend class CDecoder; ++ friend class COutput; ++public: ++ CVaapiRenderPicture(CCriticalSection §ion) ++ : texture(None), avFrame(NULL), refCount(0), renderPicSection(section) { fence = None; } ++ void Sync(); ++ DVDVideoPicture DVDPic; ++ int texWidth, texHeight; ++ CRect crop; ++ GLuint texture; ++ bool valid; ++ CDecoder *vaapi; ++ AVFrame *avFrame; ++ CVaapiRenderPicture* Acquire(); ++ long Release(); ++private: ++ void ReturnUnused(); ++ bool usefence; ++ GLsync fence; ++ int refCount; ++ Pixmap pixmap; ++ GLXPixmap glPixmap; ++ CCriticalSection &renderPicSection; ++}; + +-struct CSurfaceGL ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++ ++/** ++ * Buffer pool holds allocated vaapi and gl resources ++ * Embedded in COutput ++ */ ++struct VaapiBufferPool + { +- CSurfaceGL(void* id, CDisplayPtr& display) +- : m_id(id) +- , m_display(display) +- {} +- ~CSurfaceGL(); +- +- void* m_id; +- CDisplayPtr m_display; ++ VaapiBufferPool(); ++ virtual ~VaapiBufferPool(); ++ std::vector allRenderPics; ++ std::deque usedRenderPics; ++ std::deque freeRenderPics; ++ std::deque syncRenderPics; ++ std::deque processedPics; ++ std::deque decodedPics; ++ CCriticalSection renderPicSec; + }; + +-typedef boost::shared_ptr CSurfaceGLPtr; ++class COutputControlProtocol : public Protocol ++{ ++public: ++ COutputControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT, ++ FLUSH, ++ PRECLEANUP, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ STATS, ++ }; ++}; + +-// silly type to avoid includes +-struct CHolder ++class COutputDataProtocol : public Protocol + { +- CDisplayPtr display; +- CSurfacePtr surface; +- CSurfaceGLPtr surfglx; ++public: ++ COutputDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWFRAME = 0, ++ RETURNPIC, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; + +- CHolder() +- {} ++struct SDiMethods ++{ ++ EINTERLACEMETHOD diMethods[8]; ++ int numDiMethods; + }; + ++/** ++ * COutput is embedded in CDecoder and embeds vpp ++ * The class has its own OpenGl context which is shared with render thread ++ * COuput generated ready to render textures and passes them back to ++ * CDecoder ++ */ ++class CPostproc; ++ ++class COutput : private CThread ++{ ++public: ++ COutput(CEvent *inMsgEvent); ++ virtual ~COutput(); ++ void Start(); ++ void Dispose(); ++ COutputControlProtocol m_controlPort; ++ COutputDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ bool HasWork(); ++ void InitCycle(); ++ CVaapiRenderPicture* ProcessPicture(CVaapiProcessedPicture &pic); ++ void QueueReturnPicture(CVaapiRenderPicture *pic); ++ void ProcessReturnPicture(CVaapiRenderPicture *pic); ++ bool ProcessSyncPicture(); ++ void ReleaseProcessedPicture(CVaapiProcessedPicture &pic); ++ void DropVppProcessedPictures(); ++ bool Init(); ++ bool Uninit(); ++ void Flush(); ++ bool CreateGlxContext(); ++ bool DestroyGlxContext(); ++ bool EnsureBufferPool(); ++ void ReleaseBufferPool(bool precleanup = false); ++ bool GLInit(); ++ bool CheckSuccess(VAStatus status); ++ PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; ++ PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_vaError; ++ CVaapiConfig m_config; ++ VaapiBufferPool m_bufferPool; ++ Display *m_Display; ++ Window m_Window; ++ GLXContext m_glContext; ++ GLXWindow m_glWindow; ++ Pixmap m_pixmap; ++ GLXPixmap m_glPixmap; ++ CVaapiDecodedPicture m_currentPicture; ++ GLenum m_textureTarget; ++ CPostproc *m_pp; ++ SDiMethods m_diMethods; ++ EINTERLACEMETHOD m_currentDiMethod; ++}; ++ ++//----------------------------------------------------------------------------- ++// VAAPI Video Surface states ++//----------------------------------------------------------------------------- ++ ++class CVideoSurfaces ++{ ++public: ++ void AddSurface(VASurfaceID surf); ++ void ClearReference(VASurfaceID surf); ++ bool MarkRender(VASurfaceID surf); ++ void ClearRender(VASurfaceID surf); ++ bool IsValid(VASurfaceID surf); ++ VASurfaceID GetFree(VASurfaceID surf); ++ VASurfaceID GetAtIndex(int idx); ++ VASurfaceID RemoveNext(bool skiprender = false); ++ void Reset(); ++ int Size(); ++ bool HasFree(); ++protected: ++ std::map m_state; ++ std::list m_freeSurfaces; ++ CCriticalSection m_section; ++}; ++ ++//----------------------------------------------------------------------------- ++// VAAPI decoder ++//----------------------------------------------------------------------------- ++ ++class CVAAPIContext ++{ ++public: ++ static bool EnsureContext(CVAAPIContext **ctx, CDecoder *decoder); ++ void Release(CDecoder *decoder); ++ VADisplay GetDisplay(); ++ bool SupportsProfile(VAProfile profile); ++ VAConfigAttrib GetAttrib(VAProfile profile); ++ VAConfigID CreateConfig(VAProfile profile, VAConfigAttrib attrib); ++ static void FFReleaseBuffer(void *opaque, uint8_t *data); ++private: ++ CVAAPIContext(); ++ void Close(); ++ bool CreateContext(); ++ void DestroyContext(); ++ void QueryCaps(); ++ bool CheckSuccess(VAStatus status); ++ bool IsValidDecoder(CDecoder *decoder); ++ static CVAAPIContext *m_context; ++ static CCriticalSection m_section; ++ static Display *m_X11dpy; ++ VADisplay m_display; ++ int m_refCount; ++ int m_attributeCount; ++ VADisplayAttribute *m_attributes; ++ int m_profileCount; ++ VAProfile *m_profiles; ++ std::vector m_decoders; ++}; ++ ++/** ++ * VAAPI main class ++ */ + class CDecoder +- : public CDVDVideoCodecFFmpeg::IHardwareDecoder ++ : public CDVDVideoCodecFFmpeg::IHardwareDecoder + { +- bool EnsureContext(AVCodecContext *avctx); +- bool EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count); ++ friend class CVaapiRenderPicture; ++ + public: ++ + CDecoder(); +- ~CDecoder(); ++ virtual ~CDecoder(); ++ + virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces = 0); + 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 long Release(); ++ virtual bool CanSkipDeint(); ++ virtual unsigned GetAllowedReferences() { return 5; } ++ ++ virtual int Check(AVCodecContext* avctx); + virtual const std::string Name() { return "vaapi"; } +- virtual CCriticalSection* Section() { if(m_display) return m_display.get(); else return NULL; } +- virtual unsigned GetAllowedReferences(); + +- int GetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags); +- void RelBuffer(uint8_t *data); ++ bool Supports(EINTERLACEMETHOD method); ++ EINTERLACEMETHOD AutoInterlaceMethod(); ++ ++ void FFReleaseBuffer(uint8_t *data); ++ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags); + +- 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; ++ void SetWidthHeight(int width, int height); ++ bool ConfigVAAPI(); ++ bool CheckStatus(VAStatus vdp_st, int line); ++ void FiniVAAPIOutput(); ++ void ReturnRenderPicture(CVaapiRenderPicture *renderPic); ++ long ReleasePicReference(); ++ bool CheckSuccess(VAStatus status); ++ ++ enum EDisplayState ++ { VAAPI_OPEN ++ , VAAPI_RESET ++ , VAAPI_LOST ++ , VAAPI_ERROR ++ } m_DisplayState; ++ CCriticalSection m_DecoderSection; ++ CEvent m_DisplayEvent; ++ int m_ErrorCount; ++ ++ ThreadIdentifier m_decoderThread; ++ bool m_vaapiConfigured; ++ CVaapiConfig m_vaapiConfig; ++ CVideoSurfaces m_videoSurfaces; ++ vaapi_context m_hwContext; ++ ++ COutput m_vaapiOutput; ++ CVaapiBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CVaapiRenderPicture *m_presentPicture; ++ ++ int m_codecControl; ++ std::vector m_diMethods; ++}; + +- int m_refs; +- std::list m_surfaces_used; +- std::list m_surfaces_free; ++//----------------------------------------------------------------------------- ++// Postprocessing ++//----------------------------------------------------------------------------- + +- CDisplayPtr m_display; +- VAConfigID m_config; +- VAContextID m_context; ++/** ++ * Base class ++ */ ++class CPostproc ++{ ++public: ++ virtual ~CPostproc() {}; ++ virtual bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL) = 0; ++ virtual bool Init(EINTERLACEMETHOD method) = 0; ++ virtual bool AddPicture(CVaapiDecodedPicture &inPic) = 0; ++ virtual bool Filter(CVaapiProcessedPicture &outPic) = 0; ++ virtual void ClearRef(VASurfaceID surf) = 0; ++ virtual void Flush() = 0; ++ virtual bool Compatible(EINTERLACEMETHOD method) = 0; ++protected: ++ CVaapiConfig m_config; ++ int m_step; ++}; + +- vaapi_context *m_hwaccel; ++/** ++ * skip post processing ++ */ ++class CSkipPostproc : public CPostproc ++{ ++public: ++ bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL); ++ bool Init(EINTERLACEMETHOD method); ++ bool AddPicture(CVaapiDecodedPicture &inPic); ++ bool Filter(CVaapiProcessedPicture &outPic); ++ void ClearRef(VASurfaceID surf); ++ void Flush(); ++ bool Compatible(EINTERLACEMETHOD method); ++protected: ++ CVaapiDecodedPicture m_pic; ++}; + +- CHolder m_holder; // silly struct to pass data to renderer ++/** ++ * VAAPI post processing ++ */ ++class CVppPostproc : public CPostproc ++{ ++public: ++ CVppPostproc(); ++ virtual ~CVppPostproc(); ++ bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL); ++ bool Init(EINTERLACEMETHOD method); ++ bool AddPicture(CVaapiDecodedPicture &inPic); ++ bool Filter(CVaapiProcessedPicture &outPic); ++ void ClearRef(VASurfaceID surf); ++ void Flush(); ++ bool Compatible(EINTERLACEMETHOD method); ++protected: ++ bool CheckSuccess(VAStatus status); ++ void Dispose(); ++ void Advance(); ++ VAConfigID m_configId; ++ VAContextID m_contextId; ++ CVideoSurfaces m_videoSurfaces; ++ std::deque m_decodedPics; ++ VABufferID m_filter; ++ int m_forwardRefs, m_backwardRefs; ++ int m_currentIdx; ++ int m_frameCount; ++}; ++ ++/** ++ * ffmpeg filter ++ */ ++class CFFmpegPostproc : public CPostproc ++{ ++public: ++ CFFmpegPostproc(); ++ virtual ~CFFmpegPostproc(); ++ bool PreInit(CVaapiConfig &config, SDiMethods *methods = NULL); ++ bool Init(EINTERLACEMETHOD method); ++ bool AddPicture(CVaapiDecodedPicture &inPic); ++ bool Filter(CVaapiProcessedPicture &outPic); ++ void ClearRef(VASurfaceID surf); ++ void Flush(); ++ bool Compatible(EINTERLACEMETHOD method); ++protected: ++ bool CheckSuccess(VAStatus status); ++ void Close(); ++ DllLibSSE4 m_dllSSE4; ++ uint8_t *m_cache; ++ AVFilterGraph* m_pFilterGraph; ++ AVFilterContext* m_pFilterIn; ++ AVFilterContext* m_pFilterOut; ++ AVFrame *m_pFilterFrameIn; ++ AVFrame *m_pFilterFrameOut; ++ EINTERLACEMETHOD m_diMethod; ++ DVDVideoPicture m_DVDPic; ++ double m_frametime; ++ double m_lastOutPts; + }; + + } +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 29ffb19..b928436 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1011,6 +1011,7 @@ static std::string GetRenderFormatName(ERenderFormat format) + case RENDER_FMT_VDPAU_420: return "VDPAU_420"; + case RENDER_FMT_DXVA: return "DXVA"; + case RENDER_FMT_VAAPI: return "VAAPI"; ++ case RENDER_FMT_VAAPINV12: return "VAAPI_NV12"; + case RENDER_FMT_OMXEGL: return "OMXEGL"; + case RENDER_FMT_CVBREF: return "BGRA"; + case RENDER_FMT_EGLIMG: return "EGLIMG"; +diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h +index 32a2e8d..88434a4 100644 +--- a/xbmc/settings/VideoSettings.h ++++ b/xbmc/settings/VideoSettings.h +@@ -63,6 +63,10 @@ enum EINTERLACEMETHOD + VS_INTERLACEMETHOD_SW_BLEND = 20, + VS_INTERLACEMETHOD_AUTO_ION = 21, + ++ VS_INTERLACEMETHOD_VAAPI_BOB = 22, ++ VS_INTERLACEMETHOD_VAAPI_MADI = 23, ++ VS_INTERLACEMETHOD_VAAPI_MACI = 24, ++ + 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 e194229..1e21591 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -264,6 +264,9 @@ void CGUIDialogVideoSettings::InitializeSettings() + entries.push_back(make_pair(16320, VS_INTERLACEMETHOD_DXVA_BOB)); + entries.push_back(make_pair(16321, VS_INTERLACEMETHOD_DXVA_BEST)); + entries.push_back(make_pair(16325, VS_INTERLACEMETHOD_AUTO_ION)); ++ entries.push_back(make_pair(16327, VS_INTERLACEMETHOD_VAAPI_BOB)); ++ entries.push_back(make_pair(16328, VS_INTERLACEMETHOD_VAAPI_MADI)); ++ entries.push_back(make_pair(16329, VS_INTERLACEMETHOD_VAAPI_MACI)); + + /* remove unsupported methods */ + for (StaticIntegerSettingOptions::iterator it = entries.begin(); it != entries.end(); ) +-- +1.9.3 + + +From 706d0a492031b24e35db5e6e6469b0d4c4d9c5bb Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 29 Jun 2014 14:45:28 +0200 +Subject: [PATCH 21/22] VAAPI: Don't use swfilter for large surfaces - fallback + to vaapi render + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 34 ++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 93be338..4e1b136 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -1689,12 +1689,18 @@ void COutput::InitCycle() + m_pp->Init(method); + m_currentDiMethod = method; + } ++ else ++ { ++ delete m_pp; ++ m_pp = NULL; ++ } + } + } + // progressive + else + { +- if (m_pp && !m_pp->Compatible(VS_INTERLACEMETHOD_NONE)) ++ method = VS_INTERLACEMETHOD_NONE; ++ if (m_pp && !m_pp->Compatible(method)) + { + delete m_pp; + m_pp = NULL; +@@ -1702,16 +1708,27 @@ void COutput::InitCycle() + } + if (!m_pp) + { +- if (CSettings::Get().GetBool("videoplayer.prefervaapirender")) +- m_pp = new CSkipPostproc(); +- else ++ if (!CSettings::Get().GetBool("videoplayer.prefervaapirender")) + m_pp = new CFFmpegPostproc(); ++ else ++ m_pp = new CSkipPostproc(); + if (m_pp->PreInit(m_config)) + { +- m_pp->Init(VS_INTERLACEMETHOD_NONE); ++ m_pp->Init(method); ++ } ++ else ++ { ++ delete m_pp; ++ m_pp = NULL; + } + } + } ++ if (!m_pp) // fallback ++ { ++ m_pp = new CSkipPostproc(); ++ if (m_pp->PreInit(m_config)) ++ m_pp->Init(method); ++ } + } + + CVaapiRenderPicture* COutput::ProcessPicture(CVaapiProcessedPicture &pic) +@@ -2727,6 +2744,13 @@ bool CFFmpegPostproc::PreInit(CVaapiConfig &config, SDiMethods *methods) + CLog::Log(LOGNOTICE,"VAAPI::SupportsFilter failed loading sse4 lib"); + return false; + } ++ ++ // copying large surfaces via sse4 is a bit slow ++ // we just return false here as the primary use case the ++ // sse4 copy method is deinterlacing of max 1080i content ++ if (m_config.vidWidth > 1920 || m_config.vidHeight > 1088) ++ return false; ++ + VAImage image; + VASurfaceID surface = config.videoSurfaces->GetAtIndex(0); + VAStatus status = vaDeriveImage(config.dpy, surface, &image); +-- +1.9.3 + + +From 0a2db7ebdf9b6545c8ff4a4854f5d4639c623993 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 29 Jun 2014 16:21:44 +0200 +Subject: [PATCH 22/22] VAAPI: Fix fallback condition + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 4e1b136..92b2f97 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -2264,8 +2264,7 @@ void CSkipPostproc::Flush() + + bool CSkipPostproc::Compatible(EINTERLACEMETHOD method) + { +- if (method == VS_INTERLACEMETHOD_NONE && +- CSettings::Get().GetBool("videoplayer.prefervaapirender")) ++ if (method == VS_INTERLACEMETHOD_NONE) + return true; + + return false; -- 1.9.3 diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-999.91-patch_for_6322457.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.91-patch_for_6322457.patch new file mode 100644 index 0000000000..11dede9c9a --- /dev/null +++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.91-patch_for_6322457.patch @@ -0,0 +1,12 @@ +diff -Naur xbmc-master-14-687ac52/xbmc/dialogs/GUIDialogSeekBar.cpp xbmc-master-14-687ac52.patch/xbmc/dialogs/GUIDialogSeekBar.cpp +--- xbmc-master-14-687ac52/xbmc/dialogs/GUIDialogSeekBar.cpp 2014-07-06 16:16:21.000000000 +0200 ++++ xbmc-master-14-687ac52.patch/xbmc/dialogs/GUIDialogSeekBar.cpp 2014-07-06 19:45:14.102908695 +0200 +@@ -68,7 +68,7 @@ + } + + // update controls +- if (!g_application.GetSeekHandler()->InProgress() && !g_infoManager.m_performingSeek) ++ if (!g_application.GetSeekHandler()->InProgress() && !g_infoManager.m_performingSeek && g_infoManager.GetTotalPlayTime()) + { // position the bar at our current time + CONTROL_SELECT_ITEM(POPUP_SEEK_LABEL, (unsigned int)(g_infoManager.GetPlayTime()/g_infoManager.GetTotalPlayTime() * 0.1f)); + SET_CONTROL_LABEL(POPUP_SEEK_LABEL, g_infoManager.GetCurrentPlayTime());