Files
LibreELEC.tv/projects/RPi/patches/xbmc/xbmc-001-newclock4.patch
2014-10-05 16:12:48 +02:00

11741 lines
460 KiB
Diff

From cf3fb928d3e89202c8c64ace9460676d6284e561 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 18 Aug 2014 17:48:04 +0100
Subject: [PATCH 01/99] omxplayer: Reset codec on flush to stop a stale
timestamp from being returned
---
xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
index f1208e6..01d2afc 100644
--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
@@ -490,6 +490,8 @@ void OMXPlayerAudio::Process()
void OMXPlayerAudio::Flush()
{
m_flush = true;
+ if(m_pAudioCodec)
+ m_pAudioCodec->Reset();
m_messageQueue.Flush();
m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
}
From dfb8943208c17327c3ef1040c6e7b018b501925d Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 7 Apr 2014 18:19:32 +0100
Subject: [PATCH 02/99] [rbp/omxplayer] When opening a stream don't try to
update gui so often
---
xbmc/dialogs/GUIDialogBusy.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xbmc/dialogs/GUIDialogBusy.cpp b/xbmc/dialogs/GUIDialogBusy.cpp
index e7cfcdd..20b99ad 100644
--- a/xbmc/dialogs/GUIDialogBusy.cpp
+++ b/xbmc/dialogs/GUIDialogBusy.cpp
@@ -68,7 +68,11 @@ bool CGUIDialogBusy::WaitOnEvent(CEvent &event, unsigned int displaytime /* = 10
if (dialog)
{
dialog->Show();
+#ifdef TARGET_RASPBERRY_PI
+ while(!event.WaitMSec(100))
+#else
while(!event.WaitMSec(1))
+#endif
{
g_windowManager.ProcessRenderLoop(false);
if (allowCancel && dialog->IsCanceled())
From 83739b52ad8654b3245ff41343dd5900c975b312 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 29 Apr 2014 15:23:22 +0100
Subject: [PATCH 03/99] [ffmpeg] Speed up wtv index creation
The index creation is O(N^2) with number of entries (typically thousands).
On a Pi this can take more than 60 seconds to execute for a recording of a few hours.
By replacing with an O(N) loop, this takes virtually zero time
---
tools/depends/target/ffmpeg/Makefile | 3 +-
.../ffmpeg_Speed_up_wtv_index_creation.patch | 47 ++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
create mode 100644 tools/depends/target/ffmpeg/ffmpeg_Speed_up_wtv_index_creation.patch
diff --git a/tools/depends/target/ffmpeg/Makefile b/tools/depends/target/ffmpeg/Makefile
index 0e08dcf..7ce982c 100644
--- a/tools/depends/target/ffmpeg/Makefile
+++ b/tools/depends/target/ffmpeg/Makefile
@@ -1,6 +1,6 @@
include ../../Makefile.include
include FFMPEG-VERSION
-DEPS= ../../Makefile.include FFMPEG-VERSION Makefile
+DEPS= ../../Makefile.include FFMPEG-VERSION Makefile ffmpeg_Speed_up_wtv_index_creation.patch
# set to "yes" to enable patching
# we don't apply patches until we move to a vanilla ffmpeg tarball
@@ -63,6 +63,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS)
rm -rf $(PLATFORM); mkdir -p $(PLATFORM)
cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
cd $(PLATFORM); sed -i".bak" -e "s%pkg_config_default=pkg-config%export PKG_CONFIG_LIBDIR=$(PREFIX)/lib/pkgconfig \&\& pkg_config_default=$(NATIVEPREFIX)/bin/pkg-config%" configure
+ cd $(PLATFORM); patch -p3 < ../ffmpeg_Speed_up_wtv_index_creation.patch
cd $(PLATFORM);\
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \
./configure $(ffmpg_config)
diff --git a/tools/depends/target/ffmpeg/ffmpeg_Speed_up_wtv_index_creation.patch b/tools/depends/target/ffmpeg/ffmpeg_Speed_up_wtv_index_creation.patch
new file mode 100644
index 0000000..4ac5636
--- /dev/null
+++ b/tools/depends/target/ffmpeg/ffmpeg_Speed_up_wtv_index_creation.patch
@@ -0,0 +1,47 @@
+commit 0e7427498cb1131671f6fe9d054245ae7e5a36f5
+Author: popcornmix <popcornmix@gmail.com>
+Date: Tue Mar 25 19:43:07 2014 +0000
+
+ [ffmpeg] Speed up wtv index creation
+
+ The index creation is O(N^2) with number of entries (typically thousands).
+ On a Pi this can take more than 60 seconds to execute for a recording of a few hours.
+
+ By replacing with an O(N) loop, this takes virtually zero time
+
+diff --git a/lib/ffmpeg/libavformat/wtvdec.c b/lib/ffmpeg/libavformat/wtvdec.c
+index e423370..70898bd 100644
+--- a/lib/ffmpeg/libavformat/wtvdec.c
++++ b/lib/ffmpeg/libavformat/wtvdec.c
+@@ -980,21 +980,23 @@ static int read_header(AVFormatContext *s)
+ pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
+ if (pb) {
+ int i;
++ AVIndexEntry *e = wtv->index_entries;
++ AVIndexEntry *e_end = wtv->index_entries + wtv->nb_index_entries - 1;
++ uint64_t last_position = 0;
+ while (1) {
+ uint64_t frame_nb = avio_rl64(pb);
+ uint64_t position = avio_rl64(pb);
++ while (frame_nb > e->size && e <= e_end) {
++ e->pos = last_position;
++ e++;
++ }
+ if (avio_feof(pb))
+ break;
+- for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
+- AVIndexEntry *e = wtv->index_entries + i;
+- if (frame_nb > e->size)
+- break;
+- if (position > e->pos)
+- e->pos = position;
+- }
++ last_position = position;
+ }
++ e_end->pos = last_position;
+ wtvfile_close(pb);
+- st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
++ st->duration = e_end->timestamp;
+ }
+ }
+ }
From d8bcb56bcfb580860e3e0dc26c94ee9c80f643e9 Mon Sep 17 00:00:00 2001
From: Jonathan Marshall <jmarshall@xbmc.org>
Date: Sat, 2 Nov 2013 23:49:17 +1300
Subject: [PATCH 04/99] adds GetTvShowSeasons
---
xbmc/video/VideoDatabase.cpp | 30 ++++++++++++++++++++++++------
xbmc/video/VideoDatabase.h | 1 +
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp
index 769bf30..a6e9efa 100644
--- a/xbmc/video/VideoDatabase.cpp
+++ b/xbmc/video/VideoDatabase.cpp
@@ -4213,7 +4213,7 @@ bool CVideoDatabase::RemoveArtForItem(int mediaId, const MediaType &mediaType, c
return result;
}
-bool CVideoDatabase::GetTvShowSeasonArt(int showId, map<int, map<string, string> > &seasonArt)
+bool CVideoDatabase::GetTvShowSeasons(int showId, map<int, int> &seasons)
{
try
{
@@ -4224,19 +4224,37 @@ bool CVideoDatabase::GetTvShowSeasonArt(int showId, map<int, map<string, string>
CStdString sql = PrepareSQL("select idSeason,season from seasons where idShow=%i", showId);
m_pDS2->query(sql.c_str());
- vector< pair<int, int> > seasons;
+ seasons.clear();
while (!m_pDS2->eof())
{
- seasons.push_back(make_pair(m_pDS2->fv(0).get_asInt(), m_pDS2->fv(1).get_asInt()));
+ seasons.insert(make_pair(m_pDS2->fv(1).get_asInt(), m_pDS2->fv(0).get_asInt()));
m_pDS2->next();
}
m_pDS2->close();
+ return true;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s(%d) failed", __FUNCTION__, showId);
+ }
+ return false;
+}
+
+bool CVideoDatabase::GetTvShowSeasonArt(int showId, map<int, map<string, string> > &seasonArt)
+{
+ try
+ {
+ if (NULL == m_pDB.get()) return false;
+ if (NULL == m_pDS2.get()) return false; // using dataset 2 as we're likely called in loops on dataset 1
+
+ map<int, int> seasons;
+ GetTvShowSeasons(showId, seasons);
- for (vector< pair<int,int> >::const_iterator i = seasons.begin(); i != seasons.end(); ++i)
+ for (map<int, int>::const_iterator i = seasons.begin(); i != seasons.end(); ++i)
{
map<string, string> art;
- GetArtForItem(i->first, MediaTypeSeason, art);
- seasonArt.insert(make_pair(i->second,art));
+ GetArtForItem(i->second, MediaTypeSeason, art);
+ seasonArt.insert(make_pair(i->first,art));
}
return true;
}
diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h
index 78259ed..cbb26b7 100644
--- a/xbmc/video/VideoDatabase.h
+++ b/xbmc/video/VideoDatabase.h
@@ -746,6 +746,7 @@ class CVideoDatabase : public CDatabase
std::string GetArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType);
bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType);
bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::set<std::string> &artTypes);
+ bool GetTvShowSeasons(int showId, std::map<int, int> &seasons);
bool GetTvShowSeasonArt(int mediaId, std::map<int, std::map<std::string, std::string> > &seasonArt);
bool GetArtTypes(const MediaType &mediaType, std::vector<std::string> &artTypes);
From 5389ca816eccfe0b3eef345d904f3e104614b8c9 Mon Sep 17 00:00:00 2001
From: Jonathan Marshall <jmarshall@xbmc.org>
Date: Sat, 2 Nov 2013 23:50:10 +1300
Subject: [PATCH 05/99] move AddSeason() public.
---
xbmc/video/VideoDatabase.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h
index cbb26b7..1a79c00 100644
--- a/xbmc/video/VideoDatabase.h
+++ b/xbmc/video/VideoDatabase.h
@@ -757,6 +757,7 @@ class CVideoDatabase : public CDatabase
virtual bool GetFilter(CDbUrl &videoUrl, Filter &filter, SortDescription &sorting);
+ int AddSeason(int showID, int season);
int AddSet(const CStdString& strSet);
void ClearMovieSet(int idMovie);
void SetMovieSet(int idMovie, int idSet);
@@ -787,7 +788,6 @@ class CVideoDatabase : public CDatabase
int AddTvShow();
int AddMusicVideo(const CStdString& strFilenameAndPath);
- int AddSeason(int showID, int season);
/*! \brief Adds a path to the tvshow link table.
\param idShow the id of the show.
From 96dac4a1e5c700d091fd7dba8d13dace8b914ab4 Mon Sep 17 00:00:00 2001
From: Jonathan Marshall <jmarshall@xbmc.org>
Date: Sat, 2 Nov 2013 23:48:24 +1300
Subject: [PATCH 06/99] adds GetArt function to (video) scraper, allowing art
to be fetched given the video identifier.
---
xbmc/addons/Scraper.cpp | 38 ++++++++++++++++++++++++++++++++++++++
xbmc/addons/Scraper.h | 3 +++
xbmc/video/VideoInfoDownloader.cpp | 5 +++++
xbmc/video/VideoInfoDownloader.h | 7 +++++++
4 files changed, 53 insertions(+)
diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp
index 76d5248..f3f2930 100644
--- a/xbmc/addons/Scraper.cpp
+++ b/xbmc/addons/Scraper.cpp
@@ -924,6 +924,44 @@ EPISODELIST CScraper::GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl
return vcep;
}
+// takes URL; returns true and populates art XML details on success, false otherwise
+bool CScraper::GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video)
+{
+ CLog::Log(LOGDEBUG, "%s: Reading art for '%s' using %s scraper "
+ "(file: '%s', content: '%s', version: '%s')", __FUNCTION__, id.c_str(), Name().c_str(), Path().c_str(),
+ ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
+
+ video.Reset();
+ vector<string> vcsIn;
+ CScraperUrl scurl;
+ vcsIn.push_back(id);
+ vector<string> vcsOut = RunNoThrow("GetArt", scurl, fcurl, &vcsIn);
+
+ // parse XML output
+ bool fRet(false);
+ for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
+ {
+ CXBMCTinyXML doc;
+ doc.Parse(*i, TIXML_ENCODING_UTF8);
+ if (!doc.RootElement())
+ {
+ CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
+ continue;
+ }
+
+ TiXmlHandle xhDoc(&doc);
+ TiXmlElement *pxeDetails = xhDoc.FirstChild("details").Element();
+ if (!pxeDetails)
+ {
+ CLog::Log(LOGERROR, "%s: Invalid XML file (want <details>)", __FUNCTION__);
+ continue;
+ }
+ video.Load(pxeDetails, true/*fChain*/);
+ fRet = true; // but don't exit in case of chaining
+ }
+ return fRet;
+}
+
// takes URL; returns true and populates video details on success, false otherwise
bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
bool fMovie/*else episode*/, CVideoInfoTag &video)
diff --git a/xbmc/addons/Scraper.h b/xbmc/addons/Scraper.h
index c7274f2..5df5296 100644
--- a/xbmc/addons/Scraper.h
+++ b/xbmc/addons/Scraper.h
@@ -18,6 +18,8 @@
* <http://www.gnu.org/licenses/>.
*
*/
+
+#include <string>
#include "addons/Addon.h"
#include "XBDateTime.h"
#include "utils/ScraperUrl.h"
@@ -146,6 +148,7 @@ class CScraper : public CAddon
CAlbum &album);
bool GetArtistDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
const std::string &sSearch, CArtist &artist);
+ bool GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video);
private:
CScraper(const CScraper &rhs);
diff --git a/xbmc/video/VideoInfoDownloader.cpp b/xbmc/video/VideoInfoDownloader.cpp
index f33ac8a..5d84734 100644
--- a/xbmc/video/VideoInfoDownloader.cpp
+++ b/xbmc/video/VideoInfoDownloader.cpp
@@ -191,6 +191,11 @@ bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url,
return m_info->GetVideoDetails(*m_http, url, true/*fMovie*/, movieDetails);
}
+bool CVideoInfoDownloader::GetArt(const std::string &id, CVideoInfoTag &details)
+{
+ return m_info->GetArt(*m_http, id, details);
+}
+
bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url,
CVideoInfoTag &movieDetails,
CGUIDialogProgress *pProgress /* = NULL */)
diff --git a/xbmc/video/VideoInfoDownloader.h b/xbmc/video/VideoInfoDownloader.h
index 22ac229..75bc341 100644
--- a/xbmc/video/VideoInfoDownloader.h
+++ b/xbmc/video/VideoInfoDownloader.h
@@ -59,6 +59,13 @@ class CVideoInfoDownloader : public CThread
static void ShowErrorDialog(const ADDON::CScraperError &sce);
+ /*! \brief Grab art URLs for an item with the scraper
+ \param id the unique identifier used by the scraper to describe the item.
+ \param details [out] the video info tag structure to fill with art.
+ \return true on success, false on failure.
+ */
+ bool GetArt(const std::string &id, CVideoInfoTag &details);
+
protected:
enum LOOKUP_STATE { DO_NOTHING = 0,
FIND_MOVIE = 1,
From 9e2ba737076ae127290a5e4abc6d9599d1c2cd1c Mon Sep 17 00:00:00 2001
From: Jonathan Marshall <jmarshall@xbmc.org>
Date: Sat, 2 Nov 2013 23:53:14 +1300
Subject: [PATCH 07/99] refresh season art if a new season is found that isn't
recorded in the database yet. Fixes #14339
---
xbmc/video/VideoInfoScanner.cpp | 33 ++++++++++++++++++++++++++++++++-
xbmc/video/VideoInfoScanner.h | 2 ++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp
index 04e578b..b86746a 100644
--- a/xbmc/video/VideoInfoScanner.cpp
+++ b/xbmc/video/VideoInfoScanner.cpp
@@ -1360,6 +1360,10 @@ namespace VIDEO
pDlgProgress->Progress();
}
+ bool updateSeasons = false;
+ map<int, int> seasons;
+ m_database.GetTvShowSeasons(showInfo.m_iDbId, seasons);
+
EPISODELIST episodes;
bool hasEpisodeGuide = false;
@@ -1408,6 +1412,8 @@ namespace VIDEO
}
if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, true, &showInfo) < 0)
return INFO_ERROR;
+ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end())
+ updateSeasons = true;
continue;
}
@@ -1537,6 +1543,8 @@ namespace VIDEO
if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, useLocal, &showInfo) < 0)
return INFO_ERROR;
+ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end())
+ updateSeasons = true;
}
else
{
@@ -1545,9 +1553,27 @@ namespace VIDEO
file->cDate.GetAsLocalizedDate().c_str(), file->strTitle.c_str());
}
}
+ if (updateSeasons)
+ UpdateSeasons(showInfo, scraper, useLocal);
return INFO_ADDED;
}
+ void CVideoInfoScanner::UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal)
+ {
+ map<int, map<string, string> > seasonArt;
+ m_database.GetTvShowSeasonArt(showInfo.m_iDbId, seasonArt);
+ CVideoInfoTag details;
+ CVideoInfoDownloader loader(scraper);
+ loader.GetArt(showInfo.m_strIMDBNumber, details);
+ details.m_strPath = showInfo.m_strPath;
+ GetSeasonThumbs(details, seasonArt, CVideoThumbLoader::GetArtTypes("season"), useLocal);
+ for (map<int, map<string, string> >::iterator i = seasonArt.begin(); i != seasonArt.end(); ++i)
+ {
+ int seasonID = m_database.AddSeason(showInfo.m_iDbId, i->first);
+ m_database.SetArtForItem(seasonID, "season", i->second);
+ }
+ }
+
CStdString CVideoInfoScanner::GetnfoFile(CFileItem *item, bool bGrabAny) const
{
CStdString nfoFile;
@@ -1812,6 +1838,11 @@ namespace VIDEO
}
for (int season = -1; season <= maxSeasons; season++)
{
+ // skip if we already have some art
+ map<int, map<string, string> >::const_iterator i = seasonArt.find(season);
+ if (i != seasonArt.end() && !i->second.empty())
+ continue;
+
map<string, string> art;
if (useLocal)
{
@@ -1865,7 +1896,7 @@ namespace VIDEO
art.insert(make_pair(artTypes.front(), image));
}
- seasonArt.insert(make_pair(season, art));
+ seasonArt[season] = art;
}
}
diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h
index 7da1bf2..c764e20 100644
--- a/xbmc/video/VideoInfoScanner.h
+++ b/xbmc/video/VideoInfoScanner.h
@@ -230,6 +230,8 @@ namespace VIDEO
*/
INFO_RET OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, const CVideoInfoTag& showInfo, CGUIDialogProgress* pDlgProgress = NULL);
+ void UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal);
+
bool EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList);
bool ProcessItemByVideoInfoTag(const CFileItem *item, EPISODELIST &episodeList);
From 3f7128d405004113fcc237427a35ae423ab89a2f Mon Sep 17 00:00:00 2001
From: Jonathan Marshall <jmarshall@xbmc.org>
Date: Sat, 2 Nov 2013 23:53:34 +1300
Subject: [PATCH 08/99] REMOVEME: updated thetvdb.com scraper to support art
updates
---
addons/metadata.tvdb.com/tvdb.xml | 59 +++++++++++++++++++++++++--------------
1 file changed, 38 insertions(+), 21 deletions(-)
diff --git a/addons/metadata.tvdb.com/tvdb.xml b/addons/metadata.tvdb.com/tvdb.xml
index f27e4fc..bdf329f 100644
--- a/addons/metadata.tvdb.com/tvdb.xml
+++ b/addons/metadata.tvdb.com/tvdb.xml
@@ -102,57 +102,74 @@
<RegExp input="$$5" output="&lt;actor&gt;&lt;name&gt;\2&lt;/name&gt;&lt;role&gt;\3&lt;/role&gt;&lt;/actor&gt;" dest="4+">
<expression repeat="yes" noclean="1,2,3">&lt;Actor&gt;.*?&lt;Image&gt;([^&lt;]*)&lt;/Image&gt;.*?&lt;Name&gt;([^&lt;]*)&lt;/Name&gt;.*?&lt;Role&gt;([^&lt;]*)</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$2" output="&lt;chain function=&quot;GetArt&quot;&gt;\1&lt;/chain&gt;" dest="4+">
+ <expression/>
+ </RegExp>
+ <RegExp input="$$3" output="\1" dest="6">
+ <expression>.*/(.*).zip</expression>
+ </RegExp>
+ <RegExp input="$$3" output="&lt;episodeguide&gt;&lt;url cache=&quot;$$2-$$6.xml&quot;&gt;\1&lt;/url&gt;&lt;/episodeguide&gt;" dest="4+">
+ <expression/>
+ </RegExp>
+ <expression noclean="1"/>
+ </RegExp>
+ </GetDetails>
+
+ <GetArt dest="3">
+ <RegExp input="$$4" output="&lt;details&gt;\1&lt;/details&gt;" dest="3">
+ <RegExp input="$$1" output="&lt;url function=&quot;ParseArt&quot; cache=&quot;\1-banners.xml&quot;&gt;http://thetvdb.com/api/1D62F2F90030C444/series/\1/banners.xml&lt;/url&gt;" dest="4">
+ <expression/>
+ </RegExp>
+ <expression noclean="1"/>
+ </RegExp>
+ </GetArt>
+ <ParseArt dest="3">
+ <RegExp input="$$4" output="&lt;details&gt;\1&lt;/details&gt;" dest="3">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;series&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;graphical&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;$INFO[language]&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;series&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;graphical&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;((?!$INFO[language])[a-z])*&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;series&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;text&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;$INFO[language]&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;series&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;text&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;((?!$INFO[language])[a-z])*&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;series&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;blank&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;\2&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;\2&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;season&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;season&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;$INFO[language]&lt;/Language&gt;[^&lt;]*[^S]*Season&gt;([0-9]+)&lt;/Season&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;\3&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;\3&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;season&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;season&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;((?!$INFO[language])[a-z])*&lt;/Language&gt;[^&lt;]*[^S]*Season&gt;([0-9]+)&lt;/Season&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot; type=&quot;season&quot; season=&quot;\2&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot; type=&quot;season&quot; season=&quot;\2&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;season&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;seasonwide&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;$INFO[language]&lt;/Language&gt;[^&lt;]*[^S]*Season&gt;([0-9]+)&lt;/Season&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;banner&quot; type=&quot;season&quot; season=&quot;\3&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;banner&quot; type=&quot;season&quot; season=&quot;\3&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;season&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;seasonwide&lt;/BannerType2&gt;[^&lt;]*&lt;Language&gt;((?!$INFO[language])[a-z])*&lt;/Language&gt;[^&lt;]*[^S]*Season&gt;([0-9]+)&lt;/Season&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;poster&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;poster&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;poster&lt;/BannerType&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;-1&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb aspect=&quot;poster&quot; type=&quot;season&quot; season=&quot;-1&quot;&gt;http://thetvdb.com/banners/\1&lt;/thumb&gt;" dest="4+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;poster&lt;/BannerType&gt;</expression>
</RegExp>
- <RegExp conditional="fanart" input="$$7" output="&lt;fanart url=&quot;http://thetvdb.com/banners/&quot;&gt;\1&lt;/fanart&gt;" dest="4+">
- <RegExp input="$$5" output="&lt;thumb dim=&quot;\2&quot; colors=&quot;\3&quot; preview=&quot;_cache/\1&quot;&gt;\1&lt;/thumb&gt;" dest="7+">
+ <RegExp conditional="fanart" input="$$5" output="&lt;fanart url=&quot;http://thetvdb.com/banners/&quot;&gt;\1&lt;/fanart&gt;" dest="4+">
+ <RegExp input="$$1" output="&lt;thumb dim=&quot;\2&quot; colors=&quot;\3&quot; preview=&quot;_cache/\1&quot;&gt;\1&lt;/thumb&gt;" dest="5">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;fanart&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;([^&lt;]*)&lt;/BannerType2&gt;[^&lt;]*&lt;Colors&gt;([^&lt;]*)&lt;/Colors&gt;[^&lt;]*&lt;Language&gt;$INFO[language]&lt;/Language&gt;</expression>
</RegExp>
- <RegExp input="$$5" output="&lt;thumb dim=&quot;\2&quot; colors=&quot;\3&quot; preview=&quot;_cache/\1&quot;&gt;\1&lt;/thumb&gt;" dest="7+">
+ <RegExp input="$$1" output="&lt;thumb dim=&quot;\2&quot; colors=&quot;\3&quot; preview=&quot;_cache/\1&quot;&gt;\1&lt;/thumb&gt;" dest="5+">
<expression repeat="yes">&lt;BannerPath&gt;([^&lt;]*)&lt;/BannerPath&gt;[^&lt;]*&lt;BannerType&gt;fanart&lt;/BannerType&gt;[^&lt;]*&lt;BannerType2&gt;([^&lt;]*)&lt;/BannerType2&gt;[^&lt;]*&lt;Colors&gt;([^&lt;]*)&lt;/Colors&gt;[^&lt;]*&lt;Language&gt;((?!$INFO[language])[a-z])*&lt;/Language&gt;</expression>
</RegExp>
<expression noclean="1"/>
</RegExp>
- <RegExp input="$$3" output="\1" dest="6">
- <expression>.*/(.*).zip</expression>
- </RegExp>
- <RegExp input="$$3" output="&lt;episodeguide&gt;&lt;url cache=&quot;$$2-$$6.xml&quot;&gt;\1&lt;/url&gt;&lt;/episodeguide&gt;" dest="4+">
- <expression/>
- </RegExp>
<expression noclean="1"/>
</RegExp>
- </GetDetails>
+ </ParseArt>
<!-- input: $1=html !-->
<!-- input: $2=series url !-->
From ce3a875e3134f9a030e490f16dd59c9175b52923 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 2 Aug 2014 17:48:04 +0100
Subject: [PATCH 09/99] [omx] Report decoded image name
---
xbmc/cores/omxplayer/OMXImage.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
index 3fbea3b..57f69c5 100644
--- a/xbmc/cores/omxplayer/OMXImage.cpp
+++ b/xbmc/cores/omxplayer/OMXImage.cpp
@@ -325,6 +325,7 @@ bool COMXImage::DecodeJpegToTexture(COMXImageFile *file, unsigned int width, uns
{
ret = true;
*userdata = tex;
+ CLog::Log(LOGDEBUG, "%s: decoded %s %dx%d", __func__, file->GetFilename(), width, height);
}
else
{
From 02dda99b8168816aeea1126ca2eeeae7403395a6 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 14 Dec 2013 16:55:05 +0000
Subject: [PATCH 10/99] logging: Add microsecond timer to log messages
---
xbmc/utils/log.cpp | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp
index 4e51166..3c405ab 100644
--- a/xbmc/utils/log.cpp
+++ b/xbmc/utils/log.cpp
@@ -23,6 +23,7 @@
#include "threads/SingleLock.h"
#include "threads/Thread.h"
#include "utils/StringUtils.h"
+#include "utils/TimeUtils.cpp"
static const char* const levelNames[] =
{"DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "SEVERE", "FATAL", "NONE"};
@@ -195,19 +196,31 @@ void CLog::PrintDebugString(const std::string& line)
bool CLog::WriteLogString(int logLevel, const std::string& logString)
{
+#if defined(TARGET_LINUX)
+ static const char* prefixFormat = "%02.2d:%02.2d:%02.2d %10.6f T:%" PRIu64" %7s: ";
+#else
static const char* prefixFormat = "%02.2d:%02.2d:%02.2d T:%" PRIu64" %7s: ";
-
+#endif
std::string strData(logString);
/* fixup newline alignment, number of spaces should equal prefix length */
StringUtils::Replace(strData, "\n", "\n ");
int hour, minute, second;
s_globals.m_platform.GetCurrentLocalTime(hour, minute, second);
-
+
+#if defined(TARGET_LINUX)
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ float Now = now.tv_sec + now.tv_nsec * 1e-9;
+#endif
+
strData = StringUtils::Format(prefixFormat,
hour,
minute,
second,
+#if defined(TARGET_LINUX)
+ Now,
+#endif
(uint64_t)CThread::GetCurrentThreadId(),
levelNames[logLevel]) + strData;
From 6c35f600273abd1b53ea06dbb950f83cedeada00 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 8 Mar 2014 15:36:06 +0000
Subject: [PATCH 13/99] [hifiberry] Hack: force it to be recognised as IEC958
capable to enable passthrough options
---
xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
index a464b4b..7eba389 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -1296,6 +1296,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev
if (snd_card_get_name(cardNr, &cardName) == 0)
info.m_displayName = cardName;
+ // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver
+ if (info.m_displayName == "snd_rpi_hifiberry_digi")
+ info.m_deviceType = AE_DEVTYPE_IEC958;
+
if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
{
From 44e7c31812dfaf5b38835a8fb96794efd44590ac Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 11 Dec 2013 17:21:54 +0000
Subject: [PATCH 14/99] Move the reference-counting of Begin and End calls from
DX and GL source files into GUIFontTTF.cpp.
---
xbmc/guilib/GUIFontTTF.cpp | 21 ++++++
xbmc/guilib/GUIFontTTF.h | 6 +-
xbmc/guilib/GUIFontTTFDX.cpp | 79 ++++++++++------------
xbmc/guilib/GUIFontTTFDX.h | 4 +-
xbmc/guilib/GUIFontTTFGL.cpp | 154 ++++++++++++++++++++-----------------------
xbmc/guilib/GUIFontTTFGL.h | 4 +-
6 files changed, 135 insertions(+), 133 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 008c7ae4..e507833 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -308,6 +308,27 @@ bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float as
return true;
}
+void CGUIFontTTFBase::Begin()
+{
+ if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
+ {
+ m_vertex_count = 0;
+ }
+ // Keep track of the nested begin/end calls.
+ m_nestedBeginCount++;
+}
+
+void CGUIFontTTFBase::End()
+{
+ if (m_nestedBeginCount == 0)
+ return;
+
+ if (--m_nestedBeginCount > 0)
+ return;
+
+ LastEnd();
+}
+
void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
{
Begin();
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 4501dbd..df54a5d 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -77,8 +77,8 @@ class CGUIFontTTFBase
bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f, bool border = false);
- virtual void Begin() = 0;
- virtual void End() = 0;
+ void Begin();
+ void End();
const CStdString& GetFileName() const { return m_strFileName; };
@@ -168,6 +168,8 @@ class CGUIFontTTFBase
CStdString m_strFileName;
private:
+ virtual bool FirstBegin() = 0;
+ virtual void LastEnd() = 0;
CGUIFontTTFBase(const CGUIFontTTFBase&);
CGUIFontTTFBase& operator=(const CGUIFontTTFBase&);
int m_referenceCount;
diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
index e3eba24..2f90668 100644
--- a/xbmc/guilib/GUIFontTTFDX.cpp
+++ b/xbmc/guilib/GUIFontTTFDX.cpp
@@ -51,65 +51,56 @@ CGUIFontTTFDX::~CGUIFontTTFDX(void)
free(m_index);
}
-void CGUIFontTTFDX::Begin()
+bool CGUIFontTTFDX::FirstBegin()
{
LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
if (pD3DDevice == NULL)
+ {
CLog::Log(LOGERROR, __FUNCTION__" - failed to get Direct3D device");
+ return false;
+ }
- if (m_nestedBeginCount == 0 && pD3DDevice != NULL && m_texture != NULL)
+ int unit = 0;
+ // just have to blit from our texture.
+ m_texture->BindToUnit(unit);
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+ unit++;
+
+ if(g_Windowing.UseLimitedColor())
{
- int unit = 0;
- // just have to blit from our texture.
- m_texture->BindToUnit(unit);
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD );
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
+ pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
unit++;
-
- if(g_Windowing.UseLimitedColor())
- {
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD );
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
- pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
- unit++;
- }
-
- // no other texture stages needed
- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
-
- pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
- pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
- pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
- pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
- pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
- pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
- pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
-
- pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
- m_vertex_count = 0;
}
- // Keep track of the nested begin/end calls.
- m_nestedBeginCount++;
+ // no other texture stages needed
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+
+ pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
+ pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
+ pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
+ pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+ pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
+ pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
+
+ pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
+ return true;
}
-void CGUIFontTTFDX::End()
+void CGUIFontTTFDX::LastEnd()
{
LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
- if (m_nestedBeginCount == 0)
- return;
-
- if (--m_nestedBeginCount > 0)
- return;
-
if (m_vertex_count == 0)
return;
diff --git a/xbmc/guilib/GUIFontTTFDX.h b/xbmc/guilib/GUIFontTTFDX.h
index 0431085..17dfefe 100644
--- a/xbmc/guilib/GUIFontTTFDX.h
+++ b/xbmc/guilib/GUIFontTTFDX.h
@@ -41,8 +41,8 @@ class CGUIFontTTFDX : public CGUIFontTTFBase
CGUIFontTTFDX(const CStdString& strFileName);
virtual ~CGUIFontTTFDX(void);
- virtual void Begin();
- virtual void End();
+ virtual bool FirstBegin();
+ virtual void LastEnd();
protected:
virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index 6a8291b..97853fd 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -53,108 +53,96 @@ CGUIFontTTFGL::~CGUIFontTTFGL(void)
{
}
-void CGUIFontTTFGL::Begin()
+bool CGUIFontTTFGL::FirstBegin()
{
- if (m_nestedBeginCount == 0 && m_texture != NULL)
+ if (m_textureStatus == TEXTURE_REALLOCATED)
{
- if (m_textureStatus == TEXTURE_REALLOCATED)
- {
- if (glIsTexture(m_nTexture))
- g_TextureManager.ReleaseHwTexture(m_nTexture);
- m_textureStatus = TEXTURE_VOID;
- }
-
- if (m_textureStatus == TEXTURE_VOID)
- {
- // Have OpenGL generate a texture object handle for us
- glGenTextures(1, (GLuint*) &m_nTexture);
+ if (glIsTexture(m_nTexture))
+ g_TextureManager.ReleaseHwTexture(m_nTexture);
+ m_textureStatus = TEXTURE_VOID;
+ }
- // Bind the texture object
- glBindTexture(GL_TEXTURE_2D, m_nTexture);
+ if (m_textureStatus == TEXTURE_VOID)
+ {
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures(1, (GLuint*) &m_nTexture);
+
+ // Bind the texture object
+ glBindTexture(GL_TEXTURE_2D, m_nTexture);
#ifdef HAS_GL
- glEnable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_2D);
#endif
- // Set the texture's stretching properties
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // Set the texture's stretching properties
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // Set the texture image -- THIS WORKS, so the pixels must be wrong.
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, 0);
-
- VerifyGLState();
- m_textureStatus = TEXTURE_UPDATED;
- }
+ // Set the texture image -- THIS WORKS, so the pixels must be wrong.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, 0);
- if (m_textureStatus == TEXTURE_UPDATED)
- {
- glBindTexture(GL_TEXTURE_2D, m_nTexture);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE,
- m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch());
- glDisable(GL_TEXTURE_2D);
-
- m_updateY1 = m_updateY2 = 0;
- m_textureStatus = TEXTURE_READY;
- }
+ VerifyGLState();
+ m_textureStatus = TEXTURE_UPDATED;
+ }
- // Turn Blending On
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
- glEnable(GL_BLEND);
+ if (m_textureStatus == TEXTURE_UPDATED)
+ {
+ glBindTexture(GL_TEXTURE_2D, m_nTexture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE,
+ m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch());
+ glDisable(GL_TEXTURE_2D);
+
+ m_updateY1 = m_updateY2 = 0;
+ m_textureStatus = TEXTURE_READY;
+ }
+
+ // Turn Blending On
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
+ glEnable(GL_BLEND);
#ifdef HAS_GL
- glEnable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_2D);
#endif
- glBindTexture(GL_TEXTURE_2D, m_nTexture);
+ glBindTexture(GL_TEXTURE_2D, m_nTexture);
#ifdef HAS_GL
- glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- VerifyGLState();
+ glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ VerifyGLState();
+
+ if(g_Windowing.UseLimitedColor())
+ {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
+ glEnable(GL_TEXTURE_2D);
- if(g_Windowing.UseLimitedColor())
- {
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
- glEnable(GL_TEXTURE_2D);
-
- const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
- glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD);
- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT);
- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR);
- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE);
- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS);
- VerifyGLState();
- }
+ const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
+ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD);
+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT);
+ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
+ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR);
+ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE);
+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS);
+ VerifyGLState();
+ }
#else
- g_Windowing.EnableGUIShader(SM_FONTS);
+ g_Windowing.EnableGUIShader(SM_FONTS);
#endif
-
- m_vertex_count = 0;
- }
- // Keep track of the nested begin/end calls.
- m_nestedBeginCount++;
+ return true;
}
-void CGUIFontTTFGL::End()
+void CGUIFontTTFGL::LastEnd()
{
- if (m_nestedBeginCount == 0)
- return;
-
- if (--m_nestedBeginCount > 0)
- return;
-
#ifdef HAS_GL
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
index c0bb53a..735fb3a 100644
--- a/xbmc/guilib/GUIFontTTFGL.h
+++ b/xbmc/guilib/GUIFontTTFGL.h
@@ -41,8 +41,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
CGUIFontTTFGL(const CStdString& strFileName);
virtual ~CGUIFontTTFGL(void);
- virtual void Begin();
- virtual void End();
+ virtual bool FirstBegin();
+ virtual void LastEnd();
protected:
virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
From b0eb8735bb06d3f50b546bfc65607b841a926f5f Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 11 Dec 2013 18:47:54 +0000
Subject: [PATCH 15/99] Convert CGUIFontTTFBase::m_vertex to be managed as a
std::vector.
Also retired CGUIFontTTFBase::m_vertex_count and
CGUIFontTTFBase::m_vertex_size because these can be derived from vector
member functions.
---
xbmc/guilib/GUIFontTTF.cpp | 29 +++++------------------------
xbmc/guilib/GUIFontTTF.h | 4 +---
xbmc/guilib/GUIFontTTFDX.cpp | 12 ++++++------
xbmc/guilib/GUIFontTTFGL.cpp | 12 ++++++------
4 files changed, 18 insertions(+), 39 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index e507833..0a80471 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -138,8 +138,7 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
m_maxChars = 0;
m_nestedBeginCount = 0;
- m_vertex_size = 4*1024;
- m_vertex = (SVertex*)malloc(m_vertex_size * sizeof(SVertex));
+ m_vertex.reserve(4*1024);
m_face = NULL;
m_stroker = NULL;
@@ -154,7 +153,6 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
m_textureScaleX = m_textureScaleY = 0.0;
m_ellipsesWidth = m_height = 0.0f;
m_color = 0;
- m_vertex_count = 0;
m_nTexture = 0;
}
@@ -215,9 +213,7 @@ void CGUIFontTTFBase::Clear()
g_freeTypeLibrary.ReleaseStroker(m_stroker);
m_stroker = NULL;
- free(m_vertex);
- m_vertex = NULL;
- m_vertex_count = 0;
+ m_vertex.clear();
}
bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing, bool border)
@@ -312,7 +308,7 @@ void CGUIFontTTFBase::Begin()
{
if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
{
- m_vertex_count = 0;
+ m_vertex.clear();
}
// Keep track of the nested begin/end calls.
m_nestedBeginCount++;
@@ -745,22 +741,9 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
float tt = texture.y1 * m_textureScaleY;
float tb = texture.y2 * m_textureScaleY;
- // grow the vertex buffer if required
- if(m_vertex_count >= m_vertex_size)
- {
- m_vertex_size *= 2;
- void* old = m_vertex;
- m_vertex = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex));
- if (!m_vertex)
- {
- free(old);
- CLog::Log(LOGSEVERE, "%s: can't allocate %" PRIdS" bytes for texture", __FUNCTION__ , m_vertex_size * sizeof(SVertex));
- return;
- }
- }
-
+ m_vertex.resize(m_vertex.size() + 4);
+ SVertex* v = &m_vertex[m_vertex.size() - 4];
m_color = color;
- SVertex* v = m_vertex + m_vertex_count;
unsigned char r = GET_R(color)
, g = GET_G(color)
@@ -827,8 +810,6 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
v[3].y = y[2];
v[3].z = z[2];
#endif
-
- m_vertex_count+=4;
}
// Oblique code - original taken from freetype2 (ftsynth.c)
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index df54a5d..10a7060 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -156,9 +156,7 @@ class CGUIFontTTFBase
unsigned int m_nTexture;
- SVertex* m_vertex;
- int m_vertex_count;
- int m_vertex_size;
+ std::vector<SVertex> m_vertex;
float m_textureScaleX;
float m_textureScaleY;
diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
index 2f90668..6ef8984 100644
--- a/xbmc/guilib/GUIFontTTFDX.cpp
+++ b/xbmc/guilib/GUIFontTTFDX.cpp
@@ -101,17 +101,17 @@ void CGUIFontTTFDX::LastEnd()
{
LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
- if (m_vertex_count == 0)
+ if (m_vertex.size() == 0)
return;
- unsigned index_size = m_vertex_size * 6 / 4;
+ unsigned index_size = m_vertex.capacity() * 6 / 4;
if(m_index_size < index_size)
{
uint16_t* id = (uint16_t*)calloc(index_size, sizeof(uint16_t));
if(id == NULL)
return;
- for(int i = 0, b = 0; i < m_vertex_size; i += 4, b += 6)
+ for(int i = 0, b = 0; i < m_vertex.capacity(); i += 4, b += 6)
{
id[b+0] = i + 0;
id[b+1] = i + 1;
@@ -140,11 +140,11 @@ void CGUIFontTTFDX::LastEnd()
pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST
, 0
- , m_vertex_count
- , m_vertex_count / 2
+ , m_vertex.size()
+ , m_vertex.size() / 2
, m_index
, D3DFMT_INDEX16
- , m_vertex
+ , &m_vertex[0]
, sizeof(SVertex));
pD3DDevice->SetTransform(D3DTS_WORLD, &orig);
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index 97853fd..b76c6a5 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -146,13 +146,13 @@ void CGUIFontTTFGL::LastEnd()
#ifdef HAS_GL
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
- glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r));
- glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x));
- glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u));
+ glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, r));
+ glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, x));
+ glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, u));
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glDrawArrays(GL_QUADS, 0, m_vertex_count);
+ glDrawArrays(GL_QUADS, 0, m_vertex.size());
glPopClientAttrib();
glActiveTexture(GL_TEXTURE1);
@@ -168,10 +168,10 @@ void CGUIFontTTFGL::LastEnd()
GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
// stack object until VBOs will be used
- std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
+ std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
SVertex *vertices = &vecVertices[0];
- for (int i=0; i<m_vertex_count; i+=4)
+ for (size_t i=0; i<m_vertex.size(); i+=4)
{
*vertices++ = m_vertex[i];
*vertices++ = m_vertex[i+1];
From f59702d81eba5e5de5cb856047d4821dad0d6415 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Mon, 16 Dec 2013 18:58:12 +0000
Subject: [PATCH 16/99] CGUIFontTTFBase::RenderCharacter can now append to
arbitrary vectors of vertices rather than only CGUIFontTTFBase::m_vertex
---
xbmc/guilib/GUIFontTTF.cpp | 12 +++++++-----
xbmc/guilib/GUIFontTTF.h | 2 +-
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 0a80471..848c5c8 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -329,6 +329,8 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
{
Begin();
+ std::vector<SVertex> &vertices = m_vertex;
+
// save the origin, which is scaled separately
m_originX = x;
m_originY = y;
@@ -409,7 +411,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
for (int i = 0; i < 3; i++)
{
- RenderCharacter(startX + cursorX, startY, period, color, !scrolling);
+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
cursorX += period->advance;
}
break;
@@ -418,7 +420,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
break; // exceeded max allowed width - stop rendering
- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling);
+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
if ( alignment & XBFONT_JUSTIFIED )
{
if ((*pos & 0xffff) == L' ')
@@ -675,7 +677,7 @@ bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character *
return true;
}
-void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX)
+void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices)
{
// actual image width isn't same as the character width as that is
// just baseline width and height should include the descent
@@ -741,8 +743,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
float tt = texture.y1 * m_textureScaleY;
float tb = texture.y2 * m_textureScaleY;
- m_vertex.resize(m_vertex.size() + 4);
- SVertex* v = &m_vertex[m_vertex.size() - 4];
+ vertices.resize(vertices.size() + 4);
+ SVertex* v = &vertices[vertices.size() - 4];
m_color = color;
unsigned char r = GET_R(color)
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 10a7060..dde0350 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -109,7 +109,7 @@ class CGUIFontTTFBase
// Stuff for pre-rendering for speed
inline Character *GetCharacter(character_t letter);
bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch);
- void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX);
+ void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices);
void ClearCharacterCache();
virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0;
From 4aa871df47379c79ff394e5aa694560f68d5c638 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 15 Jan 2014 17:18:38 +0000
Subject: [PATCH 17/99] Add a cache of font glyph bounding box vertices.
This is implemented as a template because ultimately we will key on different
parameters and store values of different types, depending upon whether we
have a GLES or non-GLES backend, and for GLES, whether or not the currently
applicable transformation matrices permit the use of hardware clipping.
---
XBMC.xcodeproj/project.pbxproj | 10 ++
project/VS2010Express/XBMC.vcxproj | 2 +
project/VS2010Express/XBMC.vcxproj.filters | 6 +
xbmc/guilib/GUIFontCache.cpp | 105 ++++++++++++++
xbmc/guilib/GUIFontCache.h | 217 +++++++++++++++++++++++++++++
xbmc/guilib/GUIFontTTF.cpp | 181 +++++++++++++-----------
xbmc/guilib/GUIFontTTF.h | 5 +
xbmc/guilib/GUIFontTTFGL.cpp | 1 +
xbmc/guilib/GraphicContext.h | 1 +
xbmc/guilib/Makefile.in | 1 +
xbmc/guilib/TransformMatrix.h | 11 ++
11 files changed, 456 insertions(+), 84 deletions(-)
create mode 100644 xbmc/guilib/GUIFontCache.cpp
create mode 100644 xbmc/guilib/GUIFontCache.h
diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
index 4924acd..1d312b8 100644
--- a/XBMC.xcodeproj/project.pbxproj
+++ b/XBMC.xcodeproj/project.pbxproj
@@ -168,6 +168,9 @@
1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; };
1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; };
1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; };
+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; };
32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; };
36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; };
36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; };
@@ -4011,6 +4014,8 @@
1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = "<group>"; };
1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = "<group>"; };
1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = "<group>"; };
+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = "<group>"; };
+ 2F4564D41970129A00396109 /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = "<group>"; };
32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = "<group>"; };
32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = "<group>"; };
36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = "<group>"; };
@@ -6518,6 +6523,8 @@
18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */,
18B7C76B1294222E009E7A26 /* GUIFont.cpp */,
18B7C7111294222D009E7A26 /* GUIFont.h */,
+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */,
+ 2F4564D41970129A00396109 /* GUIFontCache.h */,
18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */,
18B7C7121294222D009E7A26 /* GUIFontManager.h */,
18B7C76D1294222E009E7A26 /* GUIFontTTF.cpp */,
@@ -11007,6 +11014,7 @@
7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */,
F584E12E0F257C5100DB26A5 /* HTTPDirectory.cpp in Sources */,
F54C51D20F1E783200D46E3C /* GUIDialogKaraokeSongSelector.cpp in Sources */,
+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */,
F54C51D50F1E784800D46E3C /* karaokelyricscdg.cpp in Sources */,
F54C51D80F1E785700D46E3C /* karaokelyrics.cpp in Sources */,
F54C51E50F1E787700D46E3C /* karaokelyricstextkar.cpp in Sources */,
@@ -12675,6 +12683,7 @@
DFF0F45B17528350002DA3A4 /* Control.cpp in Sources */,
DFF0F45C17528350002DA3A4 /* Dialog.cpp in Sources */,
DFF0F45D17528350002DA3A4 /* File.cpp in Sources */,
+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */,
DFF0F45E17528350002DA3A4 /* InfoTagMusic.cpp in Sources */,
DFF0F45F17528350002DA3A4 /* InfoTagVideo.cpp in Sources */,
DFF0F46017528350002DA3A4 /* Keyboard.cpp in Sources */,
@@ -13473,6 +13482,7 @@
E499131D174E5DAD00741B6D /* GUIVisualisationControl.cpp in Sources */,
E499131E174E5DAD00741B6D /* GUIWindow.cpp in Sources */,
E499131F174E5DAD00741B6D /* GUIWindowManager.cpp in Sources */,
+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */,
E4991320174E5DAD00741B6D /* GUIWrappingListContainer.cpp in Sources */,
E4991321174E5DAD00741B6D /* imagefactory.cpp in Sources */,
E4991322174E5DAD00741B6D /* IWindowManagerCallback.cpp in Sources */,
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index 64f7d5c..1dcad9d 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -425,6 +425,7 @@
<ClCompile Include="..\..\xbmc\guilib\GUIFadeLabelControl.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFixedListContainer.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp" />
+ <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontTTF.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFontTTFDX.cpp" />
@@ -1747,6 +1748,7 @@
<ClInclude Include="..\..\xbmc\guilib\GUIFadeLabelControl.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFixedListContainer.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFont.h" />
+ <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontTTF.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFontTTFDX.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 2f3a22d..8c73472 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -991,6 +991,9 @@
<ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp">
<Filter>guilib</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp">
+ <Filter>guilib</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp">
<Filter>guilib</Filter>
</ClCompile>
@@ -3885,6 +3888,9 @@
<ClInclude Include="..\..\xbmc\guilib\GUIFont.h">
<Filter>guilib</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h">
+ <Filter>guilib</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h">
<Filter>guilib</Filter>
</ClInclude>
diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
new file mode 100644
index 0000000..2c72f9c
--- /dev/null
+++ b/xbmc/guilib/GUIFontCache.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <vector>
+#include "utils/StdString.h" // required by GUIFontTTF.h
+#include "GUIFontTTF.h"
+#include "GraphicContext.h"
+
+template<class Position, class Value>
+void CGUIFontCacheEntry<Position, Value>::Reassign::operator()(CGUIFontCacheEntry<Position, Value> &entry)
+{
+ entry.m_key.m_pos = m_key.m_pos;
+ entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end());
+ entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end());
+ entry.m_key.m_alignment = m_key.m_alignment;
+ entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth;
+ entry.m_key.m_scrolling = m_key.m_scrolling;
+ entry.m_matrix = m_key.m_matrix;
+ entry.m_key.m_scaleX = m_key.m_scaleX;
+ entry.m_key.m_scaleY = m_key.m_scaleY;
+
+ entry.m_lastUsedMillis = m_nowMillis;
+ entry.m_value.clear();
+}
+
+template<class Position, class Value>
+CGUIFontCacheEntry<Position, Value>::~CGUIFontCacheEntry()
+{
+ delete &m_key.m_colors;
+ delete &m_key.m_text;
+ m_value.clear();
+}
+
+template<class Position, class Value>
+Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
+ const vecColors &colors, const vecText &text,
+ uint32_t alignment, float maxPixelWidth,
+ bool scrolling,
+ unsigned int nowMillis, bool &dirtyCache)
+{
+ const CGUIFontCacheKey<Position> key(pos,
+ const_cast<vecColors &>(colors), const_cast<vecText &>(text),
+ alignment, maxPixelWidth,
+ scrolling, g_graphicsContext.GetGUIMatrix(),
+ g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
+ EntryHashIterator i = m_list.template get<Hash>().find(key);
+ if (i == m_list.template get<Hash>().end())
+ {
+ /* Cache miss */
+ EntryAgeIterator oldest = m_list.template get<Age>().begin();
+ if (!m_list.template get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
+ {
+ /* The oldest existing entry is old enough to expire and reuse */
+ m_list.template get<Hash>().modify(m_list.template project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
+ m_list.template get<Age>().relocate(m_list.template get<Age>().end(), oldest);
+ }
+ else
+ {
+ /* We need a new entry instead */
+ /* Yes, this causes the creation an destruction of a temporary entry, but
+ * this code ought to only be used infrequently, when the cache needs to grow */
+ m_list.template get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
+ }
+ dirtyCache = true;
+ return (--m_list.template get<Age>().end())->m_value;
+ }
+ else
+ {
+ /* Cache hit */
+ /* Update time in entry and move to the back of the list */
+ i->m_lastUsedMillis = nowMillis;
+ m_list.template get<Age>().relocate(m_list.template get<Age>().end(), m_list.template project<Age>(i));
+ dirtyCache = false;
+ return i->m_value;
+ }
+}
+
+template<class Position, class Value>
+void CGUIFontCache<Position, Value>::Flush()
+{
+ m_list.template get<Age>().clear();
+}
+
+template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
+template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
+template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
+template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
new file mode 100644
index 0000000..ef65845
--- /dev/null
+++ b/xbmc/guilib/GUIFontCache.h
@@ -0,0 +1,217 @@
+/*!
+\file GUIFontCache.h
+\brief
+*/
+
+#ifndef CGUILIB_GUIFONTCACHE_H
+#define CGUILIB_GUIFONTCACHE_H
+#pragma once
+
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <cstddef>
+#include <cstring>
+#include <stdint.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "boost/multi_index_container.hpp"
+#include "boost/multi_index/sequenced_index.hpp"
+#include "boost/multi_index/hashed_index.hpp"
+#include "boost/multi_index/member.hpp"
+
+#include "TransformMatrix.h"
+
+using namespace boost::multi_index;
+
+#define FONT_CACHE_TIME_LIMIT (1000)
+
+template<class Position, class Value> class CGUIFontCache;
+class CGUIFontTTFBase;
+
+template<class Position>
+struct CGUIFontCacheKey
+{
+ Position m_pos;
+ vecColors &m_colors;
+ vecText &m_text;
+ uint32_t m_alignment;
+ float m_maxPixelWidth;
+ bool m_scrolling;
+ const TransformMatrix &m_matrix;
+ float m_scaleX;
+ float m_scaleY;
+
+ CGUIFontCacheKey(Position pos,
+ vecColors &colors, vecText &text,
+ uint32_t alignment, float maxPixelWidth,
+ bool scrolling, const TransformMatrix &matrix,
+ float scaleX, float scaleY) :
+ m_pos(pos),
+ m_colors(colors), m_text(text),
+ m_alignment(alignment), m_maxPixelWidth(maxPixelWidth),
+ m_scrolling(scrolling), m_matrix(matrix),
+ m_scaleX(scaleX), m_scaleY(scaleY)
+ {}
+};
+
+template<class Position, class Value>
+struct CGUIFontCacheEntry
+{
+ const CGUIFontCache<Position, Value> &m_cache;
+ CGUIFontCacheKey<Position> m_key;
+ TransformMatrix m_matrix;
+
+ /* These need to be declared as mutable to get round the fact that only
+ * const iterators are available. These fields do not affect comparison or
+ * hash functors, so from the container's point of view, they are mutable. */
+ mutable unsigned int m_lastUsedMillis;
+ mutable Value m_value;
+
+ CGUIFontCacheEntry(const CGUIFontCache<Position, Value> &cache, const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) :
+ m_cache(cache),
+ m_key(key.m_pos,
+ *new vecColors, *new vecText,
+ key.m_alignment, key.m_maxPixelWidth,
+ key.m_scrolling, m_matrix,
+ key.m_scaleX, key.m_scaleY),
+ m_lastUsedMillis(nowMillis)
+ {
+ m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
+ m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
+ m_matrix = key.m_matrix;
+ }
+
+ CGUIFontCacheEntry(const CGUIFontCacheEntry &other) :
+ m_cache(other.m_cache),
+ m_key(other.m_key.m_pos,
+ *new vecColors, *new vecText,
+ other.m_key.m_alignment, other.m_key.m_maxPixelWidth,
+ other.m_key.m_scrolling, m_matrix,
+ other.m_key.m_scaleX, other.m_key.m_scaleY),
+ m_lastUsedMillis(other.m_lastUsedMillis),
+ m_value(other.m_value)
+ {
+ m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end());
+ m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end());
+ m_matrix = other.m_key.m_matrix;
+ }
+
+ struct Reassign
+ {
+ Reassign(const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {}
+ void operator()(CGUIFontCacheEntry &entry);
+ private:
+ const CGUIFontCacheKey<Position> &m_key;
+ unsigned int m_nowMillis;
+ };
+
+ ~CGUIFontCacheEntry();
+};
+
+template<class Position>
+struct CGUIFontCacheHash
+{
+ size_t operator()(const CGUIFontCacheKey<Position> &key) const
+ {
+ /* Not much effort has gone into choosing this hash function */
+ size_t hash = 0, i;
+ for (i = 0; i < 3 && i < key.m_text.size(); ++i)
+ hash += key.m_text[i];
+ if (key.m_colors.size())
+ hash += key.m_colors[0];
+ hash += MatrixHashContribution(key);
+ return hash;
+ }
+};
+
+template<class Position>
+struct CGUIFontCacheKeysMatch
+{
+ bool operator()(const CGUIFontCacheKey<Position> &a, const CGUIFontCacheKey<Position> &b) const
+ {
+ return a.m_text == b.m_text &&
+ a.m_colors == b.m_colors &&
+ a.m_alignment == b.m_alignment &&
+ a.m_scrolling == b.m_scrolling &&
+ a.m_maxPixelWidth == b.m_maxPixelWidth &&
+ Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) &&
+ a.m_scaleX == b.m_scaleX &&
+ a.m_scaleY == b.m_scaleY;
+ }
+};
+
+template<class Position, class Value>
+class CGUIFontCache
+{
+ /* Empty structs used as tags to identify indexes */
+ struct Age {};
+ struct Hash {};
+
+ typedef multi_index_container<
+ CGUIFontCacheEntry<Position, Value>,
+ indexed_by<
+ sequenced<tag<Age> >,
+ hashed_unique<tag<Hash>, member<CGUIFontCacheEntry<Position, Value>, CGUIFontCacheKey<Position>, &CGUIFontCacheEntry<Position, Value>::m_key>, CGUIFontCacheHash<Position>, CGUIFontCacheKeysMatch<Position> >
+ >
+ > EntryList;
+
+ typedef typename EntryList::template index<Age>::type::iterator EntryAgeIterator;
+ typedef typename EntryList::template index<Hash>::type::iterator EntryHashIterator;
+
+ EntryList m_list;
+
+public:
+ const CGUIFontTTFBase &m_font;
+
+ CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {}
+ Value &Lookup(Position &pos,
+ const vecColors &colors, const vecText &text,
+ uint32_t alignment, float maxPixelWidth,
+ bool scrolling,
+ unsigned int nowMillis, bool &dirtyCache);
+ void Flush();
+};
+
+struct CGUIFontCacheStaticPosition
+{
+ float m_x;
+ float m_y;
+ CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
+};
+
+typedef std::vector<SVertex> CGUIFontCacheStaticValue;
+
+inline bool Match(const CGUIFontCacheStaticPosition &a, const TransformMatrix &a_m,
+ const CGUIFontCacheStaticPosition &b, const TransformMatrix &b_m,
+ bool scrolling)
+{
+ return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m;
+}
+
+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPosition> &a)
+{
+ /* Ensure horizontally translated versions end up in different buckets */
+ return a.m_matrix.m[0][3];
+}
+
+#endif
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 848c5c8..0290fc4 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -27,6 +27,7 @@
#include "utils/MathUtils.h"
#include "utils/log.h"
#include "windowing/WindowingFactory.h"
+#include "threads/SystemClock.h"
#include <math.h>
@@ -131,7 +132,7 @@ class CFreeTypeLibrary
XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
#define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
-CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
{
m_texture = NULL;
m_char = NULL;
@@ -329,108 +330,120 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
{
Begin();
- std::vector<SVertex> &vertices = m_vertex;
-
- // save the origin, which is scaled separately
- m_originX = x;
- m_originY = y;
-
- // Check if we will really need to truncate or justify the text
- if ( alignment & XBFONT_TRUNCATED )
+ bool dirtyCache;
+ CGUIFontCacheStaticPosition staticPos(x, y);
+ std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
+ colors, text,
+ alignment, maxPixelWidth,
+ scrolling,
+ XbmcThreads::SystemClockMillis(),
+ dirtyCache);
+ if (dirtyCache)
{
- if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
- alignment &= ~XBFONT_TRUNCATED;
- }
- else if ( alignment & XBFONT_JUSTIFIED )
- {
- if ( maxPixelWidth <= 0.0f )
- alignment &= ~XBFONT_JUSTIFIED;
- }
+ // save the origin, which is scaled separately
+ m_originX = x;
+ m_originY = y;
- // calculate sizing information
- float startX = 0;
- float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
+ // Check if we will really need to truncate or justify the text
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
+ alignment &= ~XBFONT_TRUNCATED;
+ }
+ else if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ( maxPixelWidth <= 0.0f )
+ alignment &= ~XBFONT_JUSTIFIED;
+ }
- if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
- {
- // Get the extent of this line
- float w = GetTextWidthInternal( text.begin(), text.end() );
+ // calculate sizing information
+ float startX = 0;
+ float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
- if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
- w = maxPixelWidth;
+ if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
+ {
+ // Get the extent of this line
+ float w = GetTextWidthInternal( text.begin(), text.end() );
- if ( alignment & XBFONT_CENTER_X)
- w *= 0.5f;
- // Offset this line's starting position
- startX -= w;
- }
+ if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
+ w = maxPixelWidth;
- float spacePerLetter = 0; // for justification effects
- if ( alignment & XBFONT_JUSTIFIED )
- {
- // first compute the size of the text to render in both characters and pixels
- unsigned int lineChars = 0;
- float linePixels = 0;
- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
+ if ( alignment & XBFONT_CENTER_X)
+ w *= 0.5f;
+ // Offset this line's starting position
+ startX -= w;
+ }
+
+ float spacePerLetter = 0; // for justification effects
+ if ( alignment & XBFONT_JUSTIFIED )
{
- Character *ch = GetCharacter(*pos);
- if (ch)
- { // spaces have multiple times the justification spacing of normal letters
- lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
- linePixels += ch->advance;
+ // first compute the size of the text to render in both characters and pixels
+ unsigned int lineChars = 0;
+ float linePixels = 0;
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
+ {
+ Character *ch = GetCharacter(*pos);
+ if (ch)
+ { // spaces have multiple times the justification spacing of normal letters
+ lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
+ linePixels += ch->advance;
+ }
}
+ if (lineChars > 1)
+ spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
}
- if (lineChars > 1)
- spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
- }
- float cursorX = 0; // current position along the line
-
- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- {
- // If starting text on a new line, determine justification effects
- // Get the current letter in the CStdString
- color_t color = (*pos & 0xff0000) >> 16;
- if (color >= colors.size())
- color = 0;
- color = colors[color];
+ float cursorX = 0; // current position along the line
- // grab the next character
- Character *ch = GetCharacter(*pos);
- if (!ch) continue;
-
- if ( alignment & XBFONT_TRUNCATED )
+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
{
- // Check if we will be exceeded the max allowed width
- if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
- {
- // Yup. Let's draw the ellipses, then bail
- // Perhaps we should really bail to the next line in this case??
- Character *period = GetCharacter(L'.');
- if (!period)
- break;
+ // If starting text on a new line, determine justification effects
+ // Get the current letter in the CStdString
+ color_t color = (*pos & 0xff0000) >> 16;
+ if (color >= colors.size())
+ color = 0;
+ color = colors[color];
+
+ // grab the next character
+ Character *ch = GetCharacter(*pos);
+ if (!ch) continue;
- for (int i = 0; i < 3; i++)
+ if ( alignment & XBFONT_TRUNCATED )
+ {
+ // Check if we will be exceeded the max allowed width
+ if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
{
- RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
- cursorX += period->advance;
+ // Yup. Let's draw the ellipses, then bail
+ // Perhaps we should really bail to the next line in this case??
+ Character *period = GetCharacter(L'.');
+ if (!period)
+ break;
+
+ for (int i = 0; i < 3; i++)
+ {
+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
+ cursorX += period->advance;
+ }
+ break;
}
- break;
}
- }
- else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
- break; // exceeded max allowed width - stop rendering
+ else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
+ break; // exceeded max allowed width - stop rendering
- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
- if ( alignment & XBFONT_JUSTIFIED )
- {
- if ((*pos & 0xffff) == L' ')
- cursorX += ch->advance + spacePerLetter * justification_word_weight;
+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
+ if ( alignment & XBFONT_JUSTIFIED )
+ {
+ if ((*pos & 0xffff) == L' ')
+ cursorX += ch->advance + spacePerLetter * justification_word_weight;
+ else
+ cursorX += ch->advance + spacePerLetter;
+ }
else
- cursorX += ch->advance + spacePerLetter;
+ cursorX += ch->advance;
}
- else
- cursorX += ch->advance;
}
+ /* Append the new vertices (from the cache or otherwise) to the set collected
+ * since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
End();
}
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index dde0350..77111bc 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -64,6 +64,9 @@ struct SVertex
};
+#include "GUIFontCache.h"
+
+
class CGUIFontTTFBase
{
friend class CGUIFont;
@@ -165,6 +168,8 @@ class CGUIFontTTFBase
CStdString m_strFileName;
+ CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
+
private:
virtual bool FirstBegin() = 0;
virtual void LastEnd() = 0;
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index b76c6a5..9935ea4 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -221,6 +221,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
m_textureScaleX = 1.0f / m_textureWidth;
if (m_textureHeight < newHeight)
CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
+ m_staticCache.Flush();
memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
if (m_texture)
diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
index 6c2dcd4..bab2457 100644
--- a/xbmc/guilib/GraphicContext.h
+++ b/xbmc/guilib/GraphicContext.h
@@ -146,6 +146,7 @@ class CGraphicContext : public CCriticalSection,
inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); }
bool RectIsAngled(float x1, float y1, float x2, float y2) const;
+ inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; }
inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; }
inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; }
inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE
diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in
index 086fb0d..af82979 100644
--- a/xbmc/guilib/Makefile.in
+++ b/xbmc/guilib/Makefile.in
@@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp
SRCS += GUIFadeLabelControl.cpp
SRCS += GUIFixedListContainer.cpp
SRCS += GUIFont.cpp
+SRCS += GUIFontCache.cpp
SRCS += GUIFontManager.cpp
SRCS += GUIFontTTF.cpp
SRCS += GUIImage.cpp
diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h
index f351c99..9036ba9 100644
--- a/xbmc/guilib/TransformMatrix.h
+++ b/xbmc/guilib/TransformMatrix.h
@@ -245,3 +245,14 @@ class TransformMatrix
float alpha;
bool identity;
};
+
+inline bool operator==(const TransformMatrix &a, const TransformMatrix &b)
+{
+ return a.alpha == b.alpha && ((a.identity && b.identity) ||
+ (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof a.m / sizeof a.m[0][0], &b.m[0][0])));
+}
+
+inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b)
+{
+ return !operator==(a, b);
+}
From 4da5d7b1677f96874f09f3f1cc910651eb3460ec Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 23 Jan 2014 22:24:17 +0000
Subject: [PATCH 18/99] Lay the groundwork for hardware clipping.
For glScissor() to replace CGraphicContext::ClipRect, a necessary condition
is that no shear or rotation is introduced between the coordinate systems
they use; this depends upon the settings of the GUI matrix m_finalTransform
as well as the OpenGL model-view and projection matrices. These all remain
unchanged between paired calls of CGUIShader::OnEnabled and
CGUIShader::OnDisabled, so we scan the matrices in CGUIShader::OnEnabled to
see whether hardware clipping is possible.
Then, in CGUIFontTTFBase::RenderCharacter, we don't apply software clipping
in such cases. However, because vertices arising from multiple
CGUIFontTTFBase::DrawTextInternal calls (each of which often uses a different
clip rectangle) get lumped into the same vector, which only at the end is
passed to OpenGL for rendering, we need to wait a few commits before we can
actually apply hardware clipping. In the meantime, expect to see rendering
errors.
---
xbmc/guilib/GUIFontTTF.cpp | 3 +-
xbmc/guilib/GUIShader.cpp | 80 +++++++++++++++++++++++++++++++-
xbmc/guilib/GUIShader.h | 11 +++++
xbmc/guilib/GraphicContext.cpp | 10 ++++
xbmc/guilib/GraphicContext.h | 1 +
xbmc/rendering/RenderSystem.h | 2 +
xbmc/rendering/gles/RenderSystemGLES.cpp | 22 +++++++++
xbmc/rendering/gles/RenderSystemGLES.h | 2 +
8 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 0290fc4..e3808d9 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -709,7 +709,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
(posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY());
vertex += CPoint(m_originX, m_originY);
CRect texture(ch->left, ch->top, ch->right, ch->bottom);
- g_graphicsContext.ClipRect(vertex, texture);
+ if (!g_Windowing.ScissorsCanEffectClipping())
+ g_graphicsContext.ClipRect(vertex, texture);
// transform our positions - note, no scaling due to GUI calibration/resolution occurs
float x[4], y[4], z[4];
diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
index 23cb84f..5d836cee 100644
--- a/xbmc/guilib/GUIShader.cpp
+++ b/xbmc/guilib/GUIShader.cpp
@@ -26,6 +26,8 @@
#include "GUIShader.h"
#include "MatrixGLES.h"
#include "utils/log.h"
+#include "windowing/WindowingFactory.h"
+#include "guilib/GraphicContext.h"
using namespace Shaders;
@@ -88,8 +90,82 @@ bool CGUIShader::OnEnabled()
{
// This is called after glUseProgram()
- glUniformMatrix4fv(m_hProj, 1, GL_FALSE, g_matrices.GetMatrix(MM_PROJECTION));
- glUniformMatrix4fv(m_hModel, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
+ GLfloat *projMatrix = g_matrices.GetMatrix(MM_PROJECTION);
+ GLfloat *modelMatrix = g_matrices.GetMatrix(MM_MODELVIEW);
+ glUniformMatrix4fv(m_hProj, 1, GL_FALSE, projMatrix);
+ glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix);
+
+ const TransformMatrix &guiMatrix = g_graphicsContext.GetGUIMatrix();
+ CRect viewPort; // absolute positions of corners
+ g_Windowing.GetViewPort(viewPort);
+
+ /* glScissor operates in window coordinates. In order that we can use it to
+ * perform clipping, we must ensure that there is an independent linear
+ * transformation from the coordinate system used by CGraphicContext::ClipRect
+ * to window coordinates, separately for X and Y (in other words, no
+ * rotation or shear is introduced at any stage). To do, this, we need to
+ * check that zeros are present in the following locations:
+ *
+ * GUI matrix:
+ * / * 0 * * \
+ * | 0 * * * |
+ * \ 0 0 * * /
+ * ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with
+ * input z = 0, so this column doesn't matter
+ * Model-view matrix:
+ * / * 0 0 * \
+ * | 0 * 0 * |
+ * | 0 0 * * |
+ * \ * * * * / <- eye w has no influence on window x/y (last column below
+ * is either 0 or ignored)
+ * Projection matrix:
+ * / * 0 0 0 \
+ * | 0 * 0 0 |
+ * | * * * * | <- normalised device coordinate z has no influence on window x/y
+ * \ 0 0 * 0 /
+ *
+ * Some of these zeros are not strictly required to ensure this, but they tend
+ * to be zeroed in the common case, so by checking for zeros here, we simplify
+ * the calculation of the window x/y coordinates further down the line.
+ *
+ * (Minor detail: we don't quite deal in window coordinates as defined by
+ * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all
+ * that's needed to handle that is an effective negation at the stage where
+ * Y is in normalised device coordinates.)
+ */
+ m_clipPossible = guiMatrix.m[0][1] == 0 &&
+ guiMatrix.m[1][0] == 0 &&
+ guiMatrix.m[2][0] == 0 &&
+ guiMatrix.m[2][1] == 0 &&
+ modelMatrix[0+1*4] == 0 &&
+ modelMatrix[0+2*4] == 0 &&
+ modelMatrix[1+0*4] == 0 &&
+ modelMatrix[1+2*4] == 0 &&
+ modelMatrix[2+0*4] == 0 &&
+ modelMatrix[2+1*4] == 0 &&
+ projMatrix[0+1*4] == 0 &&
+ projMatrix[0+2*4] == 0 &&
+ projMatrix[0+3*4] == 0 &&
+ projMatrix[1+0*4] == 0 &&
+ projMatrix[1+2*4] == 0 &&
+ projMatrix[1+3*4] == 0 &&
+ projMatrix[3+0*4] == 0 &&
+ projMatrix[3+1*4] == 0 &&
+ projMatrix[3+3*4] == 0;
+ if (m_clipPossible)
+ {
+ m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4];
+ m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4];
+ m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4];
+ m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4];
+ float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4];
+ float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW);
+ float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme
+ m_clipXFactor = m_clipXFactor * xMult;
+ m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2;
+ m_clipYFactor = m_clipYFactor * yMult;
+ m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2;
+ }
return true;
}
diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
index f7b5d9a..fdf7452 100644
--- a/xbmc/guilib/GUIShader.h
+++ b/xbmc/guilib/GUIShader.h
@@ -39,6 +39,11 @@ class CGUIShader : public Shaders::CGLSLShaderProgram
GLint GetCord1Loc() { return m_hCord1; }
GLint GetUniColLoc() { return m_hUniCol; }
GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
+ bool HardwareClipIsPossible() { return m_clipPossible; }
+ GLfloat GetClipXFactor() { return m_clipXFactor; }
+ GLfloat GetClipXOffset() { return m_clipXOffset; }
+ GLfloat GetClipYFactor() { return m_clipYFactor; }
+ GLfloat GetClipYOffset() { return m_clipYOffset; }
protected:
GLint m_hTex0;
@@ -54,6 +59,12 @@ class CGUIShader : public Shaders::CGLSLShaderProgram
GLfloat *m_proj;
GLfloat *m_model;
+
+ bool m_clipPossible;
+ GLfloat m_clipXFactor;
+ GLfloat m_clipXOffset;
+ GLfloat m_clipYFactor;
+ GLfloat m_clipYOffset;
};
#endif // GUI_SHADER_H
diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index 38f17a7..5bffdf5 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -167,6 +167,16 @@ void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
}
}
+CRect CGraphicContext::GetClipRegion()
+{
+ if (m_clipRegions.empty())
+ return CRect(0, 0, m_iScreenWidth, m_iScreenHeight);
+ CRect clipRegion(m_clipRegions.top());
+ if (!m_origins.empty())
+ clipRegion -= m_origins.top();
+ return clipRegion;
+}
+
bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
{
// transform coordinates - we may have a rotation which changes the positioning of the
diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
index bab2457..0a27643 100644
--- a/xbmc/guilib/GraphicContext.h
+++ b/xbmc/guilib/GraphicContext.h
@@ -199,6 +199,7 @@ class CGraphicContext : public CCriticalSection,
void ApplyHardwareTransform();
void RestoreHardwareTransform();
void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL);
+ CRect GetClipRegion();
inline void AddGUITransform()
{
m_transforms.push(m_finalTransform);
diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h
index fa64eba..c1dfb93 100644
--- a/xbmc/rendering/RenderSystem.h
+++ b/xbmc/rendering/RenderSystem.h
@@ -110,6 +110,8 @@ class CRenderSystemBase
virtual void GetViewPort(CRect& viewPort) = 0;
virtual void RestoreViewPort() {};
+ virtual bool ScissorsCanEffectClipping() { return false; }
+ virtual CRect ClipRectToScissorRect(const CRect &rect) { return CRect(); }
virtual void SetScissors(const CRect &rect) = 0;
virtual void ResetScissors() = 0;
diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
index 653c9ec..deb3afc 100644
--- a/xbmc/rendering/gles/RenderSystemGLES.cpp
+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
@@ -533,6 +533,28 @@ void CRenderSystemGLES::SetViewPort(CRect& viewPort)
m_viewPort[3] = viewPort.Height();
}
+bool CRenderSystemGLES::ScissorsCanEffectClipping()
+{
+ if (m_pGUIshader[m_method])
+ return m_pGUIshader[m_method]->HardwareClipIsPossible();
+
+ return false;
+}
+
+CRect CRenderSystemGLES::ClipRectToScissorRect(const CRect &rect)
+{
+ if (!m_pGUIshader[m_method])
+ return CRect();
+ float xFactor = m_pGUIshader[m_method]->GetClipXFactor();
+ float xOffset = m_pGUIshader[m_method]->GetClipXOffset();
+ float yFactor = m_pGUIshader[m_method]->GetClipYFactor();
+ float yOffset = m_pGUIshader[m_method]->GetClipYOffset();
+ return CRect(rect.x1 * xFactor + xOffset,
+ rect.y1 * yFactor + yOffset,
+ rect.x2 * xFactor + xOffset,
+ rect.y2 * yFactor + yOffset);
+}
+
void CRenderSystemGLES::SetScissors(const CRect &rect)
{
if (!m_bRenderCreated)
diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
index 98e398a..81ee49e 100644
--- a/xbmc/rendering/gles/RenderSystemGLES.h
+++ b/xbmc/rendering/gles/RenderSystemGLES.h
@@ -63,6 +63,8 @@ class CRenderSystemGLES : public CRenderSystemBase
virtual void SetViewPort(CRect& viewPort);
virtual void GetViewPort(CRect& viewPort);
+ virtual bool ScissorsCanEffectClipping();
+ virtual CRect ClipRectToScissorRect(const CRect &rect);
virtual void SetScissors(const CRect& rect);
virtual void ResetScissors();
From eb9a11b15a9ea6566bc7e218efe91c3590f43d3e Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 23 Jan 2014 16:42:22 +0000
Subject: [PATCH 19/99] Increase font cache hit rate by keying on the
fractional part of m_originX and m_originY *after* they have been through the
graphics context's transformation matrix, plus the scale/rotation elements of
the matrix, rather than the origin in the original frame of reference plus
the complete transformation matrix. All vertices of individual glyph bounding
boxes are a constant offset from this position, and when the fractional part
of the translation is a match, the rounding of each vertex will be in the
same direction; this permits us to calculate the desired vertices from the
cached ones simply by adding the integer parts of the translations with no
additional rounding steps.
Note that this requires that software clipping is *not* performed.
---
xbmc/guilib/GUIFontCache.cpp | 8 +++++++
xbmc/guilib/GUIFontCache.h | 43 +++++++++++++++++++++++++++++++++++
xbmc/guilib/GUIFontTTF.cpp | 53 +++++++++++++++++++++++++++++++++++---------
xbmc/guilib/GUIFontTTF.h | 1 +
4 files changed, 95 insertions(+), 10 deletions(-)
diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
index 2c72f9c..df466a5 100644
--- a/xbmc/guilib/GUIFontCache.cpp
+++ b/xbmc/guilib/GUIFontCache.cpp
@@ -85,6 +85,9 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
else
{
/* Cache hit */
+ /* Update the translation arguments so that they hold the offset to apply
+ * to the cached values (but only in the dynamic case) */
+ pos.UpdateWithOffsets(i->m_key.m_pos, scrolling);
/* Update time in entry and move to the back of the list */
i->m_lastUsedMillis = nowMillis;
m_list.template get<Age>().relocate(m_list.template get<Age>().end(), m_list.template project<Age>(i));
@@ -103,3 +106,8 @@ template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStati
template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
+
+template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> &entry);
+template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
+template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
+template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
index ef65845..d913dee 100644
--- a/xbmc/guilib/GUIFontCache.h
+++ b/xbmc/guilib/GUIFontCache.h
@@ -44,6 +44,7 @@
using namespace boost::multi_index;
#define FONT_CACHE_TIME_LIMIT (1000)
+#define FONT_CACHE_DIST_LIMIT (0.01)
template<class Position, class Value> class CGUIFontCache;
class CGUIFontTTFBase;
@@ -197,6 +198,7 @@ struct CGUIFontCacheStaticPosition
float m_x;
float m_y;
CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
+ void UpdateWithOffsets(const CGUIFontCacheStaticPosition &cached, bool scrolling) {}
};
typedef std::vector<SVertex> CGUIFontCacheStaticValue;
@@ -214,4 +216,45 @@ inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPo
return a.m_matrix.m[0][3];
}
+struct CGUIFontCacheDynamicPosition
+{
+ float m_x;
+ float m_y;
+ float m_z;
+ CGUIFontCacheDynamicPosition() {}
+ CGUIFontCacheDynamicPosition(float x, float y, float z) : m_x(x), m_y(y), m_z(z) {}
+ void UpdateWithOffsets(const CGUIFontCacheDynamicPosition &cached, bool scrolling)
+ {
+ if (scrolling)
+ m_x = m_x - cached.m_x;
+ else
+ m_x = floorf(m_x - cached.m_x + FONT_CACHE_DIST_LIMIT);
+ m_y = floorf(m_y - cached.m_y + FONT_CACHE_DIST_LIMIT);
+ m_z = floorf(m_z - cached.m_z + FONT_CACHE_DIST_LIMIT);
+ }
+};
+
+typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
+
+inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
+ const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
+ bool scrolling)
+{
+ float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT;
+ float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT;
+ float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT;
+ return (scrolling || diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) &&
+ diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT &&
+ diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT &&
+ a_m.m[0][0] == b_m.m[0][0] &&
+ a_m.m[1][1] == b_m.m[1][1] &&
+ a_m.m[2][2] == b_m.m[2][2];
+ // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements
+}
+
+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheDynamicPosition> &a)
+{
+ return 0;
+}
+
#endif
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index e3808d9..412f47a 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -132,7 +132,7 @@ class CFreeTypeLibrary
XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
#define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
-CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this), m_dynamicCache(*this)
{
m_texture = NULL;
m_char = NULL;
@@ -331,13 +331,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
Begin();
bool dirtyCache;
+ bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping();
CGUIFontCacheStaticPosition staticPos(x, y);
- std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
- colors, text,
- alignment, maxPixelWidth,
- scrolling,
- XbmcThreads::SystemClockMillis(),
- dirtyCache);
+ CGUIFontCacheDynamicPosition dynamicPos;
+ if (hardwareClipping)
+ {
+ dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y),
+ g_graphicsContext.ScaleFinalYCoord(x, y),
+ g_graphicsContext.ScaleFinalZCoord(x, y));
+ }
+ std::vector<SVertex> &vertices = hardwareClipping ?
+ m_dynamicCache.Lookup(dynamicPos,
+ colors, text,
+ alignment, maxPixelWidth,
+ scrolling,
+ XbmcThreads::SystemClockMillis(),
+ dirtyCache) :
+ m_staticCache.Lookup(staticPos,
+ colors, text,
+ alignment, maxPixelWidth,
+ scrolling,
+ XbmcThreads::SystemClockMillis(),
+ dirtyCache);
if (dirtyCache)
{
// save the origin, which is scaled separately
@@ -440,10 +455,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
else
cursorX += ch->advance;
}
+ if (hardwareClipping)
+ /* Append the new vertices (which we have just constructed in the cache)
+ * to the set collected since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
+ }
+ else if (hardwareClipping)
+ {
+ /* Apply the translation offset to the vertices from the cache after
+ * appending them to the set collected since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
+ SVertex *v;
+ for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
+ {
+ v->x += dynamicPos.m_x;
+ v->y += dynamicPos.m_y;
+ v->z += dynamicPos.m_z;
+ }
}
- /* Append the new vertices (from the cache or otherwise) to the set collected
- * since the first Begin() call */
- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
+ if (!hardwareClipping)
+ /* Append the new vertices (from the cache or otherwise) to the set collected
+ * since the first Begin() call */
+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
End();
}
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 77111bc..39bfa52 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -169,6 +169,7 @@ class CGUIFontTTFBase
CStdString m_strFileName;
CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
+ CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> m_dynamicCache;
private:
virtual bool FirstBegin() = 0;
From 0fb48b90145afac07a2dccb6d3f48b45e892e975 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 8 Jan 2014 12:16:33 +0000
Subject: [PATCH 20/99] Rewrite of scrolling text code.
No longer shuffles the string round to minimise the number of characters
before the clipping rectangle; this doesn't save much on rendering time but
does harm the effectiveness of the cache. Now uses a pixel offset into the
string rather than a character + pixel offset, and plots the entire string
every time (execpt when the wrap point is visible, in which case the entire
string is plotted twice).
It also makes motion smoother, because (possibly unintentionally) the
previous code preferred to align the scroll offset with character boundaries.
This would lead to uneven changes of position, especially when the width of
the character currently being scrolled off the edge was only slightly more
than an integral multiple of the scroll increment.
---
xbmc/guilib/GUIFadeLabelControl.cpp | 8 +--
xbmc/guilib/GUIFont.cpp | 123 +++++++++++++-----------------------
xbmc/guilib/GUIFont.h | 17 ++---
xbmc/guilib/GUIRSSControl.cpp | 6 +-
xbmc/utils/RssReader.cpp | 2 +-
xbmc/utils/RssReader.h | 2 +-
6 files changed, 58 insertions(+), 100 deletions(-)
diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp
index 844f960..5859d9f 100644
--- a/xbmc/guilib/GUIFadeLabelControl.cpp
+++ b/xbmc/guilib/GUIFadeLabelControl.cpp
@@ -109,18 +109,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
bool moveToNextLabel = false;
if (!m_scrollOut)
{
- vecText text;
- m_textLayout.GetFirstText(text);
- if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size())
- text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size()));
- if (m_label.font->GetTextWidth(text) < m_width)
+ if (m_scrollInfo.pixelPos + m_width > m_scrollInfo.m_textWidth)
{
if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL)
m_fadeAnim.QueueAnimation(ANIM_PROCESS_NORMAL);
moveToNextLabel = true;
}
}
- else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength())
+ else if (m_scrollInfo.pixelPos > m_scrollInfo.m_textWidth)
moveToNextLabel = true;
// apply the fading animation
diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp
index a7ee668..eb8efdb 100644
--- a/xbmc/guilib/GUIFont.cpp
+++ b/xbmc/guilib/GUIFont.cpp
@@ -36,7 +36,12 @@ CScrollInfo::CScrollInfo(unsigned int wait /* = 50 */, float pos /* = 0 */,
initialWait = wait;
initialPos = pos;
SetSpeed(speed ? speed : defaultSpeed);
- g_charsetConverter.utf8ToW(scrollSuffix, suffix);
+ CStdStringW wsuffix;
+ g_charsetConverter.utf8ToW(scrollSuffix, wsuffix);
+ suffix.clear();
+ suffix.reserve(wsuffix.size());
+ for (vecText::size_type i = 0; i < wsuffix.size(); i++)
+ suffix.push_back(wsuffix[i]);
Reset();
}
@@ -115,11 +120,12 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
{
// draw at our scroll position
// we handle the scrolling as follows:
- // We scroll on a per-pixel basis up until we have scrolled the first character outside
- // of our viewport, whereby we cycle the string around, and reset the scroll position.
- //
- // pixelPos is the amount in pixels to move the string by.
- // characterPos is the amount in characters to rotate the string by.
+ // We scroll on a per-pixel basis (eschewing the use of character indices
+ // which were also in use previously). The complete string, including suffix,
+ // is plotted to achieve the desired effect - normally just the one time, but
+ // if there is a wrap point within the viewport then it will be plotted twice.
+ // If the string is smaller than the viewport, then it may be plotted even
+ // more times than that.
//
if (scrollInfo.waitTime)
{
@@ -135,54 +141,19 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
// move along by the appropriate scroll amount
float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());
- if (scrollInfo.pixelSpeed > 0)
+ if (!scrollInfo.m_widthValid)
{
- // we want to move scrollAmount, grab the next character
- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- if (scrollInfo.pixelPos + scrollAmount < charWidth)
- scrollInfo.pixelPos += scrollAmount; // within the current character
- else
- { // past the current character, decrement scrollAmount by the charWidth and move to the next character
- while (scrollInfo.pixelPos + scrollAmount >= charWidth)
- {
- scrollAmount -= (charWidth - scrollInfo.pixelPos);
- scrollInfo.pixelPos = 0;
- scrollInfo.characterPos++;
- if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
- {
- scrollInfo.Reset();
- break;
- }
- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- }
- }
- }
- else if (scrollInfo.pixelSpeed < 0)
- { // scrolling backwards
- // we want to move scrollAmount, grab the next character
- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- if (scrollInfo.pixelPos + scrollAmount < charWidth)
- scrollInfo.pixelPos += scrollAmount; // within the current character
- else
- { // past the current character, decrement scrollAmount by the charWidth and move to the next character
- while (scrollInfo.pixelPos + scrollAmount >= charWidth)
- {
- scrollAmount -= (charWidth - scrollInfo.pixelPos);
- scrollInfo.pixelPos = 0;
- if (scrollInfo.characterPos == 0)
- {
- scrollInfo.Reset();
- scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
- break;
- }
- scrollInfo.characterPos--;
- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- }
- }
+ /* Calculate the pixel width of the complete string */
+ scrollInfo.m_textWidth = GetTextWidth(text);
+ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
+ scrollInfo.m_widthValid = true;
}
+ scrollInfo.pixelPos += scrollAmount;
+ assert(scrollInfo.m_totalWidth != 0);
+ while (scrollInfo.pixelPos >= scrollInfo.m_totalWidth)
+ scrollInfo.pixelPos -= scrollInfo.m_totalWidth;
- if(scrollInfo.characterPos != old.characterPos
- || scrollInfo.pixelPos != old.pixelPos)
+ if (scrollInfo.pixelPos != old.pixelPos)
return true;
else
return false;
@@ -194,39 +165,27 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
if (!m_font) return;
if (!shadowColor) shadowColor = m_shadowColor;
- float spaceWidth = GetCharWidth(L' ');
- // max chars on screen + extra margin chars
- vecText::size_type maxChars =
- std::min<vecText::size_type>(
- (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
- (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));
-
if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
return; // nothing to render
- maxWidth = ROUND((maxWidth + scrollInfo.pixelPos) / g_graphicsContext.GetGUIScaleX());
+ if (!scrollInfo.m_widthValid)
+ {
+ /* Calculate the pixel width of the complete string */
+ scrollInfo.m_textWidth = GetTextWidth(text);
+ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
+ scrollInfo.m_widthValid = true;
+ }
+
+ assert(scrollInfo.m_totalWidth != 0);
+
+ float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX());
+ float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX());
- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
float offset;
if(scrollInfo.pixelSpeed >= 0)
offset = scrollInfo.pixelPos;
else
- offset = charWidth - scrollInfo.pixelPos;
-
- // Now rotate our string as needed, only take a slightly larger then visible part of the text.
- unsigned int pos = scrollInfo.characterPos;
- vecText renderText;
- renderText.reserve(maxChars);
- for (vecText::size_type i = 0; i < maxChars; i++)
- {
- if (pos >= text.size() + scrollInfo.suffix.size())
- pos = 0;
- if (pos < text.size())
- renderText.push_back(text[pos]);
- else
- renderText.push_back(scrollInfo.suffix[pos - text.size()]);
- pos++;
- }
+ offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos;
vecColors renderColors;
for (unsigned int i = 0; i < colors.size(); i++)
@@ -239,9 +198,17 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
vecColors shadowColors;
for (unsigned int i = 0; i < renderColors.size(); i++)
shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
- m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
+ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
+ {
+ m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll);
+ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
+ }
+ }
+ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
+ {
+ m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll);
+ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
}
- m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
g_graphicsContext.RestoreClipRegion();
}
diff --git a/xbmc/guilib/GUIFont.h b/xbmc/guilib/GUIFont.h
index c55db48..09cf9b3 100644
--- a/xbmc/guilib/GUIFont.h
+++ b/xbmc/guilib/GUIFont.h
@@ -64,7 +64,6 @@ class CScrollInfo
void Reset()
{
waitTime = initialWait;
- characterPos = 0;
// pixelPos is where we start the current letter, so is measured
// to the left of the text rendering's left edge. Thus, a negative
// value will mean the text starts to the right
@@ -72,25 +71,19 @@ class CScrollInfo
// privates:
m_averageFrameTime = 1000.f / abs(defaultSpeed);
m_lastFrameTime = 0;
- }
- uint32_t GetCurrentChar(const vecText &text) const
- {
- assert(text.size());
- if (characterPos < text.size())
- return text[characterPos];
- else if (characterPos < text.size() + suffix.size())
- return suffix[characterPos - text.size()];
- return text[0];
+ m_widthValid = false;
}
float GetPixelsPerFrame();
float pixelPos;
float pixelSpeed;
unsigned int waitTime;
- unsigned int characterPos;
unsigned int initialWait;
float initialPos;
- CStdStringW suffix;
+ vecText suffix;
+ mutable float m_textWidth;
+ mutable float m_totalWidth;
+ mutable bool m_widthValid;
static const int defaultSpeed = 60;
private:
diff --git a/xbmc/guilib/GUIRSSControl.cpp b/xbmc/guilib/GUIRSSControl.cpp
index 8d985cf..a8e20fc 100644
--- a/xbmc/guilib/GUIRSSControl.cpp
+++ b/xbmc/guilib/GUIRSSControl.cpp
@@ -119,7 +119,9 @@ void CGUIRSSControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyre
dirty = true;
if (CRssManager::Get().GetReader(GetID(), GetParentID(), this, m_pReader))
- m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos;
+ {
+ m_scrollInfo.pixelPos = m_pReader->m_savedScrollPixelPos;
+ }
else
{
if (m_strRSSTags != "")
@@ -174,7 +176,7 @@ void CGUIRSSControl::Render()
if (m_pReader)
{
m_pReader->CheckForUpdates();
- m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos;
+ m_pReader->m_savedScrollPixelPos = m_scrollInfo.pixelPos;
}
}
CGUIControl::Render();
diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp
index 5383156..41f9bc2 100644
--- a/xbmc/utils/RssReader.cpp
+++ b/xbmc/utils/RssReader.cpp
@@ -55,7 +55,7 @@ CRssReader::CRssReader() : CThread("RSSReader")
m_pObserver = NULL;
m_spacesBetweenFeeds = 0;
m_bIsRunning = false;
- m_SavedScrollPos = 0;
+ m_savedScrollPixelPos = 0;
m_rtlText = false;
m_requestRefresh = false;
}
diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h
index 2cda726..fbc579e 100644
--- a/xbmc/utils/RssReader.h
+++ b/xbmc/utils/RssReader.h
@@ -43,7 +43,7 @@ class CRssReader : public CThread
void SetObserver(IRssObserver* observer);
void CheckForUpdates();
void requestRefresh();
- unsigned int m_SavedScrollPos;
+ float m_savedScrollPixelPos;
private:
void Process();
From 2a40513f06b7c0e3eb8b23c29de7446c718a6ea5 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Mon, 27 Jan 2014 23:21:10 +0000
Subject: [PATCH 21/99] Move the application of the translation offsets into
the GLES code.
Still all pure software at this stage. Main change is in the data types at
the interface between CGUIFontTTFBase and CGUIFontTTFGL. The old way
(array of vertices in m_vertex) are retained in addition, for the sake`of
cases that need to use software clipping on GLES, as well as for DX and GL
support where the new scheme is not (yet?) used.
---
xbmc/guilib/GUIFontTTF.cpp | 19 +++---------
xbmc/guilib/GUIFontTTF.h | 17 +++++++++++
xbmc/guilib/GUIFontTTFGL.cpp | 72 ++++++++++++++++++++++++++++++++------------
3 files changed, 73 insertions(+), 35 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 412f47a..b0e69c0 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -214,6 +214,7 @@ void CGUIFontTTFBase::Clear()
g_freeTypeLibrary.ReleaseStroker(m_stroker);
m_stroker = NULL;
+ m_vertexTrans.clear();
m_vertex.clear();
}
@@ -309,6 +310,7 @@ void CGUIFontTTFBase::Begin()
{
if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
{
+ m_vertexTrans.clear();
m_vertex.clear();
}
// Keep track of the nested begin/end calls.
@@ -456,23 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
cursorX += ch->advance;
}
if (hardwareClipping)
- /* Append the new vertices (which we have just constructed in the cache)
- * to the set collected since the first Begin() call */
- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
}
else if (hardwareClipping)
- {
- /* Apply the translation offset to the vertices from the cache after
- * appending them to the set collected since the first Begin() call */
- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- SVertex *v;
- for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
- {
- v->x += dynamicPos.m_x;
- v->y += dynamicPos.m_y;
- v->z += dynamicPos.m_z;
- }
- }
+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
if (!hardwareClipping)
/* Append the new vertices (from the cache or otherwise) to the set collected
* since the first Begin() call */
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 39bfa52..e8afc1c 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -61,6 +61,14 @@ struct SVertex
unsigned char r, g, b, a;
#endif
float u, v;
+ struct SVertex Offset(float translate[3]) const
+ {
+ SVertex out = *this;
+ out.x += translate[0];
+ out.y += translate[1];
+ out.z += translate[2];
+ return out;
+ }
};
@@ -159,6 +167,15 @@ class CGUIFontTTFBase
unsigned int m_nTexture;
+ struct CTranslatedVertices
+ {
+ float translateX;
+ float translateY;
+ float translateZ;
+ const std::vector<SVertex> *vertexBuffer;
+ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
+ };
+ std::vector<CTranslatedVertices> m_vertexTrans;
std::vector<SVertex> m_vertex;
float m_textureScaleX;
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index 9935ea4..18c9358 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -167,34 +167,65 @@ void CGUIFontTTFGL::LastEnd()
GLint colLoc = g_Windowing.GUIShaderGetCol();
GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
- // stack object until VBOs will be used
- std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
- SVertex *vertices = &vecVertices[0];
+ // Enable the attributes used by this shader
+ glEnableVertexAttribArray(posLoc);
+ glEnableVertexAttribArray(colLoc);
+ glEnableVertexAttribArray(tex0Loc);
- for (size_t i=0; i<m_vertex.size(); i+=4)
+ if (m_vertex.size() > 0)
{
- *vertices++ = m_vertex[i];
- *vertices++ = m_vertex[i+1];
- *vertices++ = m_vertex[i+2];
+ // Deal with vertices that had to use software clipping
+ std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
+ SVertex *vertices = &vecVertices[0];
- *vertices++ = m_vertex[i+1];
- *vertices++ = m_vertex[i+3];
- *vertices++ = m_vertex[i+2];
- }
+ for (size_t i=0; i<m_vertex.size(); i+=4)
+ {
+ *vertices++ = m_vertex[i];
+ *vertices++ = m_vertex[i+1];
+ *vertices++ = m_vertex[i+2];
- vertices = &vecVertices[0];
+ *vertices++ = m_vertex[i+1];
+ *vertices++ = m_vertex[i+3];
+ *vertices++ = m_vertex[i+2];
+ }
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- // Normalize color values. Does not affect Performance at all.
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
+ vertices = &vecVertices[0];
- glEnableVertexAttribArray(posLoc);
- glEnableVertexAttribArray(colLoc);
- glEnableVertexAttribArray(tex0Loc);
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
+ // Normalize color values. Does not affect Performance at all.
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
+
+ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+ }
+ if (m_vertexTrans.size() > 0)
+ {
+ // Deal with the vertices that can be hardware clipped and therefore translated
+ std::vector<SVertex> vecVertices;
+ for (size_t i = 0; i < m_vertexTrans.size(); i++)
+ {
+ float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
+ for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
+ {
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
+ }
+ }
+ SVertex *vertices = &vecVertices[0];
- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
+ // Normalize color values. Does not affect Performance at all.
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
+
+ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+ }
+ // Disable the attributes used by this shader
glDisableVertexAttribArray(posLoc);
glDisableVertexAttribArray(colLoc);
glDisableVertexAttribArray(tex0Loc);
@@ -222,6 +253,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
if (m_textureHeight < newHeight)
CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
m_staticCache.Flush();
+ m_dynamicCache.Flush();
memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
if (m_texture)
From 0225bf11ee27a23f9401e6148c3760979854da2f Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 15 Jan 2014 15:28:06 +0000
Subject: [PATCH 22/99] Rather than applying the translation offsets to the
vertices, now applies them to the model view matrix from the top of the
matrix stack and pushes it over to OpenGL. The vertices themselves are still
all held client-side.
---
xbmc/guilib/GUIFontTTF.h | 8 -------
xbmc/guilib/GUIFontTTFGL.cpp | 40 +++++++++++++++++++++-----------
xbmc/guilib/GUIShader.h | 1 +
xbmc/rendering/gles/RenderSystemGLES.cpp | 8 +++++++
xbmc/rendering/gles/RenderSystemGLES.h | 1 +
5 files changed, 36 insertions(+), 22 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index e8afc1c..573039d 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -61,14 +61,6 @@ struct SVertex
unsigned char r, g, b, a;
#endif
float u, v;
- struct SVertex Offset(float translate[3]) const
- {
- SVertex out = *this;
- out.x += translate[0];
- out.y += translate[1];
- out.z += translate[2];
- return out;
- }
};
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index 18c9358..ea08bf4 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -29,6 +29,7 @@
#include "utils/log.h"
#include "utils/GLUtils.h"
#include "windowing/WindowingFactory.h"
+#include "guilib/MatrixGLES.h"
// stuff for freetype
#include <ft2build.h>
@@ -166,6 +167,7 @@ void CGUIFontTTFGL::LastEnd()
GLint posLoc = g_Windowing.GUIShaderGetPos();
GLint colLoc = g_Windowing.GUIShaderGetCol();
GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
+ GLint modelLoc = g_Windowing.GUIShaderGetModel();
// Enable the attributes used by this shader
glEnableVertexAttribArray(posLoc);
@@ -204,25 +206,35 @@ void CGUIFontTTFGL::LastEnd()
std::vector<SVertex> vecVertices;
for (size_t i = 0; i < m_vertexTrans.size(); i++)
{
- float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
+ // Apply the translation to the currently active (top-of-stack) model view matrix
+ g_matrices.MatrixMode(MM_MODELVIEW);
+ g_matrices.PushMatrix();
+ g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
+ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
+
+ vecVertices.clear();
for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
{
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
}
- }
- SVertex *vertices = &vecVertices[0];
+ SVertex *vertices = &vecVertices[0];
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- // Normalize color values. Does not affect Performance at all.
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
+ // Normalize color values. Does not affect Performance at all.
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+
+ g_matrices.PopMatrix();
+ }
+ // Restore the original model view matrix
+ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
}
// Disable the attributes used by this shader
diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
index fdf7452..abbe21c 100644
--- a/xbmc/guilib/GUIShader.h
+++ b/xbmc/guilib/GUIShader.h
@@ -39,6 +39,7 @@ class CGUIShader : public Shaders::CGLSLShaderProgram
GLint GetCord1Loc() { return m_hCord1; }
GLint GetUniColLoc() { return m_hUniCol; }
GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
+ GLint GetModelLoc() { return m_hModel; }
bool HardwareClipIsPossible() { return m_clipPossible; }
GLfloat GetClipXFactor() { return m_clipXFactor; }
GLfloat GetClipXOffset() { return m_clipXOffset; }
diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
index deb3afc..0904d1f 100644
--- a/xbmc/rendering/gles/RenderSystemGLES.cpp
+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
@@ -691,4 +691,12 @@ bool CRenderSystemGLES::SupportsStereo(RENDER_STEREO_MODE mode)
}
}
+GLint CRenderSystemGLES::GUIShaderGetModel()
+{
+ if (m_pGUIshader[m_method])
+ return m_pGUIshader[m_method]->GetModelLoc();
+
+ return -1;
+}
+
#endif
diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
index 81ee49e..d2f9cd1 100644
--- a/xbmc/rendering/gles/RenderSystemGLES.h
+++ b/xbmc/rendering/gles/RenderSystemGLES.h
@@ -91,6 +91,7 @@ class CRenderSystemGLES : public CRenderSystemBase
GLint GUIShaderGetCoord1();
GLint GUIShaderGetUniCol();
GLint GUIShaderGetCoord0Matrix();
+ GLint GUIShaderGetModel();
protected:
virtual void SetVSyncImpl(bool enable) = 0;
From f0f3a7eb67396c45efa7ca3e73d8f86da7a94f4d Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 29 Jan 2014 13:21:19 +0000
Subject: [PATCH 23/99] Enable hardware clipping.
---
xbmc/guilib/GUIFontTTF.cpp | 4 ++--
xbmc/guilib/GUIFontTTF.h | 5 ++++-
xbmc/guilib/GUIFontTTFGL.cpp | 6 ++++++
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index b0e69c0..3ea1051 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -458,10 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
cursorX += ch->advance;
}
if (hardwareClipping)
- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
}
else if (hardwareClipping)
- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
if (!hardwareClipping)
/* Append the new vertices (from the cache or otherwise) to the set collected
* since the first Begin() call */
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index 573039d..a6931c1 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -27,6 +27,8 @@
*
*/
+#include "Geometry.h"
+
// forward definition
class CBaseTexture;
@@ -165,7 +167,8 @@ class CGUIFontTTFBase
float translateY;
float translateZ;
const std::vector<SVertex> *vertexBuffer;
- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
+ CRect clip;
+ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
};
std::vector<CTranslatedVertices> m_vertexTrans;
std::vector<SVertex> m_vertex;
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index ea08bf4..b63e337 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -206,6 +206,10 @@ void CGUIFontTTFGL::LastEnd()
std::vector<SVertex> vecVertices;
for (size_t i = 0; i < m_vertexTrans.size(); i++)
{
+ // Apply the clip rectangle
+ CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip);
+ g_Windowing.SetScissors(clip);
+
// Apply the translation to the currently active (top-of-stack) model view matrix
g_matrices.MatrixMode(MM_MODELVIEW);
g_matrices.PushMatrix();
@@ -233,6 +237,8 @@ void CGUIFontTTFGL::LastEnd()
g_matrices.PopMatrix();
}
+ // Restore the original scissor rectangle
+ g_Windowing.ResetScissors();
// Restore the original model view matrix
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
}
From a8ce03ce098cc780bf08fd7d12680ba54382ee2b Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 15 Jan 2014 15:32:51 +0000
Subject: [PATCH 24/99] Move the vertex data across to a vertex buffer object
just prior to drawing.
---
xbmc/guilib/GUIFontTTFGL.cpp | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index b63e337..b00055d 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -228,12 +228,24 @@ void CGUIFontTTFGL::LastEnd()
}
SVertex *vertices = &vecVertices[0];
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- // Normalize color values. Does not affect Performance at all.
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
-
+ // Generate a unique buffer object name and put it in vertexBuffer
+ GLuint vertexBuffer;
+ glGenBuffers(1, &vertexBuffer);
+ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
+ // binding point (i.e. our buffer object) and initialise it from the
+ // specified client-side pointer
+ glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
+ // Set up the offsets of the various vertex attributes within the buffer
+ // object bound to GL_ARRAY_BUFFER
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
+ // Do the actual drawing operation, using the full set of vertices in the buffer
glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
+ // Release the buffer name for reuse
+ glDeleteBuffers(1, &vertexBuffer);
g_matrices.PopMatrix();
}
@@ -241,6 +253,8 @@ void CGUIFontTTFGL::LastEnd()
g_Windowing.ResetScissors();
// Restore the original model view matrix
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
+ // Unbind GL_ARRAY_BUFFER
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Disable the attributes used by this shader
From ba5d1de62ed376b4f621b878730625558fe64eee Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Wed, 15 Jan 2014 16:04:04 +0000
Subject: [PATCH 25/99] Move vertex data into an OpenGL VBO when the font cache
entry is populated.
The font cache now stores the "name" (handle) of the VBO, rather than a vector
of vertices.
---
xbmc/guilib/GUIFontCache.cpp | 6 ++++
xbmc/guilib/GUIFontCache.h | 30 +++++++++++++++++-
xbmc/guilib/GUIFontTTF.cpp | 15 +++++++--
xbmc/guilib/GUIFontTTF.h | 7 +++--
xbmc/guilib/GUIFontTTFGL.cpp | 74 ++++++++++++++++++++++++++++++--------------
xbmc/guilib/GUIFontTTFGL.h | 5 +++
6 files changed, 107 insertions(+), 30 deletions(-)
diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
index df466a5..bd84b9a 100644
--- a/xbmc/guilib/GUIFontCache.cpp
+++ b/xbmc/guilib/GUIFontCache.cpp
@@ -111,3 +111,9 @@ template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDyna
template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
+
+void CVertexBuffer::clear()
+{
+ if (m_font != NULL)
+ m_font->DestroyVertexBuffer(*this);
+}
diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
index d913dee..ff766bf 100644
--- a/xbmc/guilib/GUIFontCache.h
+++ b/xbmc/guilib/GUIFontCache.h
@@ -234,7 +234,35 @@ struct CGUIFontCacheDynamicPosition
}
};
-typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
+struct CVertexBuffer
+{
+ void *bufferHandle;
+ size_t size;
+ CVertexBuffer() : bufferHandle(NULL), size(0), m_font(NULL) {}
+ CVertexBuffer(void *bufferHandle, size_t size, const CGUIFontTTFBase *font) : bufferHandle(bufferHandle), size(size), m_font(font) {}
+ CVertexBuffer(const CVertexBuffer &other) : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font)
+ {
+ /* In practice, the copy constructor is only called before a vertex buffer
+ * has been attached. If this should ever change, we'll need another support
+ * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */
+ assert(other.bufferHandle == 0);
+ }
+ CVertexBuffer &operator=(CVertexBuffer &other)
+ {
+ /* This is used with move-assignment semantics for initialising the object in the font cache */
+ assert(bufferHandle == 0);
+ bufferHandle = other.bufferHandle;
+ other.bufferHandle = 0;
+ size = other.size;
+ m_font = other.m_font;
+ return *this;
+ }
+ void clear();
+private:
+ const CGUIFontTTFBase *m_font;
+};
+
+typedef CVertexBuffer CGUIFontCacheDynamicValue;
inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
index 3ea1051..ea510f4 100644
--- a/xbmc/guilib/GUIFontTTF.cpp
+++ b/xbmc/guilib/GUIFontTTF.cpp
@@ -342,13 +342,18 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
g_graphicsContext.ScaleFinalYCoord(x, y),
g_graphicsContext.ScaleFinalZCoord(x, y));
}
- std::vector<SVertex> &vertices = hardwareClipping ?
+ CVertexBuffer unusedVertexBuffer;
+ CVertexBuffer &vertexBuffer = hardwareClipping ?
m_dynamicCache.Lookup(dynamicPos,
colors, text,
alignment, maxPixelWidth,
scrolling,
XbmcThreads::SystemClockMillis(),
dirtyCache) :
+ unusedVertexBuffer;
+ std::vector<SVertex> tempVertices;
+ std::vector<SVertex> &vertices = hardwareClipping ?
+ tempVertices :
m_staticCache.Lookup(staticPos,
colors, text,
alignment, maxPixelWidth,
@@ -458,10 +463,14 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
cursorX += ch->advance;
}
if (hardwareClipping)
- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
+ {
+ CVertexBuffer newVertexBuffer = CreateVertexBuffer(tempVertices);
+ vertexBuffer = newVertexBuffer;
+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion()));
+ }
}
else if (hardwareClipping)
- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion()));
if (!hardwareClipping)
/* Append the new vertices (from the cache or otherwise) to the set collected
* since the first Begin() call */
diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
index a6931c1..9a35ac4 100644
--- a/xbmc/guilib/GUIFontTTF.h
+++ b/xbmc/guilib/GUIFontTTF.h
@@ -84,6 +84,9 @@ class CGUIFontTTFBase
void Begin();
void End();
+ /* The next two should only be called if we've declared we can do hardware clipping */
+ virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const { assert(false); return CVertexBuffer(); }
+ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const {}
const CStdString& GetFileName() const { return m_strFileName; };
@@ -166,9 +169,9 @@ class CGUIFontTTFBase
float translateX;
float translateY;
float translateZ;
- const std::vector<SVertex> *vertexBuffer;
+ const CVertexBuffer *vertexBuffer;
CRect clip;
- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
+ CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
};
std::vector<CTranslatedVertices> m_vertexTrans;
std::vector<SVertex> m_vertex;
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index b00055d..aabb9a6 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -52,6 +52,10 @@ CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
CGUIFontTTFGL::~CGUIFontTTFGL(void)
{
+ // It's important that all the CGUIFontCacheEntry objects are
+ // destructed before the CGUIFontTTFGL goes out of scope, because
+ // our virtual methods won't be accessible after this point
+ m_dynamicCache.Flush();
}
bool CGUIFontTTFGL::FirstBegin()
@@ -203,7 +207,6 @@ void CGUIFontTTFGL::LastEnd()
if (m_vertexTrans.size() > 0)
{
// Deal with the vertices that can be hardware clipped and therefore translated
- std::vector<SVertex> vecVertices;
for (size_t i = 0; i < m_vertexTrans.size(); i++)
{
// Apply the clip rectangle
@@ -216,36 +219,17 @@ void CGUIFontTTFGL::LastEnd()
g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- vecVertices.clear();
- for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
- {
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- }
- SVertex *vertices = &vecVertices[0];
-
- // Generate a unique buffer object name and put it in vertexBuffer
- GLuint vertexBuffer;
- glGenBuffers(1, &vertexBuffer);
// Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
- // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
- // binding point (i.e. our buffer object) and initialise it from the
- // specified client-side pointer
- glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
+
// Set up the offsets of the various vertex attributes within the buffer
// object bound to GL_ARRAY_BUFFER
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
+
// Do the actual drawing operation, using the full set of vertices in the buffer
- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- // Release the buffer name for reuse
- glDeleteBuffers(1, &vertexBuffer);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
g_matrices.PopMatrix();
}
@@ -266,6 +250,48 @@ void CGUIFontTTFGL::LastEnd()
#endif
}
+#if HAS_GLES
+CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
+{
+ // Rearrange the vertices to describe triangles
+ std::vector<SVertex> triangleVertices;
+ triangleVertices.reserve(vertices.size() * 6 / 4);
+ for (size_t i = 0; i < vertices.size(); i += 4)
+ {
+ triangleVertices.push_back(vertices[i]);
+ triangleVertices.push_back(vertices[i+1]);
+ triangleVertices.push_back(vertices[i+2]);
+ triangleVertices.push_back(vertices[i+1]);
+ triangleVertices.push_back(vertices[i+3]);
+ triangleVertices.push_back(vertices[i+2]);
+ }
+
+ // Generate a unique buffer object name and put it in bufferHandle
+ GLuint bufferHandle;
+ glGenBuffers(1, &bufferHandle);
+ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
+ glBindBuffer(GL_ARRAY_BUFFER, bufferHandle);
+ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
+ // binding point (i.e. our buffer object) and initialise it from the
+ // specified client-side pointer
+ glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
+ // Unbind GL_ARRAY_BUFFER
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ return CVertexBuffer((void *) bufferHandle, vertices.size() / 4, this);
+}
+
+void CGUIFontTTFGL::DestroyVertexBuffer(CVertexBuffer &buffer) const
+{
+ if (buffer.bufferHandle != 0)
+ {
+ // Release the buffer name for reuse
+ glDeleteBuffers(1, (GLuint *) &buffer.bufferHandle);
+ buffer.bufferHandle = 0;
+ }
+}
+#endif
+
CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
{
newHeight = CBaseTexture::PadPow2(newHeight);
diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
index 735fb3a..6102c90 100644
--- a/xbmc/guilib/GUIFontTTFGL.h
+++ b/xbmc/guilib/GUIFontTTFGL.h
@@ -29,6 +29,7 @@
#include "GUIFontTTF.h"
+#include "system.h"
/*!
@@ -43,6 +44,10 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
virtual bool FirstBegin();
virtual void LastEnd();
+#if HAS_GLES
+ virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
+ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
+#endif
protected:
virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
From 3ec6539aba4d894458e3a537632aa550a58a7a27 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 16 Jan 2014 16:29:42 +0000
Subject: [PATCH 26/99] Switch from glDrawArrays() to glDrawElements().
This involves setting up a static VBO containing the indexes necessary to
convert from quads to triangles on the fly in the GPU.
---
xbmc/guilib/GUIFontTTFGL.cpp | 72 +++++++++++++++++++++++++------------
xbmc/guilib/GUIFontTTFGL.h | 11 +++++-
xbmc/windowing/egl/WinSystemEGL.cpp | 17 +++++++++
3 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
index aabb9a6..812662c 100644
--- a/xbmc/guilib/GUIFontTTFGL.cpp
+++ b/xbmc/guilib/GUIFontTTFGL.cpp
@@ -207,6 +207,10 @@ void CGUIFontTTFGL::LastEnd()
if (m_vertexTrans.size() > 0)
{
// Deal with the vertices that can be hardware clipped and therefore translated
+
+ // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
+
for (size_t i = 0; i < m_vertexTrans.size(); i++)
{
// Apply the clip rectangle
@@ -222,14 +226,21 @@ void CGUIFontTTFGL::LastEnd()
// Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
- // Set up the offsets of the various vertex attributes within the buffer
- // object bound to GL_ARRAY_BUFFER
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
+ // Do the actual drawing operation, split into groups of characters no
+ // larger than the pre-determined size of the element array
+ for (size_t character = 0; m_vertexTrans[i].vertexBuffer->size > character; character += ELEMENT_ARRAY_MAX_CHAR_INDEX)
+ {
+ size_t count = m_vertexTrans[i].vertexBuffer->size - character;
+ count = std::min<size_t>(count, ELEMENT_ARRAY_MAX_CHAR_INDEX);
+
+ // Set up the offsets of the various vertex attributes within the buffer
+ // object bound to GL_ARRAY_BUFFER
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, x)));
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, r)));
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, u)));
- // Do the actual drawing operation, using the full set of vertices in the buffer
- glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
+ glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0);
+ }
g_matrices.PopMatrix();
}
@@ -237,8 +248,9 @@ void CGUIFontTTFGL::LastEnd()
g_Windowing.ResetScissors();
// Restore the original model view matrix
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- // Unbind GL_ARRAY_BUFFER
+ // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
// Disable the attributes used by this shader
@@ -253,19 +265,6 @@ void CGUIFontTTFGL::LastEnd()
#if HAS_GLES
CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
{
- // Rearrange the vertices to describe triangles
- std::vector<SVertex> triangleVertices;
- triangleVertices.reserve(vertices.size() * 6 / 4);
- for (size_t i = 0; i < vertices.size(); i += 4)
- {
- triangleVertices.push_back(vertices[i]);
- triangleVertices.push_back(vertices[i+1]);
- triangleVertices.push_back(vertices[i+2]);
- triangleVertices.push_back(vertices[i+1]);
- triangleVertices.push_back(vertices[i+3]);
- triangleVertices.push_back(vertices[i+2]);
- }
-
// Generate a unique buffer object name and put it in bufferHandle
GLuint bufferHandle;
glGenBuffers(1, &bufferHandle);
@@ -274,7 +273,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vert
// Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
// binding point (i.e. our buffer object) and initialise it from the
// specified client-side pointer
- glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW);
// Unbind GL_ARRAY_BUFFER
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -393,4 +392,33 @@ void CGUIFontTTFGL::DeleteHardwareTexture()
}
}
+#if HAS_GLES
+void CGUIFontTTFGL::CreateStaticVertexBuffers(void)
+{
+ // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point
+ glGenBuffers(1, &m_elementArrayHandle);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
+ // Create an array holding the mesh indices to convert quads to triangles
+ GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6];
+ for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++)
+ {
+ index[i][0] = 4*i;
+ index[i][1] = 4*i+1;
+ index[i][2] = 4*i+2;
+ index[i][3] = 4*i+1;
+ index[i][4] = 4*i+3;
+ index[i][5] = 4*i+2;
+ }
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+void CGUIFontTTFGL::DestroyStaticVertexBuffers(void)
+{
+ glDeleteBuffers(1, &m_elementArrayHandle);
+}
+
+GLuint CGUIFontTTFGL::m_elementArrayHandle;
+#endif
+
#endif
diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
index 6102c90..dcf9ca1 100644
--- a/xbmc/guilib/GUIFontTTFGL.h
+++ b/xbmc/guilib/GUIFontTTFGL.h
@@ -30,6 +30,7 @@
#include "GUIFontTTF.h"
#include "system.h"
+#include "system_gl.h"
/*!
@@ -47,13 +48,21 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
#if HAS_GLES
virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
+ static void CreateStaticVertexBuffers(void);
+ static void DestroyStaticVertexBuffers(void);
#endif
protected:
virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2);
virtual void DeleteHardwareTexture();
-
+
+#if HAS_GLES
+#define ELEMENT_ARRAY_MAX_CHAR_INDEX (1000)
+
+ static GLuint m_elementArrayHandle;
+#endif
+
private:
unsigned int m_updateY1;
unsigned int m_updateY2;
diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
index 6de3532..258a293 100644
--- a/xbmc/windowing/egl/WinSystemEGL.cpp
+++ b/xbmc/windowing/egl/WinSystemEGL.cpp
@@ -29,6 +29,7 @@
#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "settings/DisplaySettings.h"
+#include "guilib/GUIFontTTFGL.h"
#include "utils/log.h"
#include "EGLWrapper.h"
#include "EGLQuirks.h"
@@ -193,6 +194,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
return false;
}
+#if HAS_GLES
+ bool newContext = false;
+#endif
if (m_context == EGL_NO_CONTEXT)
{
if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context))
@@ -200,6 +204,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__);
return false;
}
+#if HAS_GLES
+ newContext = true;
+#endif
}
if (!m_egl->BindContext(m_display, m_surface, m_context))
@@ -208,6 +215,11 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
return false;
}
+#if HAS_GLES
+ if (newContext)
+ CGUIFontTTFGL::CreateStaticVertexBuffers();
+#endif
+
// for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates
if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION ||
g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION)
@@ -229,7 +241,12 @@ bool CWinSystemEGL::DestroyWindowSystem()
DestroyWindow();
if (m_context != EGL_NO_CONTEXT)
+ {
+#if HAS_GLES
+ CGUIFontTTFGL::DestroyStaticVertexBuffers();
+#endif
m_egl->DestroyContext(m_display, m_context);
+ }
m_context = EGL_NO_CONTEXT;
if (m_display != EGL_NO_DISPLAY)
From a662cca8f8e0208b92ef71c00743f31d27bb7055 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 1 May 2014 16:28:39 +0100
Subject: [PATCH 27/99] Improved file buffering in CArchive
Even though memcpy is typically inlined by the compiler into byte/word loads
and stores (at least for release builds), the frequency with which 1, 2 and 4
byte loads/stores are encountered in cases where the size is *not*
determinable at compile time is still high enough that it's worth handling
these specially. On the ARM1176JZF-S in the Raspberry Pi, this improves the
total time to open a library (in the case where it's fetched from a CArchive)
by around 4%.
It should be noted that this code uses 16-bit and 32-bit word loads and
stores that are not necessarily aligned to their respective widths. It is
possible that there are some architectures out there which do not support
this, although all ARMs since ARMv6 have supported it (and ARMs earlier than
that are probably not powerful enough to be good targets for XBMC).
---
xbmc/utils/Archive.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
index 6ed0f8f..8506d95 100644
--- a/xbmc/utils/Archive.h
+++ b/xbmc/utils/Archive.h
@@ -154,9 +154,17 @@ class CArchive
* than waiting until we attempt to put more data into an already full buffer */
if (m_BufferRemain > size)
{
+ switch (size)
+ {
+ case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break;
+ case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break;
+ case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break;
+ default:
memcpy(m_BufferPos, ptr, size);
m_BufferPos += size;
m_BufferRemain -= size;
+ break;
+ }
return *this;
}
else
@@ -171,9 +179,17 @@ class CArchive
/* Note, refilling the buffer is deferred until we know we need to read more from it */
if (m_BufferRemain >= size)
{
+ switch (size)
+ {
+ case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break;
+ case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break;
+ case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break;
+ default:
memcpy(ptr, m_BufferPos, size);
m_BufferPos += size;
m_BufferRemain -= size;
+ break;
+ }
return *this;
}
else
From 551b00e9f67182d167102565ee7cbfe58619eb80 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 10 Sep 2014 22:07:21 +0100
Subject: [PATCH 28/99] [mmal] Allow mmal codec for dvd stills
---
xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index f139433..4183a2b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -192,6 +192,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
#endif
CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
+#if defined(HAS_MMAL)
+ // mmal can handle dvd playback including stills
+ if (!CSettings::Get().GetBool("videoplayer.usemmal"))
+#endif
if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO))
{
// If dvd is an mpeg2 and hint.stills
From 91b24766d05447e555bba1597f1c3ed5f3bc9120 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 2 Aug 2014 17:47:38 +0100
Subject: [PATCH 30/99] [VideoReferenceClock] Add OMX support
---
xbmc/linux/RBP.cpp | 34 ++++++++++++++++++++++++
xbmc/linux/RBP.h | 3 +++
xbmc/video/VideoReferenceClock.cpp | 53 ++++++++++++++++++++++++++++++++++++++
xbmc/video/VideoReferenceClock.h | 6 +++++
4 files changed, 96 insertions(+)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 73a42c4..11376fc 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -32,6 +32,7 @@ CRBP::CRBP()
m_omx_initialized = false;
m_DllBcmHost = new DllBcmHost();
m_OMX = new COMXCore();
+ m_element = 0;
}
CRBP::~CRBP()
@@ -53,6 +54,9 @@ bool CRBP::Initialize()
m_DllBcmHost->bcm_host_init();
+ uint32_t vc_image_ptr;
+ m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr );
+
m_omx_initialized = m_OMX->Initialize();
if(!m_omx_initialized)
return false;
@@ -156,6 +160,36 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
return image;
}
+void CRBP::WaitVsync(void)
+{
+ DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ );
+ DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
+
+ VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 };
+ VC_RECT_T src_rect;
+ VC_RECT_T dst_rect;
+ vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 );
+ vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 );
+
+ if (m_element)
+ vc_dispmanx_element_remove( update, m_element );
+
+ m_element = vc_dispmanx_element_add( update,
+ display,
+ 2000, // layer
+ &dst_rect,
+ m_resource,
+ &src_rect,
+ DISPMANX_PROTECTION_NONE,
+ &alpha,
+ NULL, // clamp
+ (DISPMANX_TRANSFORM_T)0 );
+
+ vc_dispmanx_update_submit_sync(update);
+ vc_dispmanx_display_close( display );
+}
+
+
void CRBP::Deinitialize()
{
if (m_omx_image_init)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index e9a2d5a..4fd18f3 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -57,6 +57,7 @@ class CRBP
// stride can be null for packed output
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
+ void WaitVsync();
private:
DllBcmHost *m_DllBcmHost;
@@ -69,6 +70,8 @@ class CRBP
bool m_codec_mpg2_enabled;
bool m_codec_wvc1_enabled;
COMXCore *m_OMX;
+ DISPMANX_RESOURCE_HANDLE_T m_resource;
+ DISPMANX_ELEMENT_HANDLE_T m_element;
class DllLibOMXCore;
CCriticalSection m_critSection;
};
diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 6d84b60..916a15c 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -50,6 +50,9 @@
#endif
#include "windowing/WindowingFactory.h"
#include "settings/AdvancedSettings.h"
+#elif defined(TARGET_RASPBERRY_PI)
+ #include "guilib/GraphicContext.h"
+ #include "linux/RBP.h"
#endif
using namespace std;
@@ -177,6 +180,8 @@ void CVideoReferenceClock::Process()
CLog::Log(LOGDEBUG, "CVideoReferenceClock: compiled without RandR support");
#elif defined(TARGET_WINDOWS)
CLog::Log(LOGDEBUG, "CVideoReferenceClock: only available on directx build");
+#elif defined(TARGET_RASPBERRY_PI)
+ SetupSuccess = SetupOMX();
#else
CLog::Log(LOGDEBUG, "CVideoReferenceClock: no implementation available");
#endif
@@ -205,6 +210,8 @@ void CVideoReferenceClock::Process()
RunD3D();
#elif defined(TARGET_DARWIN)
RunCocoa();
+#elif defined(TARGET_RASPBERRY_PI)
+ RunOMX();
#endif
}
@@ -237,6 +244,8 @@ void CVideoReferenceClock::Process()
CleanupD3D();
#elif defined(TARGET_DARWIN)
CleanupCocoa();
+#elif defined(TARGET_RASPBERRY_PI)
+ CleanupOMX();
#endif
if (!SetupSuccess) break;
}
@@ -863,6 +872,50 @@ void CVideoReferenceClock::VblankHandler(int64_t nowtime, double fps)
SendVblankSignal();
UpdateRefreshrate();
}
+#elif defined(TARGET_RASPBERRY_PI)
+bool CVideoReferenceClock::SetupOMX()
+{
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: setting up OMX");
+
+ //init the vblank timestamp
+ m_MissedVblanks = 0;
+ m_RefreshRate = g_graphicsContext.GetFPS();
+
+ UpdateRefreshrate(true);
+ return true;
+}
+
+void CVideoReferenceClock::RunOMX()
+{
+ CSingleLock SingleLock(m_CritSection);
+ SingleLock.Leave();
+
+ while(!m_bStop)
+ {
+ g_RBP.WaitVsync();
+
+ m_RefreshRate = g_graphicsContext.GetFPS();
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock:%s fps:%.2f missed:%d Time:%.3f", __func__, m_RefreshRate, m_TotalMissedVblanks, m_CurrTime * 1e-6);
+ //update the vblank timestamp, update the clock and send a signal that we got a vblank
+ SingleLock.Enter();
+ m_VblankTime = CurrentHostCounter();
+ UpdateClock(1, true);
+ SingleLock.Leave();
+ SendVblankSignal();
+
+ if (UpdateRefreshrate())
+ {
+ //we have to measure the refreshrate again
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Displaymode changed");
+ return;
+ }
+ }
+}
+
+void CVideoReferenceClock::CleanupOMX()
+{
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: cleaning up OMX");
+}
#endif
//this is called from the vblank run function and from CVideoReferenceClock::Wait in case of a late update
diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h
index 6027031..2dabac1 100644
--- a/xbmc/video/VideoReferenceClock.h
+++ b/xbmc/video/VideoReferenceClock.h
@@ -150,6 +150,12 @@ class CVideoReferenceClock : public CThread
int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened
//not the same as m_VblankTime
+#elif defined(TARGET_RASPBERRY_PI)
+ bool SetupOMX();
+ void RunOMX();
+ void CleanupOMX();
+ int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened
+ //not the same as m_VblankTime
#endif
};
From a0daccf59266bc73f53cd2a228ff7ee038b96ae4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 12 Aug 2014 00:03:18 +0100
Subject: [PATCH 31/99] videoreferenceclock: Boost priority
---
xbmc/video/VideoReferenceClock.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 916a15c..c491d29 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -157,6 +157,9 @@ void CVideoReferenceClock::Process()
bool SetupSuccess = false;
int64_t Now;
+ /* This shouldn't be very busy and timing is important so increase priority */
+ SetPriority(GetPriority()+1);
+
#if defined(TARGET_WINDOWS) && defined(HAS_DX)
//register callback
m_D3dCallback.Reset();
From 05f051804af616f5b49eace7bd2317a96294d10f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 5 Feb 2014 11:46:33 +0000
Subject: [PATCH 32/99] [rbp/settings] Allow av sync type to be enabled
It works for dvdplayer
---
system/settings/rbp.xml | 7 -------
1 file changed, 7 deletions(-)
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 570798b..e09d974 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -1,13 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<section id="videos">
- <category id="videoplayer">
- <group id="2">
- <setting id="videoplayer.synctype">
- <visible>false</visible>
- </setting>
- </group>
- </category>
<category id="videoacceleration">
<group id="1">
<visible>false</visible>
From 650a56964c98baebeb2197d2fdd7402677347ef9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 16 Apr 2014 21:18:06 +0100
Subject: [PATCH 37/99] [omxplayer] Don't propagate 3d flags based on supported
3d modes
---
xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++-------------------------
1 file changed, 4 insertions(+), 25 deletions(-)
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 2c25fd9..c2bd788 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -759,36 +759,15 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
unsigned flags = 0;
ERenderFormat format = RENDER_FMT_BYPASS;
+ /* figure out steremode expected based on user settings and hints */
+ unsigned int stereo_flags = GetStereoModeFlags(GetStereoMode());
+
if(m_bAllowFullscreen)
{
flags |= CONF_FLAGS_FULLSCREEN;
m_bAllowFullscreen = false; // only allow on first configure
}
-
- flags |= GetStereoModeFlags(GetStereoMode());
-
- if(flags & CONF_FLAGS_STEREO_MODE_SBS)
- {
- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
- CLog::Log(LOGNOTICE, "3DSBS movie found");
- else
- {
- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
- CLog::Log(LOGNOTICE, "3DSBS movie found but not supported");
- }
- }
- else if(flags & CONF_FLAGS_STEREO_MODE_TAB)
- {
- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
- CLog::Log(LOGNOTICE, "3DTB movie found");
- else
- {
- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
- CLog::Log(LOGNOTICE, "3DTB movie found but not supported");
- }
- }
- else
- CLog::Log(LOGNOTICE, "not a 3D movie");
+ flags |= stereo_flags;
unsigned int iDisplayWidth = width;
unsigned int iDisplayHeight = height;
From 44a8c528fd577b270aeb627e28d5620b514f0328 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 17 Apr 2014 13:00:52 +0100
Subject: [PATCH 38/99] [graphics] Don't set stereo mode based on resolution
The resolution change should follow stereo mode
---
xbmc/guilib/GraphicContext.cpp | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index 5bffdf5..4be1c8b 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -420,26 +420,29 @@ void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
RESOLUTION_INFO info_org = CDisplaySettings::Get().GetResolutionInfo(res);
RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes);
- RENDER_STEREO_MODE stereo_mode = m_stereoMode;
-
// if the new mode is an actual stereo mode, switch to that
// if the old mode was an actual stereo mode, switch to no 3d mode
- if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
- stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
- else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
- stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
- else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
- || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0)
- stereo_mode = RENDER_STEREO_MODE_OFF;
-
- if(stereo_mode != m_stereoMode)
+ // only do this if 3D flags have changed
+ if ((info_org.dwFlags ^ info_last.dwFlags) & (D3DPRESENTFLAG_MODE3DTB | D3DPRESENTFLAG_MODE3DSBS))
{
- m_stereoView = RENDER_STEREO_VIEW_OFF;
- m_stereoMode = stereo_mode;
- m_nextStereoMode = stereo_mode;
- CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode);
- }
+ RENDER_STEREO_MODE stereo_mode = m_stereoMode;
+
+ if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
+ stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
+ else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+ stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
+ else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
+ || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0)
+ stereo_mode = RENDER_STEREO_MODE_OFF;
+ if(stereo_mode != m_stereoMode)
+ {
+ m_stereoView = RENDER_STEREO_VIEW_OFF;
+ m_stereoMode = stereo_mode;
+ m_nextStereoMode = stereo_mode;
+ CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode);
+ }
+ }
RESOLUTION_INFO info_mod = GetResInfo(res);
m_iScreenWidth = info_mod.iWidth;
From 1160a07cd80a264d5ddef8b9a98199c749cf498e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 17 Apr 2014 13:01:51 +0100
Subject: [PATCH 39/99] [graphics] Allow switching to a more suitable 3D
resolution
---
xbmc/guilib/GraphicContext.cpp | 40 +++++++++++++++++++++++++++++++++++++++-
xbmc/guilib/GraphicContext.h | 1 +
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index 4be1c8b..792a77d 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -35,6 +35,7 @@
#include "utils/JobManager.h"
#include "video/VideoReferenceClock.h"
#include "cores/IPlayer.h"
+#include <float.h>
using namespace std;
@@ -484,6 +485,43 @@ RESOLUTION CGraphicContext::GetVideoResolution() const
return m_Resolution;
}
+RESOLUTION CGraphicContext::Get3DVideoResolution(RESOLUTION resolution, RENDER_STEREO_MODE mode) const
+{
+ RESOLUTION best = resolution;
+ RESOLUTION_INFO curr = CDisplaySettings::Get().GetResolutionInfo(best);
+ // Find closest refresh rate
+ for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
+ {
+ const RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo((RESOLUTION)i);
+
+ //discard resolutions that are not the same width and height (and interlaced/3D flags)
+ //or have a too low refreshrate
+ if (info.iScreenWidth != curr.iScreenWidth
+ || info.iScreenHeight != curr.iScreenHeight
+ || info.iScreen != curr.iScreen
+ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
+ || fabs(info.fRefreshRate - curr.fRefreshRate) >= FLT_EPSILON)
+ continue;
+
+ if (mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+ {
+ best = (RESOLUTION)i;
+ break;
+ }
+ else if (mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
+ {
+ best = (RESOLUTION)i;
+ break;
+ }
+ else if ((mode == RENDER_STEREO_MODE_OFF || mode == RENDER_STEREO_MODE_MONO) && !(info.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)))
+ {
+ best = (RESOLUTION)i;
+ break;
+ }
+ }
+ return best;
+}
+
void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
{
res.Overscan.left = 0;
@@ -1021,7 +1059,7 @@ void CGraphicContext::Flip(const CDirtyRegionList& dirty)
if(m_stereoMode != m_nextStereoMode)
{
m_stereoMode = m_nextStereoMode;
- SetVideoResolution(GetVideoResolution(), true);
+ SetVideoResolution(Get3DVideoResolution(m_Resolution, m_stereoMode), true);
g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
}
}
diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
index 0a27643..ef5bc74 100644
--- a/xbmc/guilib/GraphicContext.h
+++ b/xbmc/guilib/GraphicContext.h
@@ -108,6 +108,7 @@ class CGraphicContext : public CCriticalSection,
bool IsValidResolution(RESOLUTION res);
void SetVideoResolution(RESOLUTION res, bool forceUpdate = false);
RESOLUTION GetVideoResolution() const;
+ RESOLUTION Get3DVideoResolution(RESOLUTION resolution, RENDER_STEREO_MODE mode) const;
void ResetOverscan(RESOLUTION res, OVERSCAN &overscan);
void ResetOverscan(RESOLUTION_INFO &resinfo);
void ResetScreenParameters(RESOLUTION res);
From 01d7fa85b9e1c7772e03c7ed43b1f02e9112da02 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 17 Apr 2014 13:38:55 +0100
Subject: [PATCH 40/99] [3D] Support switching to 3D resolutions
Include matching 3D flags (SBS/TAB) in the score of a resolution to switch to, to enable switching to 3d modes.
Also remove the old code that treated 3D modes differently when assigning a score.
---
xbmc/cores/VideoRenderers/BaseRenderer.cpp | 47 +++++++++++-------------------
1 file changed, 17 insertions(+), 30 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
index 83c3adb..8076e76 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
@@ -222,10 +222,14 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight)
{
RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current);
+ RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode();
float fRefreshRate = fps;
- float last_diff = fRefreshRate;
+ int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
+ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
+ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DTB))
+ c_weight += 1000;
// Find closest refresh rate
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
@@ -241,40 +245,23 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
|| info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
continue;
- // For 3D choose the closest refresh rate
- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
- {
- float diff = (info.fRefreshRate - fRefreshRate);
- if(diff < 0)
- diff *= -1.0f;
+ int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
- if(diff < last_diff)
- {
- last_diff = diff;
- current = (RESOLUTION)i;
- curr = info;
- }
- }
- else
- {
- int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
- int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
+ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
+ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DTB))
+ i_weight += 1000;
- // Closer the better, prefer higher refresh rate if the same
- if ((i_weight < c_weight)
- || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
- {
- current = (RESOLUTION)i;
- curr = info;
- }
+ // Closer the better, prefer higher refresh rate if the same
+ if ((i_weight < c_weight)
+ || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
+ {
+ current = (RESOLUTION)i;
+ curr = info;
+ c_weight = i_weight;
}
}
- // For 3D overwrite weight
- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
- weight = 0;
- else
- weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
+ weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
return current;
}
From 600c839947ddeb8328c1c21feea3794bd46b2050 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 23 Apr 2014 00:05:07 +0100
Subject: [PATCH 41/99] [graphics] Make pixel ratio for 3d modes consistent
Note: Use the stored stereo flags from lists of resolutions.
Use current stereo mode for current resolution.
---
xbmc/cores/VideoRenderers/BaseRenderer.cpp | 10 +++----
xbmc/guilib/GraphicContext.cpp | 37 ++++++++++++-------------
xbmc/guilib/GraphicContext.h | 12 ++++++--
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 8 ------
4 files changed, 32 insertions(+), 35 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
index 8076e76..9118cb0 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
@@ -119,7 +119,7 @@ bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fa
for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++)
{
- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j);
+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j, g_graphicsContext.GetStereoMode((RESOLUTION)j));
if (info.iScreenWidth == curr.iScreenWidth
&& info.iScreenHeight == curr.iScreenHeight
@@ -179,7 +179,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
//get the resolution with the refreshrate closest to 60 hertz
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
{
- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i));
if (MathUtils::round_int(info.fRefreshRate) == 60
&& info.iScreenWidth == curr.iScreenWidth
@@ -200,7 +200,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest");
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
{
- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i));
if (info.fRefreshRate > curr.fRefreshRate
&& info.iScreenWidth == curr.iScreenWidth
@@ -234,14 +234,14 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
// Find closest refresh rate
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
{
- const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
+ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i));
//discard resolutions that are not the same width and height (and interlaced/3D flags)
//or have a too low refreshrate
if (info.iScreenWidth != curr.iScreenWidth
|| info.iScreenHeight != curr.iScreenHeight
|| info.iScreen != curr.iScreen
- || (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
+ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
|| info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
continue;
diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index 792a77d..4890711 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -731,32 +731,33 @@ void CGraphicContext::ApplyStateBlock()
g_Windowing.ApplyStateBlock();
}
-const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
+RENDER_STEREO_MODE CGraphicContext::GetStereoMode(RESOLUTION res) const
{
RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res);
+ return (info.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL :
+ (info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL : RENDER_STEREO_MODE_OFF;
+}
- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
+const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res, RENDER_STEREO_MODE stereoMode) const
+{
+ RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res);
+
+ if(stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
{
- if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
- {
- info.fPixelRatio /= 2;
- info.iBlanking = 0;
- info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- }
+ info.fPixelRatio /= 2;
+ info.iBlanking = 0;
+ info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
info.iHeight = (info.iHeight - info.iBlanking) / 2;
info.Overscan.top /= 2;
info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2;
info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2;
}
- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+ if(stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
{
- if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
- {
- info.fPixelRatio *= 2;
- info.iBlanking = 0;
- info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- }
+ info.fPixelRatio *= 2;
+ info.iBlanking = 0;
+ info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
info.iWidth = (info.iWidth - info.iBlanking) / 2;
info.Overscan.left /= 2;
info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2;
@@ -774,16 +775,14 @@ void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
{
curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking;
- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
- curr.fPixelRatio /= 2.0;
+ curr.fPixelRatio /= 2.0;
}
if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
{
curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking;
curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking;
- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
- curr.fPixelRatio *= 2.0;
+ curr.fPixelRatio *= 2.0;
}
}
diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
index ef5bc74..c665031 100644
--- a/xbmc/guilib/GraphicContext.h
+++ b/xbmc/guilib/GraphicContext.h
@@ -120,11 +120,15 @@ class CGraphicContext : public CCriticalSection,
void GetAllowedResolutions(std::vector<RESOLUTION> &res);
// output scaling
+ const RESOLUTION_INFO GetResInfo(RESOLUTION res) const
+ {
+ return GetResInfo(res, GetStereoMode());
+ }
const RESOLUTION_INFO GetResInfo() const
{
return GetResInfo(m_Resolution);
}
- const RESOLUTION_INFO GetResInfo(RESOLUTION res) const;
+ const RESOLUTION_INFO GetResInfo(RESOLUTION res, RENDER_STEREO_MODE stereo_mode) const;
void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info);
/* \brief Get UI scaling information from a given resolution to the screen resolution.
@@ -161,9 +165,11 @@ class CGraphicContext : public CCriticalSection,
void RestoreOrigin();
void SetCameraPosition(const CPoint &camera);
void SetStereoView(RENDER_STEREO_VIEW view);
- RENDER_STEREO_VIEW GetStereoView() { return m_stereoView; }
+ RENDER_STEREO_VIEW GetStereoView() const { return m_stereoView; }
void SetStereoMode(RENDER_STEREO_MODE mode) { m_nextStereoMode = mode; }
- RENDER_STEREO_MODE GetStereoMode() { return m_stereoMode; }
+ RENDER_STEREO_MODE GetStereoMode() const { return m_stereoMode; }
+ RENDER_STEREO_MODE GetStereoMode(RESOLUTION res) const;
+
void RestoreCameraPosition();
/*! \brief Set a region in which to clip all rendering
Anything that is rendered after setting a clip region will be clipped so that no part renders
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index c58c28a..bf1e589 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -449,15 +449,9 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
m_desktopRes.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
// Also add 3D flags
if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
- {
m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- m_desktopRes.fPixelRatio *= 2.0;
- }
else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF)
- {
m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- m_desktopRes.fPixelRatio *= 0.5;
- }
HDMI_PROPERTY_PARAM_T property;
property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
vc_tv_hdmi_get_property(&property);
@@ -600,7 +594,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
RESOLUTION_INFO res2 = res;
res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- res2.fPixelRatio *= 2.0f;
res2.iSubtitles = (int)(0.965 * res2.iHeight);
AddUniqueResolution(res2, resolutions);
@@ -616,7 +609,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
RESOLUTION_INFO res2 = res;
res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- res2.fPixelRatio *= 0.5f;
res2.iSubtitles = (int)(0.965 * res2.iHeight);
AddUniqueResolution(res2, resolutions);
From 3f99e3d224941891c549d9169e13d844e1bc5b66 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 10 Aug 2014 16:45:16 +0100
Subject: [PATCH 42/99] filesystem: Make support of browsing into archives
optional
The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices.
It's quite common to see reports of a large rar file that causes xbmc to crash with an out-of-memory error when browsing or scanning.
It also can be slow as any archive in the directory is opened and extracted.
Add a settings option to enable this feature and default to disabled on Pi
---
language/English/strings.po | 10 ++++++++++
system/settings/rbp.xml | 10 ++++++++++
system/settings/settings.xml | 5 +++++
xbmc/filesystem/FileDirectoryFactory.cpp | 4 ++++
4 files changed, 29 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index f8e7820..260ac22 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15931,3 +15931,13 @@ msgstr ""
msgctxt "#37031"
msgid "Specifies how Blu-rays should be opened/played back. Disc menus are not fully supported yet and may cause problems."
msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38020"
+msgid "Support browsing into archives"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38021"
+msgid "Allow viewing and playing files in archives (e.g. zip, rar)"
+msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index e09d974..9cc4fd2 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -1,5 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<settings>
+ <section id="appearance">
+ <category id="filelists">
+ <group id="1">
+ <setting id="filelists.browsearchives">
+ <default>false</default>
+ </setting>
+ </group>
+ </category>
+ </section>
+
<section id="videos">
<category id="videoacceleration">
<group id="1">
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 304c308..ef6c141 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -226,6 +226,11 @@
<default>false</default>
<control type="toggle" />
</setting>
+ <setting id="filelists.browsearchives" type="boolean" label="38020" help="38021">
+ <level>1</level>
+ <default>true</default>
+ <control type="toggle" />
+ </setting>
</group>
</category>
<category id="screensaver" label="360" help="36128">
diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp
index 2fd8777..3b294cd 100644
--- a/xbmc/filesystem/FileDirectoryFactory.cpp
+++ b/xbmc/filesystem/FileDirectoryFactory.cpp
@@ -46,6 +46,7 @@
#include "Directory.h"
#include "File.h"
#include "ZipManager.h"
+#include "settings/Settings.h"
#include "settings/AdvancedSettings.h"
#include "FileItem.h"
#include "utils/StringUtils.h"
@@ -142,6 +143,8 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem,
return NULL;
}
#endif
+ if (CSettings::Get().GetBool("filelists.browsearchives"))
+ {
if (url.IsFileType("zip"))
{
CURL zipURL = URIUtils::CreateArchivePath("zip", url);
@@ -215,6 +218,7 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem,
}
return NULL;
}
+ }
if (url.IsFileType("xsp"))
{ // XBMC Smart playlist - just XML renamed to XSP
// read the name of the playlist in
From 7d00ed3ce60079e9309d42e753c008edb5e6458f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 11 Aug 2014 22:56:13 +0100
Subject: [PATCH 44/99] [omxplayer] Add acceleration option to choose
omxplayer/dvdplayer automatically
---
language/English/strings.po | 10 +++++++
system/settings/settings.xml | 9 ++++++
xbmc/cores/dvdplayer/DVDPlayer.cpp | 58 ++++++++++++++++++++++++++++++++++++++
3 files changed, 77 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index 260ac22..160e83c 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15941,3 +15941,13 @@ msgstr ""
msgctxt "#38021"
msgid "Allow viewing and playing files in archives (e.g. zip, rar)"
msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#37033"
+msgid "Select omxplayer or dvdplayer automatically"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#37034"
+msgid "Uses codec information and audio setting to choose dvdplayer or omxplayer as appropriate"
+msgstr ""
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index ef6c141..14f18d9 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -751,6 +751,15 @@
<default>true</default>
<control type="toggle" />
</setting>
+ <setting id="videoplayer.autoomxplayer" type="boolean" label="37033" help="37033">
+ <requirement>HAS_OMXPLAYER</requirement>
+ <dependencies>
+ <dependency type="enable" setting="videoplayer.decodingmethod" operator="is">1</dependency>
+ </dependencies>
+ <level>2</level>
+ <default>true</default>
+ <control type="toggle" />
+ </setting>
<setting id="videoplayer.useomxplayer" type="boolean" label="13458" help="13459">
<requirement>HAS_OMXPLAYER</requirement>
<dependencies>
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index bbcf514..c89aae2 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -490,6 +490,62 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer, std::
void CDVDPlayer::CreatePlayers()
{
+#ifdef HAS_OMXPLAYER
+ bool omxplayer_mode = m_omxplayer_mode;
+ bool autoomx = CSettings::Get().GetBool("videoplayer.autoomxplayer");
+ // omxplayer only handles Pi sink
+ if (autoomx && m_omxplayer_mode &&
+ CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue" &&
+ CSettings::Get().GetString("audiooutput.audiodevice") != "PI:HDMI")
+ {
+ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to audio sink", __func__);
+ m_omxplayer_mode = false;
+ }
+ if (autoomx && m_pDemuxer && m_omxplayer_mode)
+ {
+ // find video stream
+ int num_supported = 0, num_unsupported = 0;
+ AVCodecID codec = AV_CODEC_ID_NONE;
+ SelectionStreams streams = m_SelectionStreams.Get(STREAM_VIDEO, PredicateVideoPriority);
+ for(SelectionStreams::iterator it = streams.begin(); it != streams.end(); ++it)
+ {
+ int iStream = it->id;
+ CDemuxStream *stream = m_pDemuxer->GetStream(iStream);
+ if(!stream || stream->disabled)
+ continue;
+ CDVDStreamInfo hint(*stream, true);
+
+ bool supported = false;
+ if ((hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO) && g_RBP.GetCodecMpg2())
+ supported = true;
+ else if ((hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) && g_RBP.GetCodecWvc1())
+ supported = true;
+ else if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG4 || hint.codec == AV_CODEC_ID_H263 ||
+ hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 ||
+ hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB)
+ supported = true;
+ codec = hint.codec;
+ if (supported)
+ num_supported++;
+ else
+ num_unsupported++;
+ }
+ if (num_unsupported > 0 && num_supported == 0)
+ {
+ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to video codec (%x:%d/%d)", __func__, codec, num_supported, num_unsupported);
+ m_omxplayer_mode = false;
+ }
+ }
+ if (autoomx && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
+ {
+ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to dvd menus", __func__);
+ m_omxplayer_mode = false;
+ }
+
+ if (m_omxplayer_mode != omxplayer_mode)
+ DestroyPlayers();
+#endif
+
if (m_players_created)
return;
@@ -1187,6 +1243,8 @@ void CDVDPlayer::Process()
m_bAbortRequest = true;
return;
}
+ // give players a chance to reconsider now codecs are known
+ CreatePlayers();
// allow renderer to switch to fullscreen if requested
m_dvdPlayerVideo->EnableFullscreen(m_PlayerOptions.fullscreen);
From 430ad54c3e2921a8e4f6d3a328a056b296b87517 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 12 Aug 2014 16:51:18 +0100
Subject: [PATCH 45/99] AE: Add some logging for suspend/resume
---
xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 5 +++++
xbmc/cores/omxplayer/OMXAudio.cpp | 2 ++
2 files changed, 7 insertions(+)
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
index 2d013c8..c825b4b 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
@@ -347,6 +347,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
switch (signal)
{
case CActiveAEControlProtocol::INIT:
+ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_UNCONFIGURED/CActiveAEControlProtocol::INIT", __func__);
m_extError = false;
m_sink.EnumerateSinkList(false);
LoadSettings();
@@ -432,6 +433,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
m_extDeferData = true;
return;
case CActiveAEControlProtocol::SUSPEND:
+ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_CONFIGURED/CActiveAEControlProtocol::SUSPEND", __func__);
UnconfigureSink();
m_stats.SetSuspended(true);
m_state = AE_TOP_CONFIGURED_SUSPEND;
@@ -657,6 +659,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
CLog::Log(LOGDEBUG,"CActiveAE - display reset event");
displayReset = true;
case CActiveAEControlProtocol::INIT:
+ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_CONFIGURED_SUSPEND/CActiveAEControlProtocol::INIT", __func__);
m_extError = false;
if (!displayReset)
{
@@ -2334,12 +2337,14 @@ void CActiveAE::Shutdown()
bool CActiveAE::Suspend()
{
+ CLog::Log(LOGNOTICE, "ActiveAE::%s", __FUNCTION__);
return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
}
bool CActiveAE::Resume()
{
Message *reply;
+ CLog::Log(LOGNOTICE, "ActiveAE::%s", __FUNCTION__);
if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
&reply,
5000))
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index 7e85441..a73dd0a 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -932,6 +932,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
//***********************************************************************************************
bool COMXAudio::Deinitialize()
{
+ CLog::Log(LOGNOTICE, "COMXAudio::%s start", __func__);
CSingleLock lock (m_critSection);
if ( m_omx_tunnel_clock_analog.IsInitialized() )
@@ -992,6 +993,7 @@ bool COMXAudio::Deinitialize()
m_submitted = 0.0f;
m_maxLevel = 0.0f;
+ CLog::Log(LOGNOTICE, "COMXAudio::%s end", __func__);
return true;
}
From 017e54e4c9aff11a199ed0a82ea8354f5aad0f7b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 9 Jul 2014 22:45:43 +0100
Subject: [PATCH 46/99] [rbp] Make cachemembuffersize default depend on memory
size
---
xbmc/linux/RBP.cpp | 5 +++++
xbmc/settings/AdvancedSettings.cpp | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 11376fc..b67fbb1 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -22,6 +22,7 @@
#if defined(TARGET_RASPBERRY_PI)
#include "settings/Settings.h"
+#include "settings/AdvancedSettings.h"
#include "utils/log.h"
#include "cores/omxplayer/OMXImage.h"
@@ -84,6 +85,9 @@ bool CRBP::Initialize()
if (!m_gui_resolution_limit)
m_gui_resolution_limit = m_gpu_mem < 128 ? 720:1080;
+ if (g_advancedSettings.m_cacheMemBufferSize == ~0)
+ g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20;
+
g_OMXImage.Initialize();
m_omx_image_init = true;
return true;
@@ -96,6 +100,7 @@ void CRBP::LogFirmwareVerison()
response[sizeof(response) - 1] = '\0';
CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response);
CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled);
+ CLog::Log(LOGNOTICE, "cacheMemBufferSize: %dMB", g_advancedSettings.m_cacheMemBufferSize >> 20);
m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int");
response[sizeof(response) - 1] = '\0';
CLog::Log(LOGNOTICE, "Config:\n%s", response);
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 888ede3..2e2854f 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -363,7 +363,12 @@ void CAdvancedSettings::Initialize()
m_measureRefreshrate = false;
+#ifdef TARGET_RASPBERRY_PI
+ // want default to be memory dependent, but interface to gpu not available yet, so set in RBP.cpp
+ m_cacheMemBufferSize = ~0;
+#else
m_cacheMemBufferSize = 1024 * 1024 * 20;
+#endif
m_networkBufferMode = 0; // Default (buffer all internet streams/filesystems)
// the following setting determines the readRate of a player data
// as multiply of the default data read rate
From 3ea42987e583c6fe2867a37dea15ef8d4a45bb9b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 16 Jun 2014 19:06:00 +0100
Subject: [PATCH 48/99] [experimental] Disable quiet-noise generation
---
xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
index 488a0df..d9f4a43 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
@@ -870,6 +870,7 @@ void CActiveAESink::SwapInit(CSampleBuffer* samples)
void CActiveAESink::GenerateNoise()
{
+#ifndef TARGET_RASPBERRY_PI
int nb_floats = m_sampleOfSilence.pkt->max_nb_samples;
nb_floats *= m_sampleOfSilence.pkt->config.channels;
@@ -907,6 +908,7 @@ void CActiveAESink::GenerateNoise()
(uint8_t**)&noise, m_sampleOfSilence.pkt->max_nb_samples, 1.0);
_aligned_free(noise);
+#endif
}
void CActiveAESink::SetSilenceTimer()
From 2cd450a1ebf8fc2d20cda35b9b1e60fd1306fbe3 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 30 May 2014 14:58:43 +0100
Subject: [PATCH 49/99] [settings] Experiment: Report DESKTOP resolution in
video settings
---
xbmc/settings/DisplaySettings.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp
index 6902f83..50c5f97 100644
--- a/xbmc/settings/DisplaySettings.cpp
+++ b/xbmc/settings/DisplaySettings.cpp
@@ -674,6 +674,9 @@ void CDisplaySettings::SettingOptionsResolutionsFiller(const CSetting *setting,
vector<RESOLUTION_WHR> resolutions = g_Windowing.ScreenResolutions(info.iScreen, info.fRefreshRate);
for (vector<RESOLUTION_WHR>::const_iterator resolution = resolutions.begin(); resolution != resolutions.end(); ++resolution)
{
+if (resolution->ResInfo_Index == RES_DESKTOP)
+ list.push_back(make_pair(StringUtils::Format("DESKTOP"), resolution->ResInfo_Index));
+else
list.push_back(make_pair(
StringUtils::Format("%dx%d%s", resolution->width, resolution->height,
ModeFlagsToString(resolution->flags, false).c_str()),
From e6de67283fb1e636afc9c8edd08f81831a79bc2e Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 18:24:42 +0200
Subject: [PATCH 50/99] Added some vc_tv_* functions that were missing in
DllBCM.
---
xbmc/linux/DllBCM.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/xbmc/linux/DllBCM.h b/xbmc/linux/DllBCM.h
index b92fdb8..9c7e293 100644
--- a/xbmc/linux/DllBCM.h
+++ b/xbmc/linux/DllBCM.h
@@ -48,6 +48,9 @@ class DllBcmHostInterface
virtual void bcm_host_init() = 0;
virtual void bcm_host_deinit() = 0;
virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height) = 0;
+ virtual int vc_tv_power_off() = 0;
+ virtual int vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options) = 0;
+ virtual int vc_tv_hdmi_power_on_preferred() = 0;
virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) = 0;
virtual int vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
@@ -92,6 +95,12 @@ class DllBcmHost : public DllDynamic, DllBcmHostInterface
{ return ::bcm_host_deinit(); };
virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height)
{ return ::graphics_get_display_size(display_number, width, height); };
+ virtual int vc_tv_power_off()
+ { return ::vc_tv_power_off(); }
+ virtual int vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options)
+ { return ::vc_tv_sdtv_power_on(mode, options); }
+ virtual int vc_tv_hdmi_power_on_preferred()
+ { return ::vc_tv_hdmi_power_on_preferred(); }
virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags)
{ return ::vc_tv_hdmi_power_on_best(width, height, frame_rate, scan_mode, match_flags); };
From 15d4b97c14f412f8cc5f0315a50cfd8033009846 Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 18:29:03 +0200
Subject: [PATCH 51/99] Added private utility function to map a float display
aspect, to the respective SDTV_ASPECT_* enum value.
---
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index bf1e589..518a87d 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -411,6 +411,25 @@ static void SetResolutionString(RESOLUTION_INFO &res)
res.dwFlags & D3DPRESENTFLAG_MODE3DTB ? " 3DTB" : "",
res.dwFlags & D3DPRESENTFLAG_MODE3DSBS ? " 3DSBS" : "");
}
+
+static SDTV_ASPECT_T get_sdtv_aspect_from_display_aspect(float display_aspect)
+{
+ SDTV_ASPECT_T aspect;
+ const float delta = 1e-3;
+ if(fabs(get_display_aspect_ratio(SDTV_ASPECT_16_9) - display_aspect) < delta)
+ {
+ aspect = SDTV_ASPECT_16_9;
+ }
+ else if(fabs(get_display_aspect_ratio(SDTV_ASPECT_14_9) - display_aspect) < delta)
+ {
+ aspect = SDTV_ASPECT_14_9;
+ }
+ else
+ {
+ aspect = SDTV_ASPECT_4_3;
+ }
+ return aspect;
+}
#endif
bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
From 053a9bd554194f3e2cfcb2e453d74807bf5e2496 Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 19:50:58 +0200
Subject: [PATCH 52/99] Changed SDTV resolutions to be treated similarly to
HDMI resolutions in SetNativeResolution. This means that the SDTV interface
is powered up and set to the right mode.
---
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 36 ++++++++++++++++++++-----
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h | 1 -
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 518a87d..9dc39d5 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -221,7 +221,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
DestroyDispmaxWindow();
- if(!m_fixedMode && GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
+ if(GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
{
sem_init(&m_tv_synced, 0, 0);
m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
@@ -275,6 +275,33 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
m_desktopRes = res;
}
+ else if(!GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
+ {
+ sem_init(&m_tv_synced, 0, 0);
+ m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
+
+ SDTV_OPTIONS_T options;
+ options.aspect = get_sdtv_aspect_from_display_aspect((float)res.iScreenWidth / (float)res.iScreenHeight);
+
+ int success = m_DllBcmHost->vc_tv_sdtv_power_on((SDTV_MODE_T)GETFLAGS_MODE(res.dwFlags), &options);
+
+ if (success == 0)
+ {
+ CLog::Log(LOGDEBUG, "EGL set SDTV mode (%d,%d)=%d\n",
+ GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success);
+
+ sem_wait(&m_tv_synced);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "EGL failed to set SDTV mode (%d,%d)=%d\n",
+ GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success);
+ }
+ m_DllBcmHost->vc_tv_unregister_callback(CallbackTvServiceCallback);
+ sem_destroy(&m_tv_synced);
+
+ m_desktopRes = res;
+ }
m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
@@ -440,8 +467,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
if(!m_DllBcmHost)
return false;
- m_fixedMode = false;
-
/* read initial desktop resolution before probe resolutions.
* probing will replace the desktop resolution when it finds the same one.
* we raplace it because probing will generate more detailed
@@ -484,7 +509,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
m_desktopRes.iHeight = tv_state.display.sdtv.height;
m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
- m_desktopRes.dwFlags = D3DPRESENTFLAG_INTERLACED;
+ m_desktopRes.dwFlags = MAKEFLAGS(HDMI_RES_GROUP_INVALID, tv_state.display.sdtv.mode, 1);
m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
m_desktopRes.fPixelRatio = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
}
@@ -507,9 +532,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
}
- if(resolutions.size() < 2)
- m_fixedMode = true;
-
DLOG("CEGLNativeTypeRaspberryPI::ProbeResolutions\n");
return true;
#else
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
index 59401f5..a0acb1a 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
@@ -59,7 +59,6 @@ class CEGLNativeTypeRaspberryPI : public CEGLNativeType
DISPMANX_ELEMENT_HANDLE_T m_dispman_element;
TV_GET_STATE_RESP_T m_tv_state;
sem_t m_tv_synced;
- bool m_fixedMode;
RESOLUTION_INFO m_desktopRes;
int m_width;
int m_height;
From 3cb062892523c15718a1fb577e1928ecfa1fe4bc Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 19:54:59 +0200
Subject: [PATCH 53/99] Added methods SuspendVideoOutput() and
ResumeVideoOutput() to CRBP class, which can be used to power down the
Raspberry PI's video interface, and restore it at a later point.
---
xbmc/linux/RBP.cpp | 15 +++++++++++++++
xbmc/linux/RBP.h | 3 +++
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 3 +++
3 files changed, 21 insertions(+)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index b67fbb1..2ff6078 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -212,4 +212,19 @@ void CRBP::Deinitialize()
m_initialized = false;
m_omx_initialized = false;
}
+
+void CRBP::SuspendVideoOutput()
+{
+ CLog::Log(LOGDEBUG, "Raspberry PI suspending video output\n");
+ char response[80];
+ m_DllBcmHost->vc_gencmd(response, sizeof response, "display_power 0");
+}
+
+void CRBP::ResumeVideoOutput()
+{
+ char response[80];
+ m_DllBcmHost->vc_gencmd(response, sizeof response, "display_power 1");
+ CLog::Log(LOGDEBUG, "Raspberry PI resuming video output\n");
+}
+
#endif
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index 4fd18f3..f947acc 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -59,6 +59,9 @@ class CRBP
DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
void WaitVsync();
+ void SuspendVideoOutput();
+ void ResumeVideoOutput();
+
private:
DllBcmHost *m_DllBcmHost;
bool m_initialized;
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 9dc39d5..ca36082 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -59,7 +59,10 @@
# define DLOG(fmt, args...)
#endif
+#if defined(TARGET_RASPBERRY_PI)
static void SetResolutionString(RESOLUTION_INFO &res);
+static SDTV_ASPECT_T get_sdtv_aspect_from_display_aspect(float display_aspect);
+#endif
CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
{
From 81d7fd629130f5be6562ad5ba1a28fabb3eaed3e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 11 Aug 2013 15:03:36 +0100
Subject: [PATCH 54/99] PowerManager (and its IPowerSyscall instance) now gets
called from CApplication::OnKey() and can process and suppress key presses.
This is a requirement to implement a virtual sleep state.
---
xbmc/Application.cpp | 7 +++++++
xbmc/powermanagement/IPowerSyscall.h | 7 +++++++
xbmc/powermanagement/PowerManager.cpp | 6 ++++++
xbmc/powermanagement/PowerManager.h | 3 +++
4 files changed, 23 insertions(+)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 186ea7f..0a41343 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2332,6 +2332,13 @@ bool CApplication::OnKey(const CKey& key)
// special handling if the screensaver is active
CAction action = CButtonTranslator::GetInstance().GetAction(iWin, key);
+ // give the PowerManager a chance to process a keypress, and
+ // suppress further processing. we need this for virtual sleep.
+ if (g_powerManager.ProcessAction(action))
+ {
+ return true;
+ }
+
// a key has been pressed.
// reset Idle Timer
m_idleTimer.StartZero();
diff --git a/xbmc/powermanagement/IPowerSyscall.h b/xbmc/powermanagement/IPowerSyscall.h
index 7f9e7ed..711abea 100644
--- a/xbmc/powermanagement/IPowerSyscall.h
+++ b/xbmc/powermanagement/IPowerSyscall.h
@@ -20,6 +20,9 @@
*
*/
+// forward declaration
+class CAction;
+
class IPowerEventsCallback
{
public:
@@ -60,6 +63,10 @@ class IPowerSyscall
\param callback the callback to signal to
*/
virtual bool PumpPowerEvents(IPowerEventsCallback *callback) = 0;
+
+ // this is an optional part of the interface, so we provide a no-op implementation here.
+ // return true to suppress further processing of the CAction.
+ virtual bool ProcessAction(const CAction& action) { return false; }
};
class CPowerSyscallWithoutEvents : public IPowerSyscall
diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp
index 5900f98..6e819d9 100644
--- a/xbmc/powermanagement/PowerManager.cpp
+++ b/xbmc/powermanagement/PowerManager.cpp
@@ -225,6 +225,12 @@ void CPowerManager::ProcessEvents()
nesting--;
}
+bool CPowerManager::ProcessAction(const CAction& action)
+{
+ return m_instance->ProcessAction(action);
+}
+
+
void CPowerManager::OnSleep()
{
CAnnouncementManager::Get().Announce(System, "xbmc", "OnSleep");
diff --git a/xbmc/powermanagement/PowerManager.h b/xbmc/powermanagement/PowerManager.h
index 0b1f10a..e42b143 100644
--- a/xbmc/powermanagement/PowerManager.h
+++ b/xbmc/powermanagement/PowerManager.h
@@ -58,6 +58,8 @@ class CNullPowerSyscall : public IPowerSyscall
virtual bool PumpPowerEvents(IPowerEventsCallback *callback) { return false; }
+
+ virtual bool ProcessAction(const CAction& action) { return false; }
};
// This class will wrap and handle PowerSyscalls.
@@ -87,6 +89,7 @@ class CPowerManager : public IPowerEventsCallback
static void SettingOptionsShutdownStatesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current, void *data);
+ bool ProcessAction(const CAction& action);
private:
void OnSleep();
void OnWake();
From bf6321c429e5b929bc93fb75c64e0c855632d349 Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Wed, 17 Apr 2013 13:23:01 +0200
Subject: [PATCH 55/99] Added CPowerSyscallVirtualSleep class, which acts as a
base class for devices that have no native standby mode, and need to fake it
in some way.
---
xbmc/powermanagement/Makefile | 1 +
xbmc/powermanagement/PowerSyscallVirtualSleep.cpp | 84 +++++++++++++++++++++++
xbmc/powermanagement/PowerSyscallVirtualSleep.h | 56 +++++++++++++++
3 files changed, 141 insertions(+)
create mode 100644 xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
create mode 100644 xbmc/powermanagement/PowerSyscallVirtualSleep.h
diff --git a/xbmc/powermanagement/Makefile b/xbmc/powermanagement/Makefile
index 0b4c029..16056af 100644
--- a/xbmc/powermanagement/Makefile
+++ b/xbmc/powermanagement/Makefile
@@ -1,5 +1,6 @@
SRCS=DPMSSupport.cpp \
PowerManager.cpp \
+ PowerSyscallVirtualSleep.cpp \
LIB=powermanagement.a
diff --git a/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
new file mode 100644
index 0000000..6a1e47b
--- /dev/null
+++ b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "PowerSyscallVirtualSleep.h"
+#include "guilib/Key.h"
+#include "utils/log.h"
+#include "utils/StringUtils.h"
+
+bool CPowerSyscallVirtualSleep::Suspend()
+{
+ if (m_virtualSleepState == VIRTUAL_SLEEP_STATE_AWAKE)
+ {
+ if (VirtualSleep())
+ {
+ m_virtualSleepState = VIRTUAL_SLEEP_STATE_WILL_SLEEP;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CPowerSyscallVirtualSleep::PumpPowerEvents(IPowerEventsCallback *callback)
+{
+ if (m_virtualSleepState == VIRTUAL_SLEEP_STATE_WILL_WAKE)
+ {
+ callback->OnWake();
+ m_virtualSleepState = VIRTUAL_SLEEP_STATE_AWAKE;
+ return true;
+ }
+ else if (m_virtualSleepState == VIRTUAL_SLEEP_STATE_WILL_SLEEP)
+ {
+ callback->OnSleep();
+ m_virtualSleepState = VIRTUAL_SLEEP_STATE_ASLEEP;
+ return true;
+ }
+
+ return false;
+}
+
+bool CPowerSyscallVirtualSleep::ProcessAction(const CAction& action)
+{
+ if (m_virtualSleepState != VIRTUAL_SLEEP_STATE_ASLEEP)
+ return false;
+
+ // device is in virtual sleep, only one of the power keys will
+ // wake it up again.
+ if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
+ {
+ CStdString name = action.GetName();
+ StringUtils::ToLower(name);
+ if(name.Equals("xbmc.suspend()") ||
+ name.Equals("shutdown") ||
+ name.Equals("suspend") ||
+ name.Equals("hibernate"))
+ {
+ if(VirtualWake())
+ {
+ m_virtualSleepState = VIRTUAL_SLEEP_STATE_WILL_WAKE;
+ return false;
+ }
+ }
+ }
+
+ // wasn't a power key, suppress this and stay asleep
+ return true;
+}
diff --git a/xbmc/powermanagement/PowerSyscallVirtualSleep.h b/xbmc/powermanagement/PowerSyscallVirtualSleep.h
new file mode 100644
index 0000000..ef6e682
--- /dev/null
+++ b/xbmc/powermanagement/PowerSyscallVirtualSleep.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _POWER_SYSCALL_VIRTUAL_SLEEP_H_
+#define _POWER_SYSCALL_VIRTUAL_SLEEP_H_
+#include "IPowerSyscall.h"
+
+// Systems that have no native standby mode, can base their
+// IPowerSyscall implementation on this class, and need only
+// implement VirtualSleep()/VirtualWake().
+class CPowerSyscallVirtualSleep : public IPowerSyscall
+{
+public:
+ CPowerSyscallVirtualSleep() : m_virtualSleepState(VIRTUAL_SLEEP_STATE_AWAKE) {}
+ virtual ~CPowerSyscallVirtualSleep() {}
+
+ virtual bool CanSuspend() { return true; }
+ virtual bool Suspend();
+
+ virtual bool PumpPowerEvents(IPowerEventsCallback *callback);
+
+ virtual bool ProcessAction(const CAction& action);
+
+ virtual bool VirtualSleep() = 0;
+ virtual bool VirtualWake() = 0;
+
+protected:
+ // keep track of virtual sleep state for devices that support it
+ typedef enum {
+ VIRTUAL_SLEEP_STATE_AWAKE = 0,
+ VIRTUAL_SLEEP_STATE_ASLEEP,
+ VIRTUAL_SLEEP_STATE_WILL_WAKE,
+ VIRTUAL_SLEEP_STATE_WILL_SLEEP,
+ } VirtualSleepState;
+
+ VirtualSleepState m_virtualSleepState;
+};
+
+#endif // _POWER_SYSCALL_VIRTUAL_SLEEP_H_
From c02b03c0fbd8b83cd71c1c32493cbf648dd1d249 Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Wed, 17 Apr 2013 13:24:22 +0200
Subject: [PATCH 56/99] Added power management support for the Raspberry Pi.
Since it doesn't support true standby, we fake it by turning video on or off,
and ignoring remote inputs during the standby phase.
---
xbmc/powermanagement/PowerManager.cpp | 4 ++
xbmc/powermanagement/linux/Makefile | 1 +
.../linux/RaspberryPIPowerSyscall.cpp | 38 +++++++++++++++++
.../linux/RaspberryPIPowerSyscall.h | 49 ++++++++++++++++++++++
4 files changed, 92 insertions(+)
create mode 100644 xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
create mode 100644 xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp
index 6e819d9..2d8c750 100644
--- a/xbmc/powermanagement/PowerManager.cpp
+++ b/xbmc/powermanagement/PowerManager.cpp
@@ -38,6 +38,8 @@
#if defined(TARGET_DARWIN)
#include "osx/CocoaPowerSyscall.h"
+#elif defined(TARGET_RASPBERRY_PI)
+#include "linux/RaspberryPIPowerSyscall.h"
#elif defined(TARGET_ANDROID)
#include "android/AndroidPowerSyscall.h"
#elif defined(TARGET_POSIX)
@@ -71,6 +73,8 @@ void CPowerManager::Initialize()
{
#if defined(TARGET_DARWIN)
m_instance = new CCocoaPowerSyscall();
+#elif defined(TARGET_RASPBERRY_PI)
+ m_instance = new CRaspberryPIPowerSyscall();
#elif defined(TARGET_ANDROID)
m_instance = new CAndroidPowerSyscall();
#elif defined(TARGET_POSIX)
diff --git a/xbmc/powermanagement/linux/Makefile b/xbmc/powermanagement/linux/Makefile
index e9d95fb..b130812 100644
--- a/xbmc/powermanagement/linux/Makefile
+++ b/xbmc/powermanagement/linux/Makefile
@@ -1,5 +1,6 @@
SRCS=ConsoleDeviceKitPowerSyscall.cpp \
ConsoleUPowerSyscall.cpp \
+ RaspberryPIPowerSyscall.cpp \
UPowerSyscall.cpp \
LogindUPowerSyscall.cpp
diff --git a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
new file mode 100644
index 0000000..10deeb8
--- /dev/null
+++ b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(TARGET_RASPBERRY_PI)
+
+#include "RaspberryPIPowerSyscall.h"
+#include "RBP.h"
+
+bool CRaspberryPIPowerSyscall::VirtualSleep()
+{
+ g_RBP.SuspendVideoOutput();
+ return true;
+}
+
+bool CRaspberryPIPowerSyscall::VirtualWake()
+{
+ g_RBP.ResumeVideoOutput();
+ return true;
+}
+
+#endif
diff --git a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
new file mode 100644
index 0000000..fd1d67c
--- /dev/null
+++ b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
@@ -0,0 +1,49 @@
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _RASPBERRY_PI_POWER_SYSCALL_H_
+#define _RASPBERRY_PI_POWER_SYSCALL_H_
+
+#if defined(TARGET_RASPBERRY_PI)
+#include "powermanagement/PowerSyscallVirtualSleep.h"
+
+class CRaspberryPIPowerSyscall : public CPowerSyscallVirtualSleep
+{
+public:
+ CRaspberryPIPowerSyscall() : CPowerSyscallVirtualSleep() {}
+ virtual ~CRaspberryPIPowerSyscall() {}
+
+ virtual bool Powerdown() { return false; }
+ virtual bool Hibernate() { return false; }
+ virtual bool Reboot() { return false; }
+
+ virtual bool CanPowerdown() { return false; }
+ virtual bool CanHibernate() { return false; }
+ virtual bool CanReboot() { return true; }
+
+ virtual int BatteryLevel() { return 0; }
+
+ virtual bool VirtualSleep();
+ virtual bool VirtualWake();
+};
+#endif // TARGET_RASPBERRY_PI
+
+#endif // _RASPBERRY_PI_POWER_SYSCALL_H_
From d4343f847b7c527598660d7bb6295f000874c939 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 3 Mar 2014 16:16:29 +0000
Subject: [PATCH 57/99] [power] hack - don't kill lirc or cec
---
xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 37 +++++++++++++++++++++++
xbmc/powermanagement/PowerManager.cpp | 4 +--
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
index 6950f0c..4c8416f 100644
--- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
@@ -183,12 +183,49 @@ void CPeripheralCecAdapter::Announce(AnnouncementFlag flag, const char *sender,
}
else if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnSleep"))
{
+#if 1
+ bool bSendStandbyCommands(false);
+ {
+ CSingleLock lock(m_critSection);
+ bSendStandbyCommands = m_iExitCode != EXITCODE_REBOOT &&
+ m_iExitCode != EXITCODE_RESTARTAPP &&
+ !m_bDeviceRemoved &&
+ (!m_bGoingToStandby || GetSettingBool("standby_tv_on_pc_standby")) &&
+ GetSettingBool("enabled");
+
+ if (m_bGoingToStandby)
+ m_bActiveSourceBeforeStandby = m_cecAdapter->IsLibCECActiveSource();
+ }
+
+ if (bSendStandbyCommands)
+ {
+ if (m_cecAdapter->IsLibCECActiveSource())
+ {
+ if (!m_configuration.powerOffDevices.IsEmpty())
+ {
+ CLog::Log(LOGDEBUG, "%s - sending standby commands", __FUNCTION__);
+ m_standbySent = CDateTime::GetCurrentDateTime();
+ m_cecAdapter->StandbyDevices();
+ }
+ else if (m_configuration.bSendInactiveSource == 1)
+ {
+ CLog::Log(LOGDEBUG, "%s - sending inactive source commands", __FUNCTION__);
+ m_cecAdapter->SetInactiveView();
+ }
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "%s - XBMC is not the active source, not sending any standby commands", __FUNCTION__);
+ }
+ }
+#else
// this will also power off devices when we're the active source
{
CSingleLock lock(m_critSection);
m_bGoingToStandby = true;
}
StopThread();
+#endif
}
else if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnWake"))
{
diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp
index 2d8c750..901f449 100644
--- a/xbmc/powermanagement/PowerManager.cpp
+++ b/xbmc/powermanagement/PowerManager.cpp
@@ -241,7 +241,7 @@ void CPowerManager::OnSleep()
CLog::Log(LOGNOTICE, "%s: Running sleep jobs", __FUNCTION__);
// stop lirc
-#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
+#if 0 //defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
CLog::Log(LOGNOTICE, "%s: Stopping lirc", __FUNCTION__);
CBuiltins::Execute("LIRC.Stop");
#endif
@@ -277,7 +277,7 @@ void CPowerManager::OnWake()
#endif
// restart lirc
-#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
+#if 0 // defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
CLog::Log(LOGNOTICE, "%s: Restarting lirc", __FUNCTION__);
CBuiltins::Execute("LIRC.Start");
#endif
From e5e5fbc455a23da78bce9d1e1f218323ece08daf Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 3 Mar 2014 16:47:54 +0000
Subject: [PATCH 58/99] [power] hack - wake on any action
---
xbmc/powermanagement/PowerSyscallVirtualSleep.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
index 6a1e47b..a717a09 100644
--- a/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
+++ b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
@@ -62,14 +62,14 @@ bool CPowerSyscallVirtualSleep::ProcessAction(const CAction& action)
// device is in virtual sleep, only one of the power keys will
// wake it up again.
- if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
+ //if (action.GetID() == ACTION_BUILT_IN_FUNCTION)
{
CStdString name = action.GetName();
StringUtils::ToLower(name);
- if(name.Equals("xbmc.suspend()") ||
+ /*if(name.Equals("system.suspend") ||
name.Equals("shutdown") ||
name.Equals("suspend") ||
- name.Equals("hibernate"))
+ name.Equals("hibernate"))*/
{
if(VirtualWake())
{
From 3aacd299ec2bd4a9640d9edff9bc4820040ae6b4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 3 Mar 2014 17:30:07 +0000
Subject: [PATCH 59/99] [power] hack - Make suspend toggle suspend state
---
xbmc/powermanagement/PowerSyscallVirtualSleep.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
index a717a09..d39c3ed 100644
--- a/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
+++ b/xbmc/powermanagement/PowerSyscallVirtualSleep.cpp
@@ -33,6 +33,11 @@ bool CPowerSyscallVirtualSleep::Suspend()
return true;
}
}
+ else if (VirtualWake())
+ {
+ m_virtualSleepState = VIRTUAL_SLEEP_STATE_WILL_WAKE;
+ return false;
+ }
return false;
}
From d58641d07873f7e84e8e902123a23012baf6451b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 4 Mar 2014 19:33:44 +0000
Subject: [PATCH 60/99] [power] Add back in powerdown and reboot
---
.../linux/RaspberryPIPowerSyscall.cpp | 34 ++++++++++++++++++++++
.../linux/RaspberryPIPowerSyscall.h | 6 ++--
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
index 10deeb8..220bca9 100644
--- a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
+++ b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.cpp
@@ -20,7 +20,11 @@
#if defined(TARGET_RASPBERRY_PI)
+#include "system.h"
#include "RaspberryPIPowerSyscall.h"
+#if defined(HAS_DBUS)
+#include "LogindUPowerSyscall.h"
+#endif
#include "RBP.h"
bool CRaspberryPIPowerSyscall::VirtualSleep()
@@ -35,4 +39,34 @@ bool CRaspberryPIPowerSyscall::VirtualWake()
return true;
}
+bool CRaspberryPIPowerSyscall::Powerdown()
+{
+ int s = false;
+#if defined(HAS_DBUS)
+ if (CLogindUPowerSyscall::HasLogind())
+ {
+ IPowerSyscall *m_instance = new CLogindUPowerSyscall;
+ if (m_instance->CanPowerdown())
+ s = m_instance->Powerdown();
+ delete m_instance;
+ }
+#endif
+ return s;
+}
+
+bool CRaspberryPIPowerSyscall::Reboot()
+{
+ int s = false;
+#if defined(HAS_DBUS)
+ if (CLogindUPowerSyscall::HasLogind())
+ {
+ IPowerSyscall *m_instance = new CLogindUPowerSyscall;
+ if (m_instance->CanReboot())
+ s = m_instance->Reboot();
+ delete m_instance;
+ }
+#endif
+ return s;
+}
+
#endif
diff --git a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
index fd1d67c..062132e 100644
--- a/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
+++ b/xbmc/powermanagement/linux/RaspberryPIPowerSyscall.h
@@ -31,11 +31,11 @@ class CRaspberryPIPowerSyscall : public CPowerSyscallVirtualSleep
CRaspberryPIPowerSyscall() : CPowerSyscallVirtualSleep() {}
virtual ~CRaspberryPIPowerSyscall() {}
- virtual bool Powerdown() { return false; }
+ virtual bool Powerdown();
virtual bool Hibernate() { return false; }
- virtual bool Reboot() { return false; }
+ virtual bool Reboot();
- virtual bool CanPowerdown() { return false; }
+ virtual bool CanPowerdown() { return true; }
virtual bool CanHibernate() { return false; }
virtual bool CanReboot() { return true; }
From 1b42a074be346ac5f723b0c1931def7b3c72148b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 26 Apr 2014 17:27:52 +0100
Subject: [PATCH 65/99] [cec] Don't suspend pi on tv switch off - it can't wake
up
---
system/peripherals.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/system/peripherals.xml b/system/peripherals.xml
index a906628..9b5271a 100644
--- a/system/peripherals.xml
+++ b/system/peripherals.xml
@@ -16,7 +16,7 @@
<setting key="send_inactive_source" type="bool" value="1" label="36025" order="5" />
<setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="6" />
<setting key="cec_wake_screensaver" type="bool" value="1" label="36010" order="7" />
- <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="8" lvalues="36028|13005|13011" />
+ <setting key="standby_pc_on_tv_standby" type="enum" value="36028" label="36029" order="8" lvalues="36028|13005|13011" />
<setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="9" />
<setting key="use_tv_menu_language" type="bool" value="1" label="36018" order="10" />
<setting key="pause_playback_on_deactivate" type="bool" value="1" label="36033" order="11" />
From 1279d3fb5faf0fd513ff85dcd2fc76270bfb854d Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 18 Aug 2014 19:09:32 +0100
Subject: [PATCH 66/99] rbp: Use new dispmanx function for vsync callbacks
---
xbmc/linux/RBP.cpp | 85 ++++++++++++++-----------
xbmc/linux/RBP.h | 5 +-
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +-
3 files changed, 52 insertions(+), 42 deletions(-)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 2ff6078..360fc39 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -33,7 +33,7 @@ CRBP::CRBP()
m_omx_initialized = false;
m_DllBcmHost = new DllBcmHost();
m_OMX = new COMXCore();
- m_element = 0;
+ m_display = DISPMANX_NO_HANDLE;
}
CRBP::~CRBP()
@@ -55,8 +55,7 @@ bool CRBP::Initialize()
m_DllBcmHost->bcm_host_init();
- uint32_t vc_image_ptr;
- m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr );
+ //OpenDisplay(0 /*screen*/);
m_omx_initialized = m_OMX->Initialize();
if(!m_omx_initialized)
@@ -109,13 +108,24 @@ void CRBP::LogFirmwareVerison()
CLog::Log(LOGNOTICE, "Config:\n%s", response);
}
+DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
+{
+ if (m_display == DISPMANX_NO_HANDLE)
+ m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+ return m_display;
+}
+
+void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
+{
+ assert(display == m_display);
+ vc_dispmanx_display_close(m_display);
+ m_display = DISPMANX_NO_HANDLE;
+}
+
void CRBP::GetDisplaySize(int &width, int &height)
{
- DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
-
- display = vc_dispmanx_display_open( 0 /*screen*/ );
- if (vc_dispmanx_display_get_info(display, &info) == 0)
+ if (vc_dispmanx_display_get_info(m_display, &info) == 0)
{
width = info.width;
height = info.height;
@@ -125,12 +135,10 @@ void CRBP::GetDisplaySize(int &width, int &height)
width = 0;
height = 0;
}
- vc_dispmanx_display_close(display );
}
unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only)
{
- DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_RESOURCE_HANDLE_T resource;
VC_RECT_T rect;
unsigned char *image = NULL;
@@ -145,7 +153,6 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
if (!pstride)
flags |= DISPMANX_SNAPSHOT_PACK;
- display = vc_dispmanx_display_open( 0 /*screen*/ );
stride = ((width + 15) & ~15) * 4;
image = new unsigned char [height * stride];
@@ -153,45 +160,44 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
{
resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr );
- vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags);
+ assert(m_display != DISPMANX_NO_HANDLE);
+ vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags);
vc_dispmanx_rect_set(&rect, 0, 0, width, height);
vc_dispmanx_resource_read_data(resource, &rect, image, stride);
vc_dispmanx_resource_delete( resource );
- vc_dispmanx_display_close(display );
}
if (pstride)
*pstride = stride;
return image;
}
-void CRBP::WaitVsync(void)
+
+static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
+{
+ CEvent *sync = (CEvent *)arg;
+ sync->Set();
+}
+
+void CRBP::WaitVsync()
{
- DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ );
- DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
-
- VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 };
- VC_RECT_T src_rect;
- VC_RECT_T dst_rect;
- vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 );
- vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 );
-
- if (m_element)
- vc_dispmanx_element_remove( update, m_element );
-
- m_element = vc_dispmanx_element_add( update,
- display,
- 2000, // layer
- &dst_rect,
- m_resource,
- &src_rect,
- DISPMANX_PROTECTION_NONE,
- &alpha,
- NULL, // clamp
- (DISPMANX_TRANSFORM_T)0 );
-
- vc_dispmanx_update_submit_sync(update);
- vc_dispmanx_display_close( display );
+ int s;
+ CEvent sync;
+ DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+ if (m_display == DISPMANX_NO_HANDLE)
+ {
+ CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
+ return;
+ }
+ s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&sync);
+ if (s == 0)
+ {
+ sync.Wait();
+ }
+ else assert(0);
+ s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
+ assert(s == 0);
+ vc_dispmanx_display_close( m_display );
}
@@ -203,6 +209,9 @@ void CRBP::Deinitialize()
if(m_omx_initialized)
m_OMX->Deinitialize();
+ if (m_display)
+ CloseDisplay(m_display);
+
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index f947acc..ca80045 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -53,6 +53,8 @@ class CRBP
bool GetCodecMpg2() { return m_codec_mpg2_enabled; }
bool GetCodecWvc1() { return m_codec_wvc1_enabled; }
void GetDisplaySize(int &width, int &height);
+ DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device);
+ void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display);
int GetGUIResolutionLimit() { return m_gui_resolution_limit; }
// stride can be null for packed output
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
@@ -73,10 +75,9 @@ class CRBP
bool m_codec_mpg2_enabled;
bool m_codec_wvc1_enabled;
COMXCore *m_OMX;
- DISPMANX_RESOURCE_HANDLE_T m_resource;
- DISPMANX_ELEMENT_HANDLE_T m_element;
class DllLibOMXCore;
CCriticalSection m_critSection;
+ DISPMANX_DISPLAY_HANDLE_T m_display;
};
extern CRBP g_RBP;
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index ca36082..4b74ea0 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
m_desktopRes = res;
}
- m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
+ m_dispman_display = g_RBP.OpenDisplay(0);
m_width = res.iWidth;
m_height = res.iHeight;
@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
if (m_dispman_display != DISPMANX_NO_HANDLE)
{
- m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
+ g_RBP.CloseDisplay(m_dispman_display);
m_dispman_display = DISPMANX_NO_HANDLE;
}
DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
From ec1bede710310c5a4e865ee0847ca33bfce568bd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 19 Aug 2014 17:56:45 +0100
Subject: [PATCH 67/99] Revert "rbp: Use new dispmanx function for vsync
callbacks"
This reverts commit afbf8fbceaa6649fb4a6bbd9a1cee6087590412b.
---
xbmc/linux/RBP.cpp | 85 +++++++++++--------------
xbmc/linux/RBP.h | 5 +-
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +-
3 files changed, 42 insertions(+), 52 deletions(-)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 360fc39..2ff6078 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -33,7 +33,7 @@ CRBP::CRBP()
m_omx_initialized = false;
m_DllBcmHost = new DllBcmHost();
m_OMX = new COMXCore();
- m_display = DISPMANX_NO_HANDLE;
+ m_element = 0;
}
CRBP::~CRBP()
@@ -55,7 +55,8 @@ bool CRBP::Initialize()
m_DllBcmHost->bcm_host_init();
- //OpenDisplay(0 /*screen*/);
+ uint32_t vc_image_ptr;
+ m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr );
m_omx_initialized = m_OMX->Initialize();
if(!m_omx_initialized)
@@ -108,24 +109,13 @@ void CRBP::LogFirmwareVerison()
CLog::Log(LOGNOTICE, "Config:\n%s", response);
}
-DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
-{
- if (m_display == DISPMANX_NO_HANDLE)
- m_display = vc_dispmanx_display_open( 0 /*screen*/ );
- return m_display;
-}
-
-void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
-{
- assert(display == m_display);
- vc_dispmanx_display_close(m_display);
- m_display = DISPMANX_NO_HANDLE;
-}
-
void CRBP::GetDisplaySize(int &width, int &height)
{
+ DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
- if (vc_dispmanx_display_get_info(m_display, &info) == 0)
+
+ display = vc_dispmanx_display_open( 0 /*screen*/ );
+ if (vc_dispmanx_display_get_info(display, &info) == 0)
{
width = info.width;
height = info.height;
@@ -135,10 +125,12 @@ void CRBP::GetDisplaySize(int &width, int &height)
width = 0;
height = 0;
}
+ vc_dispmanx_display_close(display );
}
unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only)
{
+ DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_RESOURCE_HANDLE_T resource;
VC_RECT_T rect;
unsigned char *image = NULL;
@@ -153,6 +145,7 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
if (!pstride)
flags |= DISPMANX_SNAPSHOT_PACK;
+ display = vc_dispmanx_display_open( 0 /*screen*/ );
stride = ((width + 15) & ~15) * 4;
image = new unsigned char [height * stride];
@@ -160,44 +153,45 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
{
resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr );
- assert(m_display != DISPMANX_NO_HANDLE);
- vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags);
+ vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags);
vc_dispmanx_rect_set(&rect, 0, 0, width, height);
vc_dispmanx_resource_read_data(resource, &rect, image, stride);
vc_dispmanx_resource_delete( resource );
+ vc_dispmanx_display_close(display );
}
if (pstride)
*pstride = stride;
return image;
}
-
-static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
-{
- CEvent *sync = (CEvent *)arg;
- sync->Set();
-}
-
-void CRBP::WaitVsync()
+void CRBP::WaitVsync(void)
{
- int s;
- CEvent sync;
- DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ );
- if (m_display == DISPMANX_NO_HANDLE)
- {
- CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
- return;
- }
- s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&sync);
- if (s == 0)
- {
- sync.Wait();
- }
- else assert(0);
- s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
- assert(s == 0);
- vc_dispmanx_display_close( m_display );
+ DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ );
+ DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
+
+ VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 };
+ VC_RECT_T src_rect;
+ VC_RECT_T dst_rect;
+ vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 );
+ vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 );
+
+ if (m_element)
+ vc_dispmanx_element_remove( update, m_element );
+
+ m_element = vc_dispmanx_element_add( update,
+ display,
+ 2000, // layer
+ &dst_rect,
+ m_resource,
+ &src_rect,
+ DISPMANX_PROTECTION_NONE,
+ &alpha,
+ NULL, // clamp
+ (DISPMANX_TRANSFORM_T)0 );
+
+ vc_dispmanx_update_submit_sync(update);
+ vc_dispmanx_display_close( display );
}
@@ -209,9 +203,6 @@ void CRBP::Deinitialize()
if(m_omx_initialized)
m_OMX->Deinitialize();
- if (m_display)
- CloseDisplay(m_display);
-
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index ca80045..f947acc 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -53,8 +53,6 @@ class CRBP
bool GetCodecMpg2() { return m_codec_mpg2_enabled; }
bool GetCodecWvc1() { return m_codec_wvc1_enabled; }
void GetDisplaySize(int &width, int &height);
- DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device);
- void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display);
int GetGUIResolutionLimit() { return m_gui_resolution_limit; }
// stride can be null for packed output
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
@@ -75,9 +73,10 @@ class CRBP
bool m_codec_mpg2_enabled;
bool m_codec_wvc1_enabled;
COMXCore *m_OMX;
+ DISPMANX_RESOURCE_HANDLE_T m_resource;
+ DISPMANX_ELEMENT_HANDLE_T m_element;
class DllLibOMXCore;
CCriticalSection m_critSection;
- DISPMANX_DISPLAY_HANDLE_T m_display;
};
extern CRBP g_RBP;
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 4b74ea0..ca36082 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
m_desktopRes = res;
}
- m_dispman_display = g_RBP.OpenDisplay(0);
+ m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
m_width = res.iWidth;
m_height = res.iHeight;
@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
if (m_dispman_display != DISPMANX_NO_HANDLE)
{
- g_RBP.CloseDisplay(m_dispman_display);
+ m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
m_dispman_display = DISPMANX_NO_HANDLE;
}
DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
From f5ca95842aa2601aec05a6bfaf316d5c394525f8 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 27 Jun 2014 00:01:05 +0100
Subject: [PATCH 68/99] [rbp] Resume video output on startup
---
xbmc/linux/RBP.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 2ff6078..34e0108 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -88,6 +88,9 @@ bool CRBP::Initialize()
if (g_advancedSettings.m_cacheMemBufferSize == ~0)
g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20;
+ // in case xbcm was restarted when suspended
+ ResumeVideoOutput();
+
g_OMXImage.Initialize();
m_omx_image_init = true;
return true;
From 5ec02d54792052a230a35645a33f88297664406e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 16 Aug 2014 21:01:42 +0100
Subject: [PATCH 69/99] omxrender: Hacks to reduce GUI rendering rate when
playing video
---
language/English/strings.po | 27 +++++++++++++++++++++++++++
system/settings/rbp.xml | 16 ++++++++++++++++
xbmc/Application.cpp | 17 +++++++++++++++++
3 files changed, 60 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index 160e83c..d9b4519 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15951,3 +15951,30 @@ msgstr ""
msgctxt "#37034"
msgid "Uses codec information and audio setting to choose dvdplayer or omxplayer as appropriate"
msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38000"
+msgid "Limit GUI updates when playing video"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38001"
+msgid "This can reduce CPU when playing video by updating the overlays less often"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38002"
+msgid "Off"
+msgstr ""
+
+msgctxt "#38003"
+msgid "5 fps"
+msgstr ""
+
+msgctxt "#38004"
+msgid "10 fps"
+msgstr ""
+
+msgctxt "#38005"
+msgid "24 fps"
+msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 9cc4fd2..97eb3e3c 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -25,6 +25,22 @@
<control type="toggle" />
</setting>
</group>
+ <group id="3">
+ <setting id="videoplayer.limitguiupdate" type="integer" label="38000" help="38001">
+ <level>2</level>
+ <default>10</default>
+ <constraints>
+ <options>
+ <option label="38002">0</option> <!-- off -->
+ <option label="38003">5</option> <!-- 5 fps -->
+ <option label="38004">10</option> <!-- 10 fps -->
+ <option label="38005">24</option> <!-- 24 fps -->
+ </options>
+ </constraints>
+ <control type="spinner" format="string" />
+ <control type="edit" format="integer" />
+ </setting>
+ </group>
</category>
</section>
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 0a41343..34cb9db 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2180,6 +2180,23 @@ void CApplication::Render()
if (m_bStop)
return;
+#ifdef TARGET_RASPBERRY_PI
+ if (g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback())
+ {
+ int fps = CSettings::Get().GetInt("videoplayer.limitguiupdate");
+ unsigned int now = XbmcThreads::SystemClockMillis();
+ unsigned int frameTime = now - m_lastFrameTime;
+ if (fps > 0 && frameTime * fps < 1000)
+ {
+ g_renderManager.FrameWait(100);
+ g_infoManager.UpdateFPS();
+ g_renderManager.FrameMove();
+ g_renderManager.FrameFinish();
+ return;
+ }
+ }
+#endif
+
MEASURE_FUNCTION;
int vsync_mode = CSettings::Get().GetInt("videoscreen.vsync");
From b3e5eb969927b2e45b356fe70c6c94051441a53c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 9 Sep 2014 12:04:26 +0100
Subject: [PATCH 70/99] egl: Treat unknown display aspect ratio as square pixel
---
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index ca36082..1529045 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -493,7 +493,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
m_desktopRes.iScreenWidth = tv_state.display.hdmi.width;
m_desktopRes.iScreenHeight= tv_state.display.hdmi.height;
m_desktopRes.dwFlags = MAKEFLAGS(tv_state.display.hdmi.group, tv_state.display.hdmi.mode, tv_state.display.hdmi.scan_mode);
- m_desktopRes.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
+ m_desktopRes.fPixelRatio = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
// Also add 3D flags
if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
@@ -514,7 +514,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
m_desktopRes.dwFlags = MAKEFLAGS(HDMI_RES_GROUP_INVALID, tv_state.display.sdtv.mode, 1);
m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
- m_desktopRes.fPixelRatio = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
+ m_desktopRes.fPixelRatio = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
}
SetResolutionString(m_desktopRes);
From 96bbf2e2b66398bcef70f48cbd62097209c0a1a7 Mon Sep 17 00:00:00 2001
From: anaconda <anaconda@menakite.eu>
Date: Thu, 11 Sep 2014 21:30:43 +0200
Subject: [PATCH 71/99] Disable textbox autoscrolling while on screensaver.
---
xbmc/guilib/GUITextBox.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xbmc/guilib/GUITextBox.cpp b/xbmc/guilib/GUITextBox.cpp
index b7ef051..ba68fad 100644
--- a/xbmc/guilib/GUITextBox.cpp
+++ b/xbmc/guilib/GUITextBox.cpp
@@ -23,6 +23,7 @@
#include "utils/XBMCTinyXML.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
+#include "Application.h"
using namespace std;
@@ -132,7 +133,7 @@ void CGUITextBox::Process(unsigned int currentTime, CDirtyRegionList &dirtyregio
// update our auto-scrolling as necessary
if (m_autoScrollTime && m_lines.size() > m_itemsPerPage)
{
- if (!m_autoScrollCondition || m_autoScrollCondition->Get())
+ if ((!m_autoScrollCondition || m_autoScrollCondition->Get()) && !g_application.IsInScreenSaver())
{
if (m_lastRenderTime)
m_autoScrollDelayTime += currentTime - m_lastRenderTime;
From 9fb850204d9931af9c29529e64c1a9f6c309f4a9 Mon Sep 17 00:00:00 2001
From: anaconda <anaconda@menakite.eu>
Date: Sat, 13 Sep 2014 19:49:01 +0200
Subject: [PATCH 72/99] SQUASH: only if dim or black
---
xbmc/Application.cpp | 7 +++++++
xbmc/Application.h | 2 ++
xbmc/guilib/GUITextBox.cpp | 4 +++-
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 34cb9db..d89a379 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -5814,3 +5814,10 @@ void CApplication::CloseNetworkShares()
CSFTPSessionManager::DisconnectAllSessions();
#endif
}
+
+std::string CApplication::GetScreenSaverId()
+{
+ if (m_screenSaver)
+ return m_screenSaver->ID();
+ return "";
+}
diff --git a/xbmc/Application.h b/xbmc/Application.h
index b788471..ed19b79 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -356,6 +356,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
void SetLoggingIn(bool loggingIn) { m_loggingIn = loggingIn; }
+ std::string GetScreenSaverId();
+
protected:
virtual bool OnSettingsSaving() const;
diff --git a/xbmc/guilib/GUITextBox.cpp b/xbmc/guilib/GUITextBox.cpp
index ba68fad..e149418 100644
--- a/xbmc/guilib/GUITextBox.cpp
+++ b/xbmc/guilib/GUITextBox.cpp
@@ -133,7 +133,9 @@ void CGUITextBox::Process(unsigned int currentTime, CDirtyRegionList &dirtyregio
// update our auto-scrolling as necessary
if (m_autoScrollTime && m_lines.size() > m_itemsPerPage)
{
- if ((!m_autoScrollCondition || m_autoScrollCondition->Get()) && !g_application.IsInScreenSaver())
+ if ((!m_autoScrollCondition || m_autoScrollCondition->Get()) && !(g_application.IsInScreenSaver() &&
+ (g_application.GetScreenSaverId() == "screensaver.xbmc.builtin.black" ||
+ g_application.GetScreenSaverId() == "screensaver.xbmc.builtin.dim")))
{
if (m_lastRenderTime)
m_autoScrollDelayTime += currentTime - m_lastRenderTime;
From 36b350c61d9648a03f7c5731bb2a213c5362407a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 16 Sep 2014 00:52:02 +0100
Subject: [PATCH 73/99] [PiSink] Initial dual audio support
---
system/settings/rbp.xml | 7 -
xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 219 ++++++++++++++++++++++++------
xbmc/cores/AudioEngine/Sinks/AESinkPi.h | 5 +
xbmc/cores/omxplayer/OMXAudio.cpp | 12 +-
4 files changed, 186 insertions(+), 57 deletions(-)
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 97eb3e3c..3c372bf 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -79,13 +79,6 @@
</group>
</category>
<category id="audiooutput">
- <group id="1">
- <setting id="audiooutput.dualaudio" type="boolean" label="37017" help="36542">
- <level>2</level>
- <default>false</default>
- <control type="toggle" />
- </setting>
- </group>
<group id="3">
<setting id="audiooutput.ac3transcode" help="37024">
</setting>
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
index 7af2078..89684e4 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
@@ -43,7 +43,8 @@ CAEDeviceInfo CAESinkPi::m_info;
CAESinkPi::CAESinkPi() :
m_sinkbuffer_sec_per_byte(0),
m_Initialized(false),
- m_submitted(0)
+ m_submitted(0),
+ m_omx_output(NULL)
{
}
@@ -56,13 +57,26 @@ void CAESinkPi::SetAudioDest()
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
OMX_INIT_STRUCTURE(audioDest);
- if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
- strncpy((char *)audioDest.sName, "local", strlen("local"));
- else
- strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
- omx_err = m_omx_render.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s::%s - m_omx_render.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ if ( m_omx_render.IsInitialized() )
+ {
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
+ strncpy((char *)audioDest.sName, "local", strlen("local"));
+ else
+ strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
+ omx_err = m_omx_render.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - m_omx_render.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
+ if ( m_omx_render_slave.IsInitialized() )
+ {
+ if (CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue")
+ strncpy((char *)audioDest.sName, "local", strlen("local"));
+ else
+ strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
+ omx_err = m_omx_render_slave.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - m_omx_render_slave.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
}
static void SetAudioProps(bool stream_channels, uint32_t channel_map)
@@ -176,8 +190,11 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
m_initFormat = format;
// analogue only supports stereo
- if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue" || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
+ {
format.m_channelLayout = AE_CH_LAYOUT_2_0;
+ m_passthrough = false;
+ }
// setup for a 50ms sink feed from SoftAE
if (format.m_dataFormat != AE_FMT_FLOATP && format.m_dataFormat != AE_FMT_FLOAT &&
@@ -196,18 +213,29 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
m_format = format;
m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate);
- CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f", CLASSNAME, __func__,
- m_format.m_dataFormat, channels, m_format.m_sampleRate, m_format.m_frameSize, m_format.m_frameSize * m_format.m_frames, 1.0/m_sinkbuffer_sec_per_byte);
-
- CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
+ CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f dest=%s", CLASSNAME, __func__,
+ m_format.m_dataFormat, channels, m_format.m_sampleRate, m_format.m_frameSize, m_format.m_frameSize * m_format.m_frames, 1.0/m_sinkbuffer_sec_per_byte,
+ CSettings::Get().GetString("audiooutput.audiodevice").c_str());
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
+ {
+ if (!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
+ CLog::Log(LOGERROR, "%s::%s - m_omx_splitter.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ if (!m_omx_render_slave.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
+ CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ m_omx_output = &m_omx_splitter;
+ }
+ else
+ m_omx_output = &m_omx_render;
+
+ SetAudioDest();
+
OMX_INIT_STRUCTURE(m_pcm_input);
- m_pcm_input.nPortIndex = m_omx_render.GetInputPort();
m_pcm_input.eNumData = OMX_NumericalDataSigned;
m_pcm_input.eEndian = OMX_EndianLittle;
m_pcm_input.bInterleaved = OMX_TRUE;
@@ -222,37 +250,100 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
m_pcm_input.nChannels = channels;
m_pcm_input.nSamplingRate = m_format.m_sampleRate;
- omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ if ( m_omx_splitter.IsInitialized() )
+ {
+ m_pcm_input.nPortIndex = m_omx_splitter.GetInputPort();
+ omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort();
+ omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort() + 1;
+ omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
- m_omx_render.ResetEos();
+ if ( m_omx_render_slave.IsInitialized() )
+ {
+ m_pcm_input.nPortIndex = m_omx_render_slave.GetInputPort();
+ omx_err = m_omx_render_slave.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_render_slave SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
- SetAudioDest();
+ if ( m_omx_render.IsInitialized() )
+ {
+ m_pcm_input.nPortIndex = m_omx_render.GetInputPort();
+ omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
- // set up the number/size of buffers for decoder input
- OMX_PARAM_PORTDEFINITIONTYPE port_param;
- OMX_INIT_STRUCTURE(port_param);
- port_param.nPortIndex = m_omx_render.GetInputPort();
+ if ( m_omx_output->IsInitialized() )
+ {
+ // set up the number/size of buffers for decoder input
+ OMX_PARAM_PORTDEFINITIONTYPE port_param;
+ OMX_INIT_STRUCTURE(port_param);
+ port_param.nPortIndex = m_omx_output->GetInputPort();
- omx_err = m_omx_render.GetParameter(OMX_IndexParamPortDefinition, &port_param);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ omx_err = m_omx_output->GetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
- port_param.nBufferSize = m_format.m_frameSize * m_format.m_frames;
+ port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
+ port_param.nBufferSize = ALIGN_UP(m_format.m_frameSize * m_format.m_frames, port_param.nBufferAlignment);
- omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (intput) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ omx_err = m_omx_output->SetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- omx_err = m_omx_render.AllocInputBuffers();
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
+ omx_err = m_omx_output->AllocInputBuffers();
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
+ }
- omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ if ( m_omx_splitter.IsInitialized() )
+ {
+ m_omx_tunnel_splitter.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort());
+ omx_err = m_omx_tunnel_splitter.Establish();
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter.Establish 0x%08x", omx_err);
+ return false;
+ }
+
+ m_omx_tunnel_splitter_slave.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort() + 1, &m_omx_render_slave, m_omx_render_slave.GetInputPort());
+ omx_err = m_omx_tunnel_splitter_slave.Establish();
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter_slave.Establish 0x%08x", omx_err);
+ return false;
+ }
+ }
+
+ if ( m_omx_splitter.IsInitialized() )
+ {
+ omx_err = m_omx_splitter.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - m_omx_splitter OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
+ if ( m_omx_render.IsInitialized() )
+ {
+ omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
+ if ( m_omx_render_slave.IsInitialized() )
+ {
+ omx_err = m_omx_render_slave.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - m_omx_render_slave OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+ }
m_Initialized = true;
return true;
@@ -263,12 +354,32 @@ void CAESinkPi::Deinitialize()
{
CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
SetAudioProps(false, 0);
- if (m_Initialized)
- {
+
+ if ( m_omx_render.IsInitialized() )
+ m_omx_render.IgnoreNextError(OMX_ErrorPortUnpopulated);
+ if ( m_omx_render_slave.IsInitialized() )
+ m_omx_render_slave.IgnoreNextError(OMX_ErrorPortUnpopulated);
+
+ if ( m_omx_tunnel_splitter.IsInitialized() )
+ m_omx_tunnel_splitter.Deestablish();
+ if ( m_omx_tunnel_splitter_slave.IsInitialized() )
+ m_omx_tunnel_splitter_slave.Deestablish();
+
+ if ( m_omx_splitter.IsInitialized() )
+ m_omx_splitter.FlushAll();
+ if ( m_omx_render.IsInitialized() )
m_omx_render.FlushAll();
+ if ( m_omx_render_slave.IsInitialized() )
+ m_omx_render_slave.FlushAll();
+
+ if ( m_omx_splitter.IsInitialized() )
+ m_omx_splitter.Deinitialize();
+ if ( m_omx_render.IsInitialized() )
m_omx_render.Deinitialize();
- m_Initialized = false;
- }
+ if ( m_omx_render_slave.IsInitialized() )
+ m_omx_render_slave.Deinitialize();
+
+ m_Initialized = false;
}
bool CAESinkPi::IsCompatible(const AEAudioFormat &format, const std::string &device)
@@ -314,7 +425,7 @@ double CAESinkPi::GetCacheTotal()
unsigned int CAESinkPi::AddPackets(uint8_t **data, unsigned int frames, unsigned int offset)
{
- if (!m_Initialized || !frames)
+ if (!m_Initialized || !m_omx_output || !frames)
return frames;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
@@ -332,7 +443,7 @@ unsigned int CAESinkPi::AddPackets(uint8_t **data, unsigned int frames, unsigned
if (delay <= 0.0 && m_submitted)
CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
- omx_buffer = m_omx_render.GetInputBuffer(1000);
+ omx_buffer = m_omx_output->GetInputBuffer(1000);
if (omx_buffer == NULL)
{
CLog::Log(LOGERROR, "CAESinkPi::AddPackets timeout");
@@ -351,7 +462,7 @@ unsigned int CAESinkPi::AddPackets(uint8_t **data, unsigned int frames, unsigned
for (int i=0; i < planes; i++)
memcpy((uint8_t *)omx_buffer->pBuffer + i * planesize, data[i] + offset * pitch, planesize);
}
- omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
+ omx_err = m_omx_output->EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
m_submitted++;
@@ -419,6 +530,26 @@ void CAESinkPi::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
m_info.m_dataFormats.push_back(AE_FMT_S16NEP);
list.push_back(m_info);
+
+ m_info.m_channels.Reset();
+ m_info.m_dataFormats.clear();
+ m_info.m_sampleRates.clear();
+
+ m_info.m_deviceType = AE_DEVTYPE_PCM;
+ m_info.m_deviceName = "Both";
+ m_info.m_displayName = "HDMI and Analogue";
+ m_info.m_displayNameExtra = "";
+ m_info.m_channels += AE_CH_FL;
+ m_info.m_channels += AE_CH_FR;
+ m_info.m_sampleRates.push_back(48000);
+ m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
+ m_info.m_dataFormats.push_back(AE_FMT_S32LE);
+ m_info.m_dataFormats.push_back(AE_FMT_S16LE);
+ m_info.m_dataFormats.push_back(AE_FMT_FLOATP);
+ m_info.m_dataFormats.push_back(AE_FMT_S32NEP);
+ m_info.m_dataFormats.push_back(AE_FMT_S16NEP);
+
+ list.push_back(m_info);
}
#endif
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.h b/xbmc/cores/AudioEngine/Sinks/AESinkPi.h
index 8ab1d08..5c57999 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.h
@@ -57,8 +57,13 @@ class CAESinkPi : public IAESink
bool m_Initialized;
uint32_t m_submitted;
OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
+ COMXCoreComponent *m_omx_output;
+ COMXCoreComponent m_omx_splitter;
COMXCoreComponent m_omx_render;
+ COMXCoreComponent m_omx_render_slave;
bool m_passthrough;
+ COMXCoreTunel m_omx_tunnel_splitter;
+ COMXCoreTunel m_omx_tunnel_splitter_slave;
};
#endif
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index a73dd0a..13899bc 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -124,17 +124,17 @@ bool COMXAudio::PortSettingsChanged()
if(!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit))
return false;
}
- if(CSettings::Get().GetBool("audiooutput.dualaudio"))
+ if(CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
{
if(!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both" || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
{
if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue")
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both" || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:HDMI")
{
if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
@@ -252,7 +252,7 @@ bool COMXAudio::PortSettingsChanged()
{
// By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
// This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue"))
+ if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
{
OMX_CONFIG_BOOLEANTYPE configBool;
OMX_INIT_STRUCTURE(configBool);
@@ -278,7 +278,7 @@ bool COMXAudio::PortSettingsChanged()
{
// By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
// This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue"))
+ if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
{
OMX_CONFIG_BOOLEANTYPE configBool;
OMX_INIT_STRUCTURE(configBool);
@@ -601,7 +601,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
CAEChannelInfo stdLayout = (enum AEStdChLayout)CSettings::Get().GetInt("audiooutput.channels");
// ignore layout setting for analogue
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both" || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
stdLayout = AE_CH_LAYOUT_2_0;
// force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
From 3ff4ef08779e7b03bd219b19e4cf688b1c2b015b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 18 Sep 2014 14:24:56 +0100
Subject: [PATCH 74/99] [omxplayer] Only enable audio clock master when A/V
sync method is set to audio clock
---
xbmc/cores/omxplayer/OMXAudio.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index 13899bc..3c6c73b 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -252,7 +252,8 @@ bool COMXAudio::PortSettingsChanged()
{
// By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
// This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
+ if((CSettings::Get().GetBool("videoplayer.usedisplayasclock") && CSettings::Get().GetInt("videoplayer.synctype") == SYNC_DISCON) ||
+ CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Both")
{
OMX_CONFIG_BOOLEANTYPE configBool;
OMX_INIT_STRUCTURE(configBool);
@@ -278,7 +279,7 @@ bool COMXAudio::PortSettingsChanged()
{
// By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
// This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
+ if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") && CSettings::Get().GetInt("videoplayer.synctype") == SYNC_DISCON)
{
OMX_CONFIG_BOOLEANTYPE configBool;
OMX_INIT_STRUCTURE(configBool);
From d9f3d0781c9978e31abda2388c43f827b981a202 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 18 Aug 2014 19:09:32 +0100
Subject: [PATCH 75/99] rbp: Use new dispmanx function for vsync callbacks
[rbp] Enable vsync handler all the time
---
xbmc/linux/RBP.cpp | 96 ++++++++++++++-----------
xbmc/linux/RBP.h | 7 +-
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +-
3 files changed, 61 insertions(+), 46 deletions(-)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 34e0108..8ce60cb 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -33,7 +33,7 @@ CRBP::CRBP()
m_omx_initialized = false;
m_DllBcmHost = new DllBcmHost();
m_OMX = new COMXCore();
- m_element = 0;
+ m_display = DISPMANX_NO_HANDLE;
}
CRBP::~CRBP()
@@ -55,8 +55,7 @@ bool CRBP::Initialize()
m_DllBcmHost->bcm_host_init();
- uint32_t vc_image_ptr;
- m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr );
+ //OpenDisplay(0 /*screen*/);
m_omx_initialized = m_OMX->Initialize();
if(!m_omx_initialized)
@@ -112,13 +111,55 @@ void CRBP::LogFirmwareVerison()
CLog::Log(LOGNOTICE, "Config:\n%s", response);
}
+static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
+{
+ CEvent *sync = (CEvent *)arg;
+ sync->Set();
+}
+
+void CRBP::WaitVsync()
+{
+ CSingleLock lock (m_critSection);
+ if (m_display == DISPMANX_NO_HANDLE)
+ {
+ // don't busy spin
+ Sleep(10);
+ return;
+ }
+ m_vsync.Reset();
+ m_vsync.Wait();
+}
+
+DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
+{
+ CSingleLock lock (m_critSection);
+ if (m_display == DISPMANX_NO_HANDLE)
+ m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+
+ if (m_display != DISPMANX_NO_HANDLE)
+ {
+ int s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&m_vsync);
+ assert(s == 0);
+ }
+ return m_display;
+}
+
+void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
+{
+ CSingleLock lock (m_critSection);
+ assert(display == m_display);
+
+ int s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
+ assert(s == 0);
+
+ vc_dispmanx_display_close(m_display);
+ m_display = DISPMANX_NO_HANDLE;
+}
+
void CRBP::GetDisplaySize(int &width, int &height)
{
- DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
-
- display = vc_dispmanx_display_open( 0 /*screen*/ );
- if (vc_dispmanx_display_get_info(display, &info) == 0)
+ if (vc_dispmanx_display_get_info(m_display, &info) == 0)
{
width = info.width;
height = info.height;
@@ -128,12 +169,10 @@ void CRBP::GetDisplaySize(int &width, int &height)
width = 0;
height = 0;
}
- vc_dispmanx_display_close(display );
}
unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only)
{
- DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_RESOURCE_HANDLE_T resource;
VC_RECT_T rect;
unsigned char *image = NULL;
@@ -148,7 +187,6 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
if (!pstride)
flags |= DISPMANX_SNAPSHOT_PACK;
- display = vc_dispmanx_display_open( 0 /*screen*/ );
stride = ((width + 15) & ~15) * 4;
image = new unsigned char [height * stride];
@@ -156,56 +194,30 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
{
resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr );
- vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags);
+ assert(m_display != DISPMANX_NO_HANDLE);
+ vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags);
vc_dispmanx_rect_set(&rect, 0, 0, width, height);
vc_dispmanx_resource_read_data(resource, &rect, image, stride);
vc_dispmanx_resource_delete( resource );
- vc_dispmanx_display_close(display );
}
if (pstride)
*pstride = stride;
return image;
}
-void CRBP::WaitVsync(void)
-{
- DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ );
- DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
-
- VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 };
- VC_RECT_T src_rect;
- VC_RECT_T dst_rect;
- vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 );
- vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 );
-
- if (m_element)
- vc_dispmanx_element_remove( update, m_element );
-
- m_element = vc_dispmanx_element_add( update,
- display,
- 2000, // layer
- &dst_rect,
- m_resource,
- &src_rect,
- DISPMANX_PROTECTION_NONE,
- &alpha,
- NULL, // clamp
- (DISPMANX_TRANSFORM_T)0 );
-
- vc_dispmanx_update_submit_sync(update);
- vc_dispmanx_display_close( display );
-}
-
-
void CRBP::Deinitialize()
{
+ CSingleLock lock (m_critSection);
if (m_omx_image_init)
g_OMXImage.Deinitialize();
if(m_omx_initialized)
m_OMX->Deinitialize();
+ if (m_display)
+ CloseDisplay(m_display);
+
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index f947acc..029d69c 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -38,6 +38,7 @@
#include "DllBCM.h"
#include "OMXCore.h"
#include "threads/CriticalSection.h"
+#include "threads/Event.h"
class CRBP
{
@@ -53,6 +54,8 @@ class CRBP
bool GetCodecMpg2() { return m_codec_mpg2_enabled; }
bool GetCodecWvc1() { return m_codec_wvc1_enabled; }
void GetDisplaySize(int &width, int &height);
+ DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device);
+ void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display);
int GetGUIResolutionLimit() { return m_gui_resolution_limit; }
// stride can be null for packed output
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
@@ -73,10 +76,10 @@ class CRBP
bool m_codec_mpg2_enabled;
bool m_codec_wvc1_enabled;
COMXCore *m_OMX;
- DISPMANX_RESOURCE_HANDLE_T m_resource;
- DISPMANX_ELEMENT_HANDLE_T m_element;
class DllLibOMXCore;
CCriticalSection m_critSection;
+ DISPMANX_DISPLAY_HANDLE_T m_display;
+ CEvent m_vsync;
};
extern CRBP g_RBP;
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 1529045..b6bf1fc 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
m_desktopRes = res;
}
- m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
+ m_dispman_display = g_RBP.OpenDisplay(0);
m_width = res.iWidth;
m_height = res.iHeight;
@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
if (m_dispman_display != DISPMANX_NO_HANDLE)
{
- m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
+ g_RBP.CloseDisplay(m_dispman_display);
m_dispman_display = DISPMANX_NO_HANDLE;
}
DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
From acb93970c12591f2b3c5cc2e514a6055b1128f35 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 18 Sep 2014 23:14:31 +0100
Subject: [PATCH 76/99] Revert "rbp: Use new dispmanx function for vsync
callbacks"
This reverts commit e56163da23b6a844e7eee076e4583bce606f788b.
---
xbmc/linux/RBP.cpp | 96 +++++++++++--------------
xbmc/linux/RBP.h | 7 +-
xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +-
3 files changed, 46 insertions(+), 61 deletions(-)
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 8ce60cb..34e0108 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -33,7 +33,7 @@ CRBP::CRBP()
m_omx_initialized = false;
m_DllBcmHost = new DllBcmHost();
m_OMX = new COMXCore();
- m_display = DISPMANX_NO_HANDLE;
+ m_element = 0;
}
CRBP::~CRBP()
@@ -55,7 +55,8 @@ bool CRBP::Initialize()
m_DllBcmHost->bcm_host_init();
- //OpenDisplay(0 /*screen*/);
+ uint32_t vc_image_ptr;
+ m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr );
m_omx_initialized = m_OMX->Initialize();
if(!m_omx_initialized)
@@ -111,55 +112,13 @@ void CRBP::LogFirmwareVerison()
CLog::Log(LOGNOTICE, "Config:\n%s", response);
}
-static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
-{
- CEvent *sync = (CEvent *)arg;
- sync->Set();
-}
-
-void CRBP::WaitVsync()
-{
- CSingleLock lock (m_critSection);
- if (m_display == DISPMANX_NO_HANDLE)
- {
- // don't busy spin
- Sleep(10);
- return;
- }
- m_vsync.Reset();
- m_vsync.Wait();
-}
-
-DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
-{
- CSingleLock lock (m_critSection);
- if (m_display == DISPMANX_NO_HANDLE)
- m_display = vc_dispmanx_display_open( 0 /*screen*/ );
-
- if (m_display != DISPMANX_NO_HANDLE)
- {
- int s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&m_vsync);
- assert(s == 0);
- }
- return m_display;
-}
-
-void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
-{
- CSingleLock lock (m_critSection);
- assert(display == m_display);
-
- int s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
- assert(s == 0);
-
- vc_dispmanx_display_close(m_display);
- m_display = DISPMANX_NO_HANDLE;
-}
-
void CRBP::GetDisplaySize(int &width, int &height)
{
+ DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
- if (vc_dispmanx_display_get_info(m_display, &info) == 0)
+
+ display = vc_dispmanx_display_open( 0 /*screen*/ );
+ if (vc_dispmanx_display_get_info(display, &info) == 0)
{
width = info.width;
height = info.height;
@@ -169,10 +128,12 @@ void CRBP::GetDisplaySize(int &width, int &height)
width = 0;
height = 0;
}
+ vc_dispmanx_display_close(display );
}
unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only)
{
+ DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_RESOURCE_HANDLE_T resource;
VC_RECT_T rect;
unsigned char *image = NULL;
@@ -187,6 +148,7 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
if (!pstride)
flags |= DISPMANX_SNAPSHOT_PACK;
+ display = vc_dispmanx_display_open( 0 /*screen*/ );
stride = ((width + 15) & ~15) * 4;
image = new unsigned char [height * stride];
@@ -194,30 +156,56 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
{
resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr );
- assert(m_display != DISPMANX_NO_HANDLE);
- vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags);
+ vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags);
vc_dispmanx_rect_set(&rect, 0, 0, width, height);
vc_dispmanx_resource_read_data(resource, &rect, image, stride);
vc_dispmanx_resource_delete( resource );
+ vc_dispmanx_display_close(display );
}
if (pstride)
*pstride = stride;
return image;
}
+void CRBP::WaitVsync(void)
+{
+ DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ );
+ DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
+
+ VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 };
+ VC_RECT_T src_rect;
+ VC_RECT_T dst_rect;
+ vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 );
+ vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 );
+
+ if (m_element)
+ vc_dispmanx_element_remove( update, m_element );
+
+ m_element = vc_dispmanx_element_add( update,
+ display,
+ 2000, // layer
+ &dst_rect,
+ m_resource,
+ &src_rect,
+ DISPMANX_PROTECTION_NONE,
+ &alpha,
+ NULL, // clamp
+ (DISPMANX_TRANSFORM_T)0 );
+
+ vc_dispmanx_update_submit_sync(update);
+ vc_dispmanx_display_close( display );
+}
+
+
void CRBP::Deinitialize()
{
- CSingleLock lock (m_critSection);
if (m_omx_image_init)
g_OMXImage.Deinitialize();
if(m_omx_initialized)
m_OMX->Deinitialize();
- if (m_display)
- CloseDisplay(m_display);
-
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index 029d69c..f947acc 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -38,7 +38,6 @@
#include "DllBCM.h"
#include "OMXCore.h"
#include "threads/CriticalSection.h"
-#include "threads/Event.h"
class CRBP
{
@@ -54,8 +53,6 @@ class CRBP
bool GetCodecMpg2() { return m_codec_mpg2_enabled; }
bool GetCodecWvc1() { return m_codec_wvc1_enabled; }
void GetDisplaySize(int &width, int &height);
- DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device);
- void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display);
int GetGUIResolutionLimit() { return m_gui_resolution_limit; }
// stride can be null for packed output
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
@@ -76,10 +73,10 @@ class CRBP
bool m_codec_mpg2_enabled;
bool m_codec_wvc1_enabled;
COMXCore *m_OMX;
+ DISPMANX_RESOURCE_HANDLE_T m_resource;
+ DISPMANX_ELEMENT_HANDLE_T m_element;
class DllLibOMXCore;
CCriticalSection m_critSection;
- DISPMANX_DISPLAY_HANDLE_T m_display;
- CEvent m_vsync;
};
extern CRBP g_RBP;
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index b6bf1fc..1529045 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
m_desktopRes = res;
}
- m_dispman_display = g_RBP.OpenDisplay(0);
+ m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
m_width = res.iWidth;
m_height = res.iHeight;
@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
if (m_dispman_display != DISPMANX_NO_HANDLE)
{
- g_RBP.CloseDisplay(m_dispman_display);
+ m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
m_dispman_display = DISPMANX_NO_HANDLE;
}
DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
From ae43237eccd719fd1760f7d2bfd44c4229617c9d Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 19 Sep 2014 11:54:49 +0100
Subject: [PATCH 77/99] [dvdplayer/rbp] Add pi specific option to maintain
vsync with pll adjustment
New A/V sync option in settings/video/playback to do "Adjust PLL".
This uses video clock (so perfect video syncing) but avoids having to resample
or drop/dupe audio packets which is normally required.
Needed updated firmware
---
language/English/strings.po | 5 +++++
system/settings/rbp.xml | 20 ++++++++++++++++++
xbmc/cores/AudioEngine/Utils/AEUtil.h | 3 ++-
xbmc/cores/dvdplayer/DVDPlayerAudio.cpp | 36 +++++++++++++++++++++++++++++++--
xbmc/cores/dvdplayer/DVDPlayerAudio.h | 1 +
xbmc/linux/RBP.cpp | 13 ++++++++++++
xbmc/linux/RBP.h | 1 +
7 files changed, 76 insertions(+), 3 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index d9b4519..aba172a 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15978,3 +15978,8 @@ msgstr ""
msgctxt "#38005"
msgid "24 fps"
msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38006"
+msgid "Adjust PLL"
+msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 3c372bf..9ecae65 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -11,6 +11,26 @@
</section>
<section id="videos">
+ <category id="videoplayer" label="14086" help="36151">
+ <group id="2">
+ <setting id="videoplayer.synctype" type="integer" parent="videoplayer.usedisplayasclock" label="13500" help="36167">
+ <level>2</level>
+ <default>2</default> <!-- SYNC_RESAMPLE -->
+ <constraints>
+ <options>
+ <option label="13501">0</option> <!-- SYNC_DISCON -->
+ <option label="13502">1</option> <!-- SYNC_SKIPDUP -->
+ <option label="13503">2</option> <!-- SYNC_RESAMPLE -->
+ <option label="38006">3</option> <!-- SYNC_PLLADJUST -->
+ </options>
+ </constraints>
+ <dependencies>
+ <dependency type="enable" setting="videoplayer.usedisplayasclock" operator="is">true</dependency>
+ </dependencies>
+ <control type="spinner" format="string" />
+ </setting>
+ </group>
+ </category>
<category id="videoacceleration">
<group id="1">
<visible>false</visible>
diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h
index 1e61c50..039cd69 100644
--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h
+++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h
@@ -53,7 +53,8 @@ enum AVSync
{
SYNC_DISCON = 0,
SYNC_SKIPDUP,
- SYNC_RESAMPLE
+ SYNC_RESAMPLE,
+ SYNC_PLLADJUST
};
struct AEDelayStatus
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
index 98da461..bb2c375 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
@@ -112,6 +112,7 @@ CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock, CDVDMessageQueue& parent)
m_started = false;
m_silence = false;
m_resampleratio = 1.0;
+ m_plladjust = 1.0f;
m_synctype = SYNC_DISCON;
m_setsynctype = SYNC_DISCON;
m_prevsynctype = -1;
@@ -472,6 +473,8 @@ void CDVDPlayerAudio::UpdatePlayerInfo()
//if the resample ratio is 0.5, then we're playing twice as fast
if (m_synctype == SYNC_RESAMPLE)
s << ", rr:" << fixed << setprecision(5) << 1.0 / m_resampleratio;
+ if (m_synctype == SYNC_PLLADJUST)
+ s << ", pll:" << fixed << setprecision(5) << 1.0 / m_plladjust;
s << ", att:" << fixed << setprecision(1) << log(GetCurrentAttenuation()) * 20.0f << " dB";
@@ -622,8 +625,8 @@ void CDVDPlayerAudio::SetSyncType(bool passthrough)
if (m_synctype != m_prevsynctype)
{
- const char *synctypes[] = {"clock feedback", "skip/duplicate", "resample", "invalid"};
- int synctype = (m_synctype >= 0 && m_synctype <= 2) ? m_synctype : 3;
+ const char *synctypes[] = {"clock feedback", "skip/duplicate", "resample", "pll adjust", "invalid"};
+ int synctype = (m_synctype >= 0 && m_synctype <= 3) ? m_synctype : 4;
CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: synctype set to %i: %s", m_synctype, synctypes[synctype]);
m_prevsynctype = m_synctype;
}
@@ -697,6 +700,31 @@ void CDVDPlayerAudio::HandleSyncError(double duration)
}
m_resampleratio = 1.0 / m_pClock->GetClockSpeed() + proportional + m_integral;
}
+ else if (m_synctype == SYNC_PLLADJUST)
+ {
+#if defined(TARGET_RASPBERRY_PI)
+ //reset the integral on big errors, failsafe
+ if (fabs(m_error) > DVD_TIME_BASE)
+ m_integral = 0;
+ else if (fabs(m_error) > DVD_MSEC_TO_TIME(5))
+ m_integral += m_error / DVD_TIME_BASE / INTEGRAL;
+
+ double proportional = 0.0;
+
+ //on big errors use more proportional
+ if (fabs(m_error / DVD_TIME_BASE) > 0.0)
+ {
+ double proportionaldiv = PROPORTIONAL * (PROPREF / fabs(m_error / DVD_TIME_BASE));
+ if (proportionaldiv < PROPDIVMIN) proportionaldiv = PROPDIVMIN;
+ else if (proportionaldiv > PROPDIVMAX) proportionaldiv = PROPDIVMAX;
+
+ proportional = m_error / DVD_TIME_BASE / proportionaldiv;
+ }
+ m_plladjust = 1.0 / m_pClock->GetClockSpeed() + proportional + m_integral;
+ double new_adjust = g_RBP.AdjustHDMIClock(m_plladjust);
+ CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s pll:%.4f (%.4f) proportional:%.4f integral:%.4f", __FUNCTION__, m_plladjust, new_adjust, proportional, m_integral);
+#endif
+ }
}
}
@@ -735,6 +763,10 @@ bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
m_dvdAudio.SetResampleRatio(m_resampleratio);
m_dvdAudio.AddPackets(audioframe);
}
+ else if (m_synctype == SYNC_PLLADJUST)
+ {
+ m_dvdAudio.AddPackets(audioframe);
+ }
return true;
}
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.h b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
index e8b2ab6..02c64a0 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
@@ -232,6 +232,7 @@ class CDVDPlayerAudio : public CThread, public IDVDStreamPlayerAudio
bool m_prevskipped;
double m_maxspeedadjust;
double m_resampleratio; //resample ratio when using SYNC_RESAMPLE, used for the codec info
+ double m_plladjust; // for display using SYNC_PLLADJUST
struct SInfo
{
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 34e0108..3cd8e18 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -230,4 +230,17 @@ void CRBP::ResumeVideoOutput()
CLog::Log(LOGDEBUG, "Raspberry PI resuming video output\n");
}
+double CRBP::AdjustHDMIClock(double adjust)
+{
+ char response[80];
+ vc_gencmd(response, sizeof response, "hdmi_adjust_clock %f", adjust);
+ float new_adjust = 1.0f;
+ char *p = strchr(response, '=');
+ if (p)
+ new_adjust = atof(p+1);
+ CLog::Log(LOGDEBUG, "CRBP::%s(%.4f) = %.4f", __func__, adjust, new_adjust);
+ return new_adjust;
+}
+
+
#endif
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index f947acc..606c24f 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -58,6 +58,7 @@ class CRBP
unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
void WaitVsync();
+ double AdjustHDMIClock(double adjust);
void SuspendVideoOutput();
void ResumeVideoOutput();
From af3c4e730f3dec154902fd1c1dd7ce300e839b6f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 21 Sep 2014 18:31:31 +0100
Subject: [PATCH 78/99] hack: revert squash: don't update originaldts when
marked as invalid
---
xbmc/cores/dvdplayer/DVDPlayer.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index c89aae2..c34b96f 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -2106,6 +2106,7 @@ void CDVDPlayer::CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket)
// not sure yet - flags the packets as unknown until we get confirmation on another audio/video packet
pPacket->dts = DVD_NOPTS_VALUE;
pPacket->pts = DVD_NOPTS_VALUE;
+ current.originaldts = pPacket->dts;
}
}
else
From b1acf2753346ecdf070a2c3b29af797b008545e7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 27 Sep 2014 15:27:04 +0100
Subject: [PATCH 79/99] [omxplayer] Don't sync up to passthrough audio packets
- let GPU handle it
---
xbmc/cores/omxplayer/OMXAudio.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index 3c6c73b..d7149d9 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -1119,6 +1119,7 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
return len;
}
+#if 0
if(m_eEncoding == OMX_AUDIO_CodingDTS && m_LostSync && (m_Passthrough || m_HWDecode))
{
int skip = SyncDTS((uint8_t *)data, len);
@@ -1132,6 +1133,7 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
if(skip > 0)
return len;
}
+#endif
unsigned pitch = (m_Passthrough || m_HWDecode) ? 1:(m_BitsPerSample >> 3) * m_InputChannels;
unsigned int demuxer_samples = len / pitch;
From d7b9180b0396eee6fec27289de65960482032c1f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 27 Sep 2014 15:32:37 +0100
Subject: [PATCH 80/99] [dvdplayer] exerimental: don't raise priority of audio
thread
---
xbmc/cores/dvdplayer/DVDPlayer.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index c34b96f..c55e119 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -3320,7 +3320,11 @@ bool CDVDPlayer::OpenAudioStream(CDVDStreamInfo& hint, bool reset)
m_dvdPlayerAudio->SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1);
/* audio normally won't consume full cpu, so let it have prio */
+#ifdef TARGET_RASPBERRY_PI
+ m_dvdPlayerAudio->SetPriority(GetPriority());
+#else
m_dvdPlayerAudio->SetPriority(GetPriority()+1);
+#endif
return true;
}
From f201e6105d7268d3c49fca9059621a4511db09d5 Mon Sep 17 00:00:00 2001
From: da-anda <da-anda@xbmc.org>
Date: Sun, 17 Aug 2014 21:09:59 +0200
Subject: [PATCH 81/99] handle stereoscopic mode of videos in mixed playlists
---
language/English/strings.po | 2 +-
xbmc/guilib/StereoscopicsManager.cpp | 76 +++++++++++++++++++++++-------------
2 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index aba172a..5143e3e 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15612,7 +15612,7 @@ msgstr ""
#. Description of setting "Videos -> Playback -> Disable stereoscopic mode when playback is stopped" with label #36526
#: system/settings/settings.xml
msgctxt "#36538"
-msgid "[Enabled] Switch GUI (and some TVs) back to 2D mode when playback ended. [Disabled] GUI and TV will stay in stereoscopic 3D mode. For video playlists the stereoscopic 3D mode won't change between videos, not even for non stereoscopic ones."
+msgid "[Enabled] Switch GUI (and some TVs) back to 2D mode when playback ended - also between videos in a playlist if necessary. [Disabled] GUI and TV will stay in stereoscopic 3D mode. For video playlists the stereoscopic 3D mode won't change between videos, not even for non stereoscopic ones."
msgstr ""
#. Description of setting "System -> Video output -> Stereoscopic mode (current)" with label #36500
diff --git a/xbmc/guilib/StereoscopicsManager.cpp b/xbmc/guilib/StereoscopicsManager.cpp
index 35ba597..b013942 100644
--- a/xbmc/guilib/StereoscopicsManager.cpp
+++ b/xbmc/guilib/StereoscopicsManager.cpp
@@ -123,13 +123,23 @@ RENDER_STEREO_MODE CStereoscopicsManager::GetStereoMode(void)
void CStereoscopicsManager::SetStereoMode(const RENDER_STEREO_MODE &mode)
{
RENDER_STEREO_MODE currentMode = GetStereoMode();
- if (mode != currentMode && mode >= RENDER_STEREO_MODE_OFF)
+ RENDER_STEREO_MODE applyMode = mode;
+
+ // resolve automatic mode before applying
+ if (mode == RENDER_STEREO_MODE_AUTO)
{
- if(!g_Windowing.SupportsStereo(mode))
- return;
+ if (g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
+ applyMode = GetStereoModeOfPlayingVideo();
+ else
+ applyMode = RENDER_STEREO_MODE_OFF;
+ }
+ if (applyMode != currentMode && applyMode >= RENDER_STEREO_MODE_OFF)
+ {
+ if (!g_Windowing.SupportsStereo(applyMode))
+ return;
m_lastStereoMode = currentMode;
- CSettings::Get().SetInt("videoscreen.stereoscopicmode", mode);
+ CSettings::Get().SetInt("videoscreen.stereoscopicmode", applyMode);
}
}
@@ -210,6 +220,12 @@ RENDER_STEREO_MODE CStereoscopicsManager::GetStereoModeByUserChoice(const CStdSt
if (mode == selectableMode)
pDlgSelect->SetSelected( label );
}
+ // inject AUTO pseudo mode after OFF
+ if (i == RENDER_STEREO_MODE_OFF)
+ {
+ selectableModes.push_back(RENDER_STEREO_MODE_AUTO);
+ pDlgSelect->Add(GetLabelForStereoMode(RENDER_STEREO_MODE_AUTO));
+ }
}
pDlgSelect->DoModal();
@@ -248,20 +264,7 @@ CStdString CStereoscopicsManager::GetLabelForStereoMode(const RENDER_STEREO_MODE
RENDER_STEREO_MODE CStereoscopicsManager::GetPreferredPlaybackMode(void)
{
- RENDER_STEREO_MODE playbackMode = m_lastStereoMode;
- int preferredMode = CSettings::Get().GetInt("videoscreen.preferedstereoscopicmode");
- if (preferredMode == RENDER_STEREO_MODE_AUTO) // automatic mode, detect by movie
- {
- if (g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
- playbackMode = GetStereoModeOfPlayingVideo();
- else if (playbackMode == RENDER_STEREO_MODE_OFF)
- playbackMode = GetNextSupportedStereoMode(RENDER_STEREO_MODE_OFF);
- }
- else // predefined mode
- {
- playbackMode = (RENDER_STEREO_MODE) preferredMode;
- }
- return playbackMode;
+ return (RENDER_STEREO_MODE) CSettings::Get().GetInt("videoscreen.preferedstereoscopicmode");
}
int CStereoscopicsManager::ConvertVideoToGuiStereoMode(const std::string &mode)
@@ -450,9 +453,6 @@ void CStereoscopicsManager::ApplyStereoMode(const RENDER_STEREO_MODE &mode, bool
void CStereoscopicsManager::OnPlaybackStarted(void)
{
- if (!g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
- return;
-
STEREOSCOPIC_PLAYBACK_MODE playbackMode = (STEREOSCOPIC_PLAYBACK_MODE) CSettings::Get().GetInt("videoplayer.stereoscopicplaybackmode");
RENDER_STEREO_MODE mode = GetStereoMode();
@@ -460,8 +460,31 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
if (playbackMode == STEREOSCOPIC_PLAYBACK_MODE_IGNORE && mode == RENDER_STEREO_MODE_OFF)
return;
- if (mode != RENDER_STEREO_MODE_OFF)
+ if (!g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
+ {
+ // exit stereo mode if started item is not stereoscopic
+ // and if user prefers to stop 3D playback when movie is finished
+ if (mode != RENDER_STEREO_MODE_OFF && CSettings::Get().GetBool("videoplayer.quitstereomodeonstop"))
+ SetStereoMode(RENDER_STEREO_MODE_OFF);
return;
+ }
+
+ RENDER_STEREO_MODE preferred = GetPreferredPlaybackMode();
+ RENDER_STEREO_MODE playing = GetStereoModeOfPlayingVideo();
+
+ if (mode != RENDER_STEREO_MODE_OFF)
+ {
+ // don't change mode if user selected to not exit stereomode on playback stop
+ // users selecting this option usually have to manually switch their TV into 3D mode
+ // and would be annoyed by having to switch TV modes when next movies comes up
+ // @todo probably add a new setting for just this behavior
+ if (CSettings::Get().GetBool("videoplayer.quitstereomodeonstop") == false)
+ return;
+
+ // only change to new stereo mode if not yet in preferred stereo mode
+ if (mode == preferred || (preferred == RENDER_STEREO_MODE_AUTO && mode == playing))
+ return;
+ }
switch (playbackMode)
{
@@ -473,9 +496,6 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
pDlgSelect->Reset();
pDlgSelect->SetHeading(g_localizeStrings.Get(36527).c_str());
- RENDER_STEREO_MODE preferred = GetPreferredPlaybackMode();
- RENDER_STEREO_MODE playing = GetStereoModeOfPlayingVideo();
-
int idx_playing = -1
, idx_mono = -1;
@@ -488,7 +508,7 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
idx_mono = pDlgSelect->Add(GetLabelForStereoMode(RENDER_STEREO_MODE_MONO)); // mono / 2d
- if(playing != RENDER_STEREO_MODE_OFF && playing != preferred && g_Windowing.SupportsStereo(playing))
+ if (playing != RENDER_STEREO_MODE_OFF && playing != preferred && preferred != RENDER_STEREO_MODE_AUTO && g_Windowing.SupportsStereo(playing)) // same as movie
idx_playing = pDlgSelect->Add((CStdString)g_localizeStrings.Get(36532)
+ " ("
+ GetLabelForStereoMode(playing)
@@ -503,7 +523,7 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
int iItem = pDlgSelect->GetSelectedLabel();
if (iItem == idx_preferred) mode = preferred;
else if (iItem == idx_mono) mode = RENDER_STEREO_MODE_MONO;
- else if (iItem == idx_playing) mode = playing;
+ else if (iItem == idx_playing) mode = RENDER_STEREO_MODE_AUTO;
else if (iItem == idx_select) mode = GetStereoModeByUserChoice();
SetStereoMode(mode);
@@ -513,7 +533,7 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
}
break;
case STEREOSCOPIC_PLAYBACK_MODE_PREFERRED: // Stereoscopic
- SetStereoMode( GetPreferredPlaybackMode() );
+ SetStereoMode( preferred );
break;
case 2: // Mono
SetStereoMode( RENDER_STEREO_MODE_MONO );
From 9e888b8b6d3e4b55d57e16c443449497ac7ef520 Mon Sep 17 00:00:00 2001
From: da-anda <da-anda@xbmc.org>
Date: Sat, 16 Aug 2014 11:20:54 +0200
Subject: [PATCH 82/99] remember user selected 3D modes between videos until
playback ended
---
xbmc/guilib/StereoscopicsManager.cpp | 79 ++++++++++++++++++++++++++----------
xbmc/guilib/StereoscopicsManager.h | 6 ++-
xbmc/rendering/RenderSystem.h | 1 +
3 files changed, 63 insertions(+), 23 deletions(-)
diff --git a/xbmc/guilib/StereoscopicsManager.cpp b/xbmc/guilib/StereoscopicsManager.cpp
index b013942..3db8eaa 100644
--- a/xbmc/guilib/StereoscopicsManager.cpp
+++ b/xbmc/guilib/StereoscopicsManager.cpp
@@ -95,7 +95,8 @@ static const struct StereoModeMap StringToGuiModeMap[] =
CStereoscopicsManager::CStereoscopicsManager(void)
{
- m_lastStereoMode = RENDER_STEREO_MODE_OFF;
+ m_stereoModeSetByUser = RENDER_STEREO_MODE_UNDEFINED;
+ m_lastStereoModeSetByUser = RENDER_STEREO_MODE_UNDEFINED;
}
CStereoscopicsManager::~CStereoscopicsManager(void)
@@ -110,7 +111,6 @@ CStereoscopicsManager& CStereoscopicsManager::Get(void)
void CStereoscopicsManager::Initialize(void)
{
- m_lastStereoMode = GetStereoMode();
// turn off stereo mode on XBMC startup
SetStereoMode(RENDER_STEREO_MODE_OFF);
}
@@ -120,6 +120,16 @@ RENDER_STEREO_MODE CStereoscopicsManager::GetStereoMode(void)
return (RENDER_STEREO_MODE) CSettings::Get().GetInt("videoscreen.stereoscopicmode");
}
+void CStereoscopicsManager::SetStereoModeByUser(const RENDER_STEREO_MODE &mode)
+{
+ // only update last user mode if desired mode is different from current
+ if (mode != m_stereoModeSetByUser)
+ m_lastStereoModeSetByUser = m_stereoModeSetByUser;
+
+ m_stereoModeSetByUser = mode;
+ SetStereoMode(mode);
+}
+
void CStereoscopicsManager::SetStereoMode(const RENDER_STEREO_MODE &mode)
{
RENDER_STEREO_MODE currentMode = GetStereoMode();
@@ -138,7 +148,6 @@ void CStereoscopicsManager::SetStereoMode(const RENDER_STEREO_MODE &mode)
{
if (!g_Windowing.SupportsStereo(applyMode))
return;
- m_lastStereoMode = currentMode;
CSettings::Get().SetInt("videoscreen.stereoscopicmode", applyMode);
}
}
@@ -384,46 +393,65 @@ bool CStereoscopicsManager::OnAction(const CAction &action)
if (action.GetID() == ACTION_STEREOMODE_NEXT)
{
- SetStereoMode(GetNextSupportedStereoMode(mode));
+ SetStereoModeByUser(GetNextSupportedStereoMode(mode));
return true;
}
else if (action.GetID() == ACTION_STEREOMODE_PREVIOUS)
{
- SetStereoMode(GetNextSupportedStereoMode(mode, RENDER_STEREO_MODE_COUNT - 1));
+ SetStereoModeByUser(GetNextSupportedStereoMode(mode, RENDER_STEREO_MODE_COUNT - 1));
return true;
}
else if (action.GetID() == ACTION_STEREOMODE_TOGGLE)
{
if (mode == RENDER_STEREO_MODE_OFF)
{
- RENDER_STEREO_MODE targetMode = m_lastStereoMode;
- if (targetMode == RENDER_STEREO_MODE_OFF)
- targetMode = GetPreferredPlaybackMode();
- SetStereoMode(targetMode);
+ RENDER_STEREO_MODE targetMode = GetPreferredPlaybackMode();
+
+ // if user selected a specific mode before, make sure to
+ // switch back into that mode on toggle.
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_UNDEFINED)
+ {
+ // if user mode is set to OFF, he manually turned it off before. In this case use the last user applied mode
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_OFF)
+ targetMode = m_stereoModeSetByUser;
+ else if (m_lastStereoModeSetByUser != RENDER_STEREO_MODE_UNDEFINED && m_lastStereoModeSetByUser != RENDER_STEREO_MODE_OFF)
+ targetMode = m_lastStereoModeSetByUser;
+ }
+
+ SetStereoModeByUser(targetMode);
}
else
{
- SetStereoMode(RENDER_STEREO_MODE_OFF);
+ SetStereoModeByUser(RENDER_STEREO_MODE_OFF);
}
return true;
}
else if (action.GetID() == ACTION_STEREOMODE_SELECT)
{
- SetStereoMode(GetStereoModeByUserChoice());
+ SetStereoModeByUser(GetStereoModeByUserChoice());
return true;
}
else if (action.GetID() == ACTION_STEREOMODE_TOMONO)
{
if (mode == RENDER_STEREO_MODE_MONO)
{
- RENDER_STEREO_MODE targetMode = m_lastStereoMode;
- if (targetMode == RENDER_STEREO_MODE_OFF)
- targetMode = GetPreferredPlaybackMode();
- SetStereoMode(targetMode);
+ RENDER_STEREO_MODE targetMode = GetPreferredPlaybackMode();
+
+ // if we have an old userdefined steremode, use that one as toggle target
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_UNDEFINED)
+ {
+ // if user mode is set to OFF, he manually turned it off before. In this case use the last user applied mode
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_OFF && m_stereoModeSetByUser != mode)
+ targetMode = m_stereoModeSetByUser;
+ else if (m_lastStereoModeSetByUser != RENDER_STEREO_MODE_UNDEFINED && m_lastStereoModeSetByUser != RENDER_STEREO_MODE_OFF && m_lastStereoModeSetByUser != mode)
+ targetMode = m_lastStereoModeSetByUser;
+ }
+
+ SetStereoModeByUser(targetMode);
}
else
{
- SetStereoMode(RENDER_STEREO_MODE_MONO);
+ SetStereoModeByUser(RENDER_STEREO_MODE_MONO);
}
return true;
}
@@ -431,7 +459,7 @@ bool CStereoscopicsManager::OnAction(const CAction &action)
{
int stereoMode = ConvertStringToGuiStereoMode(action.GetName());
if (stereoMode > -1)
- SetStereoMode( (RENDER_STEREO_MODE) stereoMode);
+ SetStereoModeByUser( (RENDER_STEREO_MODE) stereoMode );
return true;
}
@@ -469,6 +497,13 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
return;
}
+ // if we're not in stereomode yet, restore previously selected stereo mode in case it was user selected
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_UNDEFINED)
+ {
+ SetStereoMode(m_stereoModeSetByUser);
+ return;
+ }
+
RENDER_STEREO_MODE preferred = GetPreferredPlaybackMode();
RENDER_STEREO_MODE playing = GetStereoModeOfPlayingVideo();
@@ -526,7 +561,7 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
else if (iItem == idx_playing) mode = RENDER_STEREO_MODE_AUTO;
else if (iItem == idx_select) mode = GetStereoModeByUserChoice();
- SetStereoMode(mode);
+ SetStereoModeByUser( mode );
}
CApplicationMessenger::Get().MediaUnPause();
@@ -546,8 +581,10 @@ void CStereoscopicsManager::OnPlaybackStarted(void)
void CStereoscopicsManager::OnPlaybackStopped(void)
{
RENDER_STEREO_MODE mode = GetStereoMode();
- if (CSettings::Get().GetBool("videoplayer.quitstereomodeonstop") == true && mode != RENDER_STEREO_MODE_OFF)
- {
+ if (CSettings::Get().GetBool("videoplayer.quitstereomodeonstop") && mode != RENDER_STEREO_MODE_OFF)
SetStereoMode(RENDER_STEREO_MODE_OFF);
- }
+ // reset user modes on playback end to start over new on next playback and not end up in a probably unwanted mode
+ if (m_stereoModeSetByUser != RENDER_STEREO_MODE_OFF)
+ m_lastStereoModeSetByUser = m_stereoModeSetByUser;
+ m_stereoModeSetByUser = RENDER_STEREO_MODE_UNDEFINED;
}
diff --git a/xbmc/guilib/StereoscopicsManager.h b/xbmc/guilib/StereoscopicsManager.h
index 422cba2..6e9c36d 100644
--- a/xbmc/guilib/StereoscopicsManager.h
+++ b/xbmc/guilib/StereoscopicsManager.h
@@ -54,8 +54,9 @@ class CStereoscopicsManager : public ISettingCallback,
static CStereoscopicsManager& Get(void);
void Initialize(void);
- void SetStereoMode(const RENDER_STEREO_MODE &mode);
RENDER_STEREO_MODE GetStereoMode(void);
+ void SetStereoModeByUser(const RENDER_STEREO_MODE &mode);
+ void SetStereoMode(const RENDER_STEREO_MODE &mode);
RENDER_STEREO_MODE GetNextSupportedStereoMode(const RENDER_STEREO_MODE &currentMode, int step = 1);
std::string DetectStereoModeByString(const std::string &needle);
RENDER_STEREO_MODE GetStereoModeByUserChoice(const CStdString &heading = "");
@@ -92,5 +93,6 @@ class CStereoscopicsManager : public ISettingCallback,
void OnPlaybackStarted(void);
void OnPlaybackStopped(void);
- RENDER_STEREO_MODE m_lastStereoMode;
+ RENDER_STEREO_MODE m_stereoModeSetByUser;
+ RENDER_STEREO_MODE m_lastStereoModeSetByUser;
};
diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h
index c1dfb93..cb54bd0 100644
--- a/xbmc/rendering/RenderSystem.h
+++ b/xbmc/rendering/RenderSystem.h
@@ -81,6 +81,7 @@ enum RENDER_STEREO_MODE
// psuevdo modes
RENDER_STEREO_MODE_AUTO = 100,
+ RENDER_STEREO_MODE_UNDEFINED = 999,
};
From 636340c2550eb0e990b9e9a3f6f198dcbee6027e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 28 Sep 2014 17:35:31 +0100
Subject: [PATCH 83/99] [renderer] Avoid warning for too few buffers with
bypass renderer
Bypass renderer doesn't use a video render queue, so shouldn't generate a warning message
---
xbmc/cores/VideoRenderers/RenderManager.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index 1ecdc16..cc3a76b 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -270,7 +270,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
if(m_QueueSize < 2)
{
m_QueueSize = 2;
- CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, renderbuffers, buffers);
+ if (m_format != RENDER_FMT_BYPASS)
+ CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, renderbuffers, buffers);
}
m_pRenderer->SetBufferSize(m_QueueSize);
From a0b4e3298118625508321a8d132bd06b8440741d Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 28 Sep 2014 19:28:17 +0100
Subject: [PATCH 84/99] [mmalcodec] Introduce a preroll period to buffer up
frames on startup
---
xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 21 +++++++++++++--------
xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h | 1 +
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 6a1f70a..c9aa390 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -136,6 +136,7 @@ CMMALVideo::CMMALVideo()
m_output_busy = 0;
m_demux_queue_length = 0;
m_es_format = mmal_format_alloc();
+ m_preroll = true;
}
CMMALVideo::~CMMALVideo()
@@ -699,6 +700,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, MMALVide
m_drop_state = false;
m_startframe = false;
+ m_preroll = !m_hints.stills;
return true;
}
@@ -910,24 +912,26 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
break;
}
int ret = 0;
- if (!m_output_ready.empty())
+ if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length)
{
#if defined(MMAL_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s - got output picture:%d", CLASSNAME, __func__, m_output_ready.size());
+ CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
#endif
- ret |= VC_PICTURE;
+ ret |= VC_BUFFER;
}
- if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length)
+ else
+ m_preroll = false;
+ if (!m_output_ready.empty() && !m_preroll)
{
#if defined(MMAL_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
+ CLog::Log(LOGDEBUG, "%s::%s - got output picture:%d", CLASSNAME, __func__, m_output_ready.size());
#endif
- ret |= VC_BUFFER;
+ ret |= VC_PICTURE;
}
if (!ret)
{
- CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)",
- CLASSNAME, __func__, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
+ CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d) preroll(%d)",
+ CLASSNAME, __func__, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, m_preroll);
Sleep(10); // otherwise we busy spin
}
return ret;
@@ -971,6 +975,7 @@ void CMMALVideo::Reset(void)
m_decoderPts = DVD_NOPTS_VALUE;
m_droppedPics = 0;
m_decode_frame_number = 1;
+ m_preroll = !m_hints.stills;
}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
index b4aa571..a2da46b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
@@ -140,6 +140,7 @@ class CMMALVideo
unsigned int m_decode_frame_number;
double m_decoderPts;
unsigned int m_droppedPics;
+ bool m_preroll;
MMAL_COMPONENT_T *m_dec;
MMAL_PORT_T *m_dec_input;
From e661aa6bc04e0848bfb1f022014a95ef69c79ecc Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 11 Apr 2014 16:12:27 +0100
Subject: [PATCH 85/99] [omxplayer] Add ability to log more timestamp info in
extra debug settings
---
language/English/strings.po | 5 +++++
xbmc/commons/ilog.h | 1 +
xbmc/cores/dvdplayer/DVDPlayer.cpp | 10 ++++++----
xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 8 ++++----
xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 9 +++++----
xbmc/settings/AdvancedSettings.cpp | 3 +++
6 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/language/English/strings.po b/language/English/strings.po
index 5143e3e..2800c80 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -2886,6 +2886,11 @@ msgctxt "#679"
msgid "Verbose logging for CEC library"
msgstr ""
+#: xbmc/settings/AdvancedSettings.cpp
+msgctxt "#697"
+msgid "Verbose logging for OMXPLAYER"
+msgstr ""
+
#empty strings from id 680 to 699
msgctxt "#700"
diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h
index 92e2835..ad02d95 100644
--- a/xbmc/commons/ilog.h
+++ b/xbmc/commons/ilog.h
@@ -53,6 +53,7 @@
#define LOGAIRTUNES (1 << (LOGMASKBIT + 8))
#define LOGUPNP (1 << (LOGMASKBIT + 9))
#define LOGCEC (1 << (LOGMASKBIT + 10))
+#define LOGOMXPLAYER (1 << (LOGMASKBIT+11))
#include "utils/params_check_macros.h"
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index c55e119..6a9707b7 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -1135,7 +1135,8 @@ void CDVDPlayer::OMXDoProcessing()
m_OmxPlayerState.video_fifo = (int)(100.0*(m_dvdPlayerVideo->GetDecoderBufferSize()-m_dvdPlayerVideo->GetDecoderFreeSpace())/m_dvdPlayerVideo->GetDecoderBufferSize());
m_OmxPlayerState.audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio->GetCacheTotal());
- #ifdef _DEBUG
+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER))
+ {
static unsigned count;
if ((count++ & 7) == 0)
{
@@ -1155,7 +1156,7 @@ void CDVDPlayer::OMXDoProcessing()
vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
m_dvdPlayerAudio->GetLevel(), 0, 0, 100);
}
- #endif
+ }
if (audio_pts != DVD_NOPTS_VALUE)
{
audio_fifo_low = m_HasAudio && audio_fifo < threshold;
@@ -1171,13 +1172,14 @@ void CDVDPlayer::OMXDoProcessing()
if (!m_HasVideo && m_HasAudio)
video_fifo_high = true;
- #ifdef _DEBUG
+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER))
+ {
CLog::Log(LOGDEBUG, "%s::%s M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", "CDVDPlayer", __FUNCTION__,
m_OmxPlayerState.stamp*1e-6, m_OmxPlayerState.av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_OmxPlayerState.av_clock.OMXIsPaused(), m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL),
audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_OmxPlayerState.threshold,
audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high,
m_dvdPlayerAudio->GetLevel(), m_dvdPlayerVideo->GetLevel(), m_dvdPlayerAudio->GetDelay(), (float)m_dvdPlayerAudio->GetCacheTotal());
- #endif
+ }
if(!m_Pause && (m_OmxPlayerState.bOmxSentEOFs || not_accepts_data || (audio_fifo_high && video_fifo_high) || m_playSpeed != DVD_PLAYSPEED_NORMAL))
{
diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
index 01d2afc..b4d8418 100644
--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
@@ -362,10 +362,10 @@ void OMXPlayerAudio::Process()
DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
- #ifdef _DEBUG
- CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts,
- (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate);
- #endif
+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER))
+ CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts,
+ (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate);
+
if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop))
{
// we are not running until something is cached in output device
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index c2bd788..5c4a515 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -42,6 +42,7 @@
#include "DVDOverlayRenderer.h"
#include "settings/DisplaySettings.h"
#include "settings/Settings.h"
+#include "settings/AdvancedSettings.h"
#include "settings/MediaSettings.h"
#include "cores/VideoRenderers/RenderFormats.h"
#include "cores/VideoRenderers/RenderFlags.h"
@@ -461,10 +462,10 @@ void OMXPlayerVideo::Process()
DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
- #ifdef _DEBUG
- CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts,
- (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0);
- #endif
+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER))
+ CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts,
+ (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0);
+
if (m_messageQueue.GetDataSize() == 0
|| m_speed < 0)
{
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 2e2854f..413c55a 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -1389,6 +1389,9 @@ void CAdvancedSettings::SettingOptionsLoggingComponentsFiller(const CSetting *se
#ifdef HAVE_LIBCEC
list.push_back(std::make_pair(g_localizeStrings.Get(679), LOGCEC));
#endif
+#ifdef TARGET_RASPBERRY_PI
+ list.push_back(std::make_pair(g_localizeStrings.Get(697), LOGOMXPLAYER));
+#endif
}
void CAdvancedSettings::setExtraLogLevel(const std::vector<CVariant> &components)
From dc0d123d7e79e9c56f950ba2cb543ec1e8e624a7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 7 Apr 2014 23:13:55 +0100
Subject: [PATCH 86/99] [omxplayer] Add ability to dump out audio/video data
for later debugging
---
language/English/strings.po | 10 ++++++++
xbmc/commons/ilog.h | 2 ++
xbmc/cores/omxplayer/OMXAudio.cpp | 49 ++++++++++++++++++++++++++++++++++++++
xbmc/cores/omxplayer/OMXVideo.cpp | 47 ++++++++++++++++++++++++++++++++++++
xbmc/settings/AdvancedSettings.cpp | 4 ++++
5 files changed, 112 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index 2800c80..989cfcc 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -2891,6 +2891,16 @@ msgctxt "#697"
msgid "Verbose logging for OMXPLAYER"
msgstr ""
+#: xbmc/settings/AdvancedSettings.cpp
+msgctxt "#698"
+msgid "Dump video frames to debug file"
+msgstr ""
+
+#: xbmc/settings/AdvancedSettings.cpp
+msgctxt "#699"
+msgid "Dump audio frames to debug file"
+msgstr ""
+
#empty strings from id 680 to 699
msgctxt "#700"
diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h
index ad02d95..be40370 100644
--- a/xbmc/commons/ilog.h
+++ b/xbmc/commons/ilog.h
@@ -54,6 +54,8 @@
#define LOGUPNP (1 << (LOGMASKBIT + 9))
#define LOGCEC (1 << (LOGMASKBIT + 10))
#define LOGOMXPLAYER (1 << (LOGMASKBIT+11))
+#define LOGDUMPVIDEO (1 << (LOGMASKBIT+12))
+#define LOGDUMPAUDIO (1 << (LOGMASKBIT+13))
#include "utils/params_check_macros.h"
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index d7149d9..f0ae0cc 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -60,6 +60,49 @@ static const uint16_t AC3FSCod [] = {48000, 44100, 32000, 0};
static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0};
+//#define DEBUG_PLAYBACK
+static void dump_omx_buffer(OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ if (!(g_advancedSettings.CanLogComponent(LOGDUMPAUDIO)))
+ return;
+ static FILE *fp;
+ if (!omx_buffer)
+ {
+ if (fp)
+ {
+ fclose(fp);
+ fp = NULL;
+ }
+ return;
+ }
+ if (!fp)
+ {
+ char filename[1024];
+ strcpy(filename, g_advancedSettings.m_logFolder.c_str());
+ strcat(filename, "audio.dat");
+#ifdef DEBUG_PLAYBACK
+ fp = fopen(filename, "rb");
+#else
+ fp = fopen(filename, "wb");
+#endif
+ }
+ if (fp)
+ {
+#ifdef DEBUG_PLAYBACK
+ OMX_BUFFERHEADERTYPE omx = {0};
+ int s = fread(&omx, sizeof omx, 1, fp);
+ omx_buffer->nFilledLen = omx.nFilledLen;
+ omx_buffer->nFlags = omx.nFlags;
+ omx_buffer->nTimeStamp = omx.nTimeStamp;
+ if (s==1)
+ fread(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp);
+#else
+ if (fwrite(omx_buffer, sizeof *omx_buffer, 1, fp) == 1)
+ fwrite(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp);
+#endif
+ }
+}
+
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@@ -867,6 +910,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
memcpy((unsigned char *)omx_buffer->pBuffer, &m_wave_header, omx_buffer->nFilledLen);
omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
{
@@ -899,6 +943,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen);
omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
{
@@ -936,6 +981,8 @@ bool COMXAudio::Deinitialize()
CLog::Log(LOGNOTICE, "COMXAudio::%s start", __func__);
CSingleLock lock (m_critSection);
+ dump_omx_buffer(NULL);
+
if ( m_omx_tunnel_clock_analog.IsInitialized() )
m_omx_tunnel_clock_analog.Deestablish();
if ( m_omx_tunnel_clock_hdmi.IsInitialized() )
@@ -1243,6 +1290,7 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
int nRetry = 0;
while(true)
{
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err == OMX_ErrorNone)
{
@@ -1490,6 +1538,7 @@ void COMXAudio::SubmitEOS()
omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN;
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
{
diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index 0363aaa..6cfb148 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -63,6 +63,49 @@
#define MAX_TEXT_LENGTH 1024
+//#define DEBUG_PLAYBACK
+static void dump_omx_buffer(OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ if (!(g_advancedSettings.CanLogComponent(LOGDUMPVIDEO)))
+ return;
+ static FILE *fp;
+ if (!omx_buffer)
+ {
+ if (fp)
+ {
+ fclose(fp);
+ fp = NULL;
+ }
+ return;
+ }
+ if (!fp)
+ {
+ char filename[1024];
+ strcpy(filename, g_advancedSettings.m_logFolder.c_str());
+ strcat(filename, "video.dat");
+#ifdef DEBUG_PLAYBACK
+ fp = fopen(filename, "rb");
+#else
+ fp = fopen(filename, "wb");
+#endif
+ }
+ if (fp)
+ {
+#ifdef DEBUG_PLAYBACK
+ OMX_BUFFERHEADERTYPE omx = {0};
+ int s = fread(&omx, sizeof omx, 1, fp);
+ omx_buffer->nFilledLen = omx.nFilledLen;
+ omx_buffer->nFlags = omx.nFlags;
+ omx_buffer->nTimeStamp = omx.nTimeStamp;
+ if (s==1)
+ fread(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp);
+#else
+ if (fwrite(omx_buffer, sizeof *omx_buffer, 1, fp) == 1)
+ fwrite(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp);
+#endif
+ }
+}
+
COMXVideo::COMXVideo() : m_video_codec_name("")
{
m_is_open = false;
@@ -118,6 +161,7 @@ bool COMXVideo::SendDecoderConfig()
memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen);
omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
{
@@ -707,6 +751,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de
void COMXVideo::Close()
{
CSingleLock lock (m_critSection);
+ dump_omx_buffer(NULL);
m_omx_tunnel_clock.Deestablish();
m_omx_tunnel_decoder.Deestablish();
if(m_deinterlace)
@@ -801,6 +846,7 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double pts)
int nRetry = 0;
while(true)
{
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err == OMX_ErrorNone)
{
@@ -931,6 +977,7 @@ void COMXVideo::SubmitEOS()
omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN;
+ dump_omx_buffer(omx_buffer);
omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
if (omx_err != OMX_ErrorNone)
{
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 413c55a..0c84e99 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -1392,6 +1392,10 @@ void CAdvancedSettings::SettingOptionsLoggingComponentsFiller(const CSetting *se
#ifdef TARGET_RASPBERRY_PI
list.push_back(std::make_pair(g_localizeStrings.Get(697), LOGOMXPLAYER));
#endif
+#ifdef TARGET_RASPBERRY_PI
+ list.push_back(std::make_pair(g_localizeStrings.Get(698), LOGDUMPVIDEO));
+ list.push_back(std::make_pair(g_localizeStrings.Get(699), LOGDUMPAUDIO));
+#endif
}
void CAdvancedSettings::setExtraLogLevel(const std::vector<CVariant> &components)
From 73b1c2d5ff0942e1f873d8a219560955bae83fbb Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 30 Sep 2014 20:52:13 +0100
Subject: [PATCH 87/99] Revert "hack: revert squash: don't update originaldts
when marked as invalid"
This reverts commit 001dbfdefe45a3883e6f7d59525462e97bade4ee.
---
xbmc/cores/dvdplayer/DVDPlayer.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 6a9707b7..90dd142 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -2108,7 +2108,6 @@ void CDVDPlayer::CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket)
// not sure yet - flags the packets as unknown until we get confirmation on another audio/video packet
pPacket->dts = DVD_NOPTS_VALUE;
pPacket->pts = DVD_NOPTS_VALUE;
- current.originaldts = pPacket->dts;
}
}
else
From 87bb444eb6b641078daee9ce43cc7a97d9b0111c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 1 Oct 2014 16:34:51 +0100
Subject: [PATCH 88/99] [mmalcodec] squash: Avoid preroll when using trickplay
---
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.cpp | 5 +++++
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.h | 1 +
xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 12 +++++++++++-
xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h | 2 ++
4 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.cpp
index 55b9969..262283d 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.cpp
@@ -96,4 +96,9 @@ bool CDVDVideoCodecMMAL::GetCodecStats(double &pts, int &droppedPics)
return m_decoder->GetCodecStats(pts, droppedPics);
}
+void CDVDVideoCodecMMAL::SetSpeed(int iSpeed)
+{
+ m_decoder->SetSpeed(iSpeed);
+}
+
#endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.h
index 67aa505..a768e70 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecMMAL.h
@@ -42,6 +42,7 @@ class CDVDVideoCodecMMAL : public CDVDVideoCodec
virtual void SetDropState(bool bDrop);
virtual const char* GetName(void);
virtual bool GetCodecStats(double &pts, int &droppedPics);
+ virtual void SetSpeed(int iSpeed);
protected:
MMALVideoPtr m_decoder;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index c9aa390..cee1499 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -137,6 +137,7 @@ CMMALVideo::CMMALVideo()
m_demux_queue_length = 0;
m_es_format = mmal_format_alloc();
m_preroll = true;
+ m_speed = DVD_PLAYSPEED_NORMAL;
}
CMMALVideo::~CMMALVideo()
@@ -701,6 +702,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, MMALVide
m_drop_state = false;
m_startframe = false;
m_preroll = !m_hints.stills;
+ m_speed = DVD_PLAYSPEED_NORMAL;
return true;
}
@@ -975,9 +977,17 @@ void CMMALVideo::Reset(void)
m_decoderPts = DVD_NOPTS_VALUE;
m_droppedPics = 0;
m_decode_frame_number = 1;
- m_preroll = !m_hints.stills;
+ m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE);
}
+void CMMALVideo::SetSpeed(int iSpeed)
+{
+#if defined(MMAL_DEBUG_VERBOSE)
+ CLog::Log(LOGDEBUG, "%s::%s %d->%d", CLASSNAME, __func__, m_speed, iSpeed);
+#endif
+
+ m_speed = iSpeed;
+}
void CMMALVideo::ReturnBuffer(CMMALVideoBuffer *buffer)
{
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
index a2da46b..4f81bbd 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
@@ -90,6 +90,7 @@ class CMMALVideo
virtual void SetDropState(bool bDrop);
virtual const char* GetName(void) { return (const char*)m_pFormatName; }
virtual bool GetCodecStats(double &pts, int &droppedPics);
+ virtual void SetSpeed(int iSpeed);
// MMAL decoder callback routines.
void ReleaseBuffer(CMMALVideoBuffer *buffer);
@@ -140,6 +141,7 @@ class CMMALVideo
unsigned int m_decode_frame_number;
double m_decoderPts;
unsigned int m_droppedPics;
+ int m_speed;
bool m_preroll;
MMAL_COMPONENT_T *m_dec;
From 53f4c6a2d2f39fbecd30316cdb3f99626a1b9f5c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 1 Oct 2014 22:44:22 +0100
Subject: [PATCH 90/99] [dvdplayer] Remove omx render features from dvdplayer
and handle in mmalrenderer
---
xbmc/cores/VideoRenderers/MMALRenderer.cpp | 48 ------------------------------
xbmc/cores/VideoRenderers/MMALRenderer.h | 5 ----
xbmc/cores/dvdplayer/DVDPlayer.cpp | 29 ------------------
xbmc/cores/dvdplayer/DVDPlayer.h | 6 ----
4 files changed, 88 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 692379c..5fb6dce 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -190,25 +190,6 @@ bool CMMALRenderer::Configure(unsigned int width, unsigned int height, unsigned
m_RenderUpdateCallBackFn = NULL;
m_RenderUpdateCallBackCtx = NULL;
- if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
- {
- m_renderFeatures.clear();
- m_scalingMethods.clear();
- m_deinterlaceModes.clear();
- m_deinterlaceMethods.clear();
-
- if (m_RenderFeaturesCallBackFn)
- {
- (*m_RenderFeaturesCallBackFn)(m_RenderFeaturesCallBackCtx, m_renderFeatures);
- // after setting up m_renderFeatures, we are done with the callback
- m_RenderFeaturesCallBackFn = NULL;
- m_RenderFeaturesCallBackCtx = NULL;
- }
- g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures);
- g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
- g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
- g_application.m_pPlayer->GetScalingMethods(m_scalingMethods);
- }
// calculate the input frame aspect ratio
CalculateFrameAspectRatio(d_width, d_height);
@@ -480,8 +461,6 @@ void CMMALRenderer::UnInit()
m_RenderUpdateCallBackFn = NULL;
m_RenderUpdateCallBackCtx = NULL;
- m_RenderFeaturesCallBackFn = NULL;
- m_RenderFeaturesCallBackCtx = NULL;
m_src_rect.SetRect(0, 0, 0, 0);
m_dst_rect.SetRect(0, 0, 0, 0);
@@ -511,13 +490,6 @@ bool CMMALRenderer::RenderCapture(CRenderCapture* capture)
bool CMMALRenderer::Supports(EDEINTERLACEMODE mode)
{
- // Player controls render, let it dictate available deinterlace modes
- if (m_format == RENDER_FMT_BYPASS)
- {
- Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode);
- return itr != m_deinterlaceModes.end();
- }
-
if(mode == VS_DEINTERLACEMODE_OFF
|| mode == VS_DEINTERLACEMODE_AUTO
|| mode == VS_DEINTERLACEMODE_FORCE)
@@ -528,13 +500,6 @@ bool CMMALRenderer::Supports(EDEINTERLACEMODE mode)
bool CMMALRenderer::Supports(EINTERLACEMETHOD method)
{
- // Player controls render, let it dictate available deinterlace methods
- if (m_format == RENDER_FMT_BYPASS)
- {
- Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method);
- return itr != m_deinterlaceMethods.end();
- }
-
if (method == VS_INTERLACEMETHOD_DEINTERLACE)
return true;
@@ -543,13 +508,6 @@ bool CMMALRenderer::Supports(EINTERLACEMETHOD method)
bool CMMALRenderer::Supports(ERENDERFEATURE feature)
{
- // Player controls render, let it dictate available render features
- if (m_format == RENDER_FMT_BYPASS)
- {
- Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature);
- return itr != m_renderFeatures.end();
- }
-
if (feature == RENDERFEATURE_STRETCH ||
feature == RENDERFEATURE_ZOOM ||
feature == RENDERFEATURE_ROTATION ||
@@ -562,12 +520,6 @@ bool CMMALRenderer::Supports(ERENDERFEATURE feature)
bool CMMALRenderer::Supports(ESCALINGMETHOD method)
{
- // Player controls render, let it dictate available scaling methods
- if (m_format == RENDER_FMT_BYPASS)
- {
- Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method);
- return itr != m_scalingMethods.end();
- }
return false;
}
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h
index 3488ce0..8ca0b94 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.h
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.h
@@ -104,11 +104,6 @@ class CMMALRenderer : public CBaseRenderer, public CThread
unsigned int m_destHeight;
int m_neededBuffers;
- Features m_renderFeatures;
- Features m_deinterlaceMethods;
- Features m_deinterlaceModes;
- Features m_scalingMethods;
-
CRect m_src_rect;
CRect m_dst_rect;
RENDER_STEREO_MODE m_video_stereo_mode;
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 90dd142..22e27ea 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -4497,32 +4497,3 @@ bool CDVDPlayer::CachePVRStream(void) const
!g_PVRManager.IsPlayingRecording() &&
g_advancedSettings.m_bPVRCacheInDvdPlayer;
}
-
-void CDVDPlayer::OMXGetRenderFeatures(std::vector<int> &renderFeatures)
-{
- if (m_omxplayer_mode)
- {
- renderFeatures.push_back(RENDERFEATURE_STRETCH);
- renderFeatures.push_back(RENDERFEATURE_CROP);
- renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
- renderFeatures.push_back(RENDERFEATURE_ZOOM);
- }
-}
-
-void CDVDPlayer::OMXGetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
-{
- if (m_omxplayer_mode)
- {
- deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
- }
-}
-
-void CDVDPlayer::OMXGetDeinterlaceModes(std::vector<int> &deinterlaceModes)
-{
- if (m_omxplayer_mode)
- {
- deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
- deinterlaceModes.push_back(VS_DEINTERLACEMODE_OFF);
- deinterlaceModes.push_back(VS_DEINTERLACEMODE_FORCE);
- }
-}
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h
index 32f350b..dac00e9 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.h
+++ b/xbmc/cores/dvdplayer/DVDPlayer.h
@@ -286,12 +286,6 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
virtual int OnDVDNavResult(void* pData, int iMessage);
- // Note: the following "OMX" methods are deprecated and will be removed in the future
- // They should be handled by the video renderer, not the player
- virtual void OMXGetRenderFeatures(std::vector<int> &renderFeatures);
- virtual void OMXGetDeinterlaceMethods(std::vector<int> &deinterlaceMethods);
- virtual void OMXGetDeinterlaceModes(std::vector<int> &deinterlaceModes);
-
virtual bool ControlsVolume() {return m_omxplayer_mode;}
protected:
From b37024fd026e62b5357b4a663ef7af35ad175af5 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 1 Oct 2014 22:45:09 +0100
Subject: [PATCH 91/99] [mmalrenderer] Add choice of 3 deinterlace schemes
---
xbmc/cores/VideoRenderers/MMALRenderer.cpp | 4 ++++
xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 4 +++-
xbmc/cores/dvdplayer/DVDPlayer.cpp | 5 ++++-
xbmc/cores/dvdplayer/DVDPlayer.h | 1 +
xbmc/cores/omxplayer/OMXVideo.cpp | 11 ++++++++---
5 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 5fb6dce..9cb4d60 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -502,6 +502,10 @@ bool CMMALRenderer::Supports(EINTERLACEMETHOD method)
{
if (method == VS_INTERLACEMETHOD_DEINTERLACE)
return true;
+ if (method == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
+ return true;
+ if (method == VS_INTERLACEMETHOD_RENDER_BOB)
+ return true;
return false;
}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index cee1499..42c62db 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -366,7 +366,9 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method)
CLog::Log(LOGERROR, "%s::%s Failed to create deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
return false;
}
- MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)}, MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 1, {3}};
+ MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)},
+ interlace_method == VS_INTERLACEMETHOD_DEINTERLACE ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST,
+ 3, {3, 0, interlace_method == VS_INTERLACEMETHOD_DEINTERLACE_HALF }};
status = mmal_port_parameter_set(m_deint->output[0], &imfx_param.hdr);
if (status != MMAL_SUCCESS)
{
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 22e27ea..b335a83 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -618,6 +618,7 @@ CDVDPlayer::CDVDPlayer(IPlayerCallback& callback)
m_OmxPlayerState.bOmxSentEOFs = false;
m_OmxPlayerState.threshold = 0.2f;
m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
+ m_OmxPlayerState.interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
#ifdef HAS_OMXPLAYER
m_omxplayer_mode = CSettings::Get().GetBool("videoplayer.useomxplayer");
#else
@@ -1123,13 +1124,15 @@ void CDVDPlayer::OMXDoProcessing()
bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
// if deinterlace setting has changed, we should close and open video
- if (m_OmxPlayerState.current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode)
+ if (m_OmxPlayerState.current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
+ m_OmxPlayerState.interlace_method != g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod))
{
CloseStream(m_CurrentVideo, false);
OpenStream(m_CurrentVideo, m_CurrentVideo.id, m_CurrentVideo.source);
if (m_State.canseek)
m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true));
m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
+ m_OmxPlayerState.interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
}
m_OmxPlayerState.video_fifo = (int)(100.0*(m_dvdPlayerVideo->GetDecoderBufferSize()-m_dvdPlayerVideo->GetDecoderFreeSpace())/m_dvdPlayerVideo->GetDecoderBufferSize());
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h
index dac00e9..88f5cf8 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.h
+++ b/xbmc/cores/dvdplayer/DVDPlayer.h
@@ -541,6 +541,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
{
OMXClock av_clock; // openmax clock component
EDEINTERLACEMODE current_deinterlace; // whether deinterlace is currently enabled
+ EINTERLACEMETHOD interlace_method; // current deinterlace method
bool bOmxWaitVideo; // whether we need to wait for video to play out on EOS
bool bOmxWaitAudio; // whether we need to wait for audio to play out on EOS
bool bOmxSentEOFs; // flag if we've send EOFs to audio/video players
diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index 6cfb148..37765b1 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -30,6 +30,8 @@
#include "linux/XMemUtils.h"
#include "DVDDemuxers/DVDDemuxUtils.h"
#include "settings/AdvancedSettings.h"
+#include "settings/MediaSettings.h"
+#include "cores/VideoRenderers/RenderManager.h"
#include "xbmc/guilib/GraphicContext.h"
#include "settings/Settings.h"
#include "utils/BitstreamConverter.h"
@@ -298,8 +300,9 @@ bool COMXVideo::PortSettingsChanged()
if(m_deinterlace)
{
- bool advanced_deinterlace = port_image.format.video.nFrameWidth * port_image.format.video.nFrameHeight <= 576 * 720;
-
+ EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
+ bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_DEINTERLACE && port_image.format.video.nFrameWidth * port_image.format.video.nFrameHeight <= 576 * 720;
+ bool half_framerate = interlace_method == VS_INTERLACEMETHOD_DEINTERLACE_HALF;
if (!advanced_deinterlace)
{
// Image_fx assumed 3 frames of context. simple deinterlace doesn't require this
@@ -319,8 +322,10 @@ bool COMXVideo::PortSettingsChanged()
OMX_INIT_STRUCTURE(image_filter);
image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
- image_filter.nNumParams = 1;
+ image_filter.nNumParams = 3;
image_filter.nParams[0] = 3;
+ image_filter.nParams[1] = 0;
+ image_filter.nParams[2] = half_framerate;
if (!advanced_deinterlace)
image_filter.eImageFilter = OMX_ImageFilterDeInterlaceFast;
else
From 268ea34172c14df4daaab4f4533f6a45eef5c9d6 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 3 Oct 2014 17:50:28 +0100
Subject: [PATCH 93/99] [AE] Add factory for AEResampler
---
xbmc/cores/AudioEngine/AEResampleFactory.cpp | 149 ++++++++
xbmc/cores/AudioEngine/AEResampleFactory.h | 43 +++
.../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 6 +-
xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h | 2 +-
.../Engines/ActiveAE/ActiveAEBuffer.cpp | 25 +-
.../AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h | 4 +-
.../Engines/ActiveAE/ActiveAEResample.cpp | 388 ---------------------
.../Engines/ActiveAE/ActiveAEResample.h | 65 ----
.../Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp | 282 +++++++++++++++
.../Engines/ActiveAE/ActiveAEResampleFFMPEG.h | 62 ++++
.../AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 12 +-
.../AudioEngine/Engines/ActiveAE/ActiveAESink.h | 2 +-
.../AudioEngine/Engines/ActiveAE/ActiveAESound.h | 2 +-
.../Engines/ActiveAE/ActiveAEStream.cpp | 15 +-
.../AudioEngine/Engines/ActiveAE/ActiveAEStream.h | 2 +-
xbmc/cores/AudioEngine/Interfaces/AEResample.h | 53 +++
xbmc/cores/AudioEngine/Makefile.in | 4 +-
xbmc/cores/paplayer/DVDPlayerCodec.cpp | 12 +-
xbmc/cores/paplayer/DVDPlayerCodec.h | 4 +-
19 files changed, 637 insertions(+), 495 deletions(-)
create mode 100644 xbmc/cores/AudioEngine/AEResampleFactory.cpp
create mode 100644 xbmc/cores/AudioEngine/AEResampleFactory.h
delete mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
delete mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h
create mode 100644 xbmc/cores/AudioEngine/Interfaces/AEResample.h
diff --git a/xbmc/cores/AudioEngine/AEResampleFactory.cpp b/xbmc/cores/AudioEngine/AEResampleFactory.cpp
new file mode 100644
index 0000000..a0aef34
--- /dev/null
+++ b/xbmc/cores/AudioEngine/AEResampleFactory.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "AEResampleFactory.h"
+#include "Engines/ActiveAE/ActiveAEResampleFFMPEG.h"
+
+extern "C" {
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libswresample/swresample.h"
+}
+
+namespace ActiveAE
+{
+
+IAEResample *CAEResampleFactory::Create()
+{
+ return new CActiveAEResampleFFMPEG();
+}
+
+
+uint64_t CAEResampleFactory::GetAVChannelLayout(CAEChannelInfo &info)
+{
+ uint64_t channelLayout = 0;
+ if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT;
+ if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT;
+ if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER;
+ if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY;
+ if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT;
+ if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT;
+ if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
+ if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
+ if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER;
+ if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT;
+ if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT;
+ if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER;
+ if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT;
+ if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER;
+ if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT;
+ if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT;
+ if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER;
+ if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT;
+
+ return channelLayout;
+}
+
+//CAEChannelInfo CActiveAEResampleFFMPEG::GetAEChannelLayout(uint64_t layout)
+//{
+// CAEChannelInfo channelLayout;
+// channelLayout.Reset();
+//
+// if (layout & AV_CH_FRONT_LEFT ) channelLayout += AE_CH_FL ;
+// if (layout & AV_CH_FRONT_RIGHT ) channelLayout += AE_CH_FR ;
+// if (layout & AV_CH_FRONT_CENTER ) channelLayout += AE_CH_FC ;
+// if (layout & AV_CH_LOW_FREQUENCY ) channelLayout += AE_CH_LFE ;
+// if (layout & AV_CH_BACK_LEFT ) channelLayout += AE_CH_BL ;
+// if (layout & AV_CH_BACK_RIGHT ) channelLayout += AE_CH_BR ;
+// if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelLayout += AE_CH_FLOC;
+// if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelLayout += AE_CH_FROC;
+// if (layout & AV_CH_BACK_CENTER ) channelLayout += AE_CH_BC ;
+// if (layout & AV_CH_SIDE_LEFT ) channelLayout += AE_CH_SL ;
+// if (layout & AV_CH_SIDE_RIGHT ) channelLayout += AE_CH_SR ;
+// if (layout & AV_CH_TOP_CENTER ) channelLayout += AE_CH_TC ;
+// if (layout & AV_CH_TOP_FRONT_LEFT ) channelLayout += AE_CH_TFL ;
+// if (layout & AV_CH_TOP_FRONT_CENTER ) channelLayout += AE_CH_TFC ;
+// if (layout & AV_CH_TOP_FRONT_RIGHT ) channelLayout += AE_CH_TFR ;
+// if (layout & AV_CH_TOP_BACK_LEFT ) channelLayout += AE_CH_BL ;
+// if (layout & AV_CH_TOP_BACK_CENTER ) channelLayout += AE_CH_BC ;
+// if (layout & AV_CH_TOP_BACK_RIGHT ) channelLayout += AE_CH_BR ;
+//
+// return channelLayout;
+//}
+
+AVSampleFormat CAEResampleFactory::GetAVSampleFormat(AEDataFormat format)
+{
+ if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8;
+ else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16;
+ else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_S24NE3) return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT;
+ else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
+
+ else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P;
+ else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P;
+ else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_S24NE4MSBP)return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_S24NE3P) return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP;
+ else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
+
+ if (AE_IS_PLANAR(format))
+ return AV_SAMPLE_FMT_FLTP;
+ else
+ return AV_SAMPLE_FMT_FLT;
+}
+
+uint64_t CAEResampleFactory::GetAVChannel(enum AEChannel aechannel)
+{
+ switch (aechannel)
+ {
+ case AE_CH_FL: return AV_CH_FRONT_LEFT;
+ case AE_CH_FR: return AV_CH_FRONT_RIGHT;
+ case AE_CH_FC: return AV_CH_FRONT_CENTER;
+ case AE_CH_LFE: return AV_CH_LOW_FREQUENCY;
+ case AE_CH_BL: return AV_CH_BACK_LEFT;
+ case AE_CH_BR: return AV_CH_BACK_RIGHT;
+ case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER;
+ case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER;
+ case AE_CH_BC: return AV_CH_BACK_CENTER;
+ case AE_CH_SL: return AV_CH_SIDE_LEFT;
+ case AE_CH_SR: return AV_CH_SIDE_RIGHT;
+ case AE_CH_TC: return AV_CH_TOP_CENTER;
+ case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT;
+ case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER;
+ case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT;
+ case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT;
+ case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER;
+ case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT;
+ default:
+ return 0;
+ }
+}
+
+int CAEResampleFactory::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout)
+{
+ return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
+}
+
+}
diff --git a/xbmc/cores/AudioEngine/AEResampleFactory.h b/xbmc/cores/AudioEngine/AEResampleFactory.h
new file mode 100644
index 0000000..21f1803
--- /dev/null
+++ b/xbmc/cores/AudioEngine/AEResampleFactory.h
@@ -0,0 +1,43 @@
+#pragma once
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "cores/AudioEngine/Interfaces/AEResample.h"
+
+class IAEResample;
+
+namespace ActiveAE
+{
+
+class CAEResampleFactory
+{
+public:
+ static IAEResample *Create();
+ static uint64_t GetAVChannelLayout(CAEChannelInfo &info);
+ static AVSampleFormat GetAVSampleFormat(AEDataFormat format);
+ static uint64_t GetAVChannel(enum AEChannel aechannel);
+ static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout);
+};
+
+}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
index c825b4b..72cd8ce 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
@@ -2676,14 +2676,14 @@ bool CActiveAE::ResampleSound(CActiveAESound *sound)
orig_config = sound->GetSound(true)->config;
- dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
+ dst_config.channel_layout = CAEResampleFactory::GetAVChannelLayout(m_internalFormat.m_channelLayout);
dst_config.channels = m_internalFormat.m_channelLayout.Count();
dst_config.sample_rate = m_internalFormat.m_sampleRate;
- dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
+ dst_config.fmt = CAEResampleFactory::GetAVSampleFormat(m_internalFormat.m_dataFormat);
dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
dst_config.dither_bits = CAEUtil::DataFormatToDitherBits(m_internalFormat.m_dataFormat);
- CActiveAEResample *resampler = new CActiveAEResample();
+ IAEResample *resampler = CAEResampleFactory::Create();
resampler->Init(dst_config.channel_layout,
dst_config.channels,
dst_config.sample_rate,
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
index de94850..9ae3c40 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
@@ -23,7 +23,7 @@
#include "threads/Thread.h"
#include "ActiveAESink.h"
-#include "ActiveAEResample.h"
+#include "cores/AudioEngine/Interfaces/AEResample.h"
#include "cores/AudioEngine/Interfaces/AEStream.h"
#include "cores/AudioEngine/Interfaces/AESound.h"
#include "cores/AudioEngine/AEFactory.h"
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp
index 9e834c6..4e4ec92 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp
@@ -22,6 +22,7 @@
#include "cores/AudioEngine/AEFactory.h"
#include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
using namespace ActiveAE;
@@ -107,12 +108,12 @@ bool CActiveAEBufferPool::Create(unsigned int totaltime)
{
CSampleBuffer *buffer;
SampleConfig config;
- config.fmt = CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat);
+ config.fmt = CAEResampleFactory::GetAVSampleFormat(m_format.m_dataFormat);
config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat);
config.dither_bits = CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat);
config.channels = m_format.m_channelLayout.Count();
config.sample_rate = m_format.m_sampleRate;
- config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
+ config.channel_layout = CAEResampleFactory::GetAVChannelLayout(m_format.m_channelLayout);
unsigned int time = 0;
unsigned int buffertime = (m_format.m_frames*1000) / m_format.m_sampleRate;
@@ -171,17 +172,17 @@ bool CActiveAEBufferPoolResample::Create(unsigned int totaltime, bool remap, boo
m_inputFormat.m_dataFormat != m_format.m_dataFormat ||
m_changeResampler)
{
- m_resampler = new CActiveAEResample();
- m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout),
+ m_resampler = CAEResampleFactory::Create();
+ m_resampler->Init(CAEResampleFactory::GetAVChannelLayout(m_format.m_channelLayout),
m_format.m_channelLayout.Count(),
m_format.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
- CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
+ CAEResampleFactory::GetAVChannelLayout(m_inputFormat.m_channelLayout),
m_inputFormat.m_channelLayout.Count(),
m_inputFormat.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_inputFormat.m_dataFormat),
upmix,
@@ -199,17 +200,17 @@ void CActiveAEBufferPoolResample::ChangeResampler()
{
delete m_resampler;
- m_resampler = new CActiveAEResample();
- m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout),
+ m_resampler = CAEResampleFactory::Create();
+ m_resampler->Init(CAEResampleFactory::GetAVChannelLayout(m_format.m_channelLayout),
m_format.m_channelLayout.Count(),
m_format.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
- CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
+ CAEResampleFactory::GetAVChannelLayout(m_inputFormat.m_channelLayout),
m_inputFormat.m_channelLayout.Count(),
m_inputFormat.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_inputFormat.m_dataFormat),
m_stereoUpmix,
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h
index b0912be..961db98 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h
@@ -89,7 +89,7 @@ class CActiveAEBufferPool
std::deque<CSampleBuffer*> m_freeSamples;
};
-class CActiveAEResample;
+class IAEResample;
class CActiveAEBufferPoolResample : public CActiveAEBufferPool
{
@@ -105,7 +105,7 @@ class CActiveAEBufferPoolResample : public CActiveAEBufferPool
std::deque<CSampleBuffer*> m_inputSamples;
std::deque<CSampleBuffer*> m_outputSamples;
CSampleBuffer *m_procSample;
- CActiveAEResample *m_resampler;
+ IAEResample *m_resampler;
uint8_t *m_planes[16];
bool m_fillPackets;
bool m_drain;
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
deleted file mode 100644
index d7e0e0f..0000000
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Team XBMC
- * http://xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "ActiveAEResample.h"
-#include "utils/log.h"
-
-extern "C" {
-#include "libavutil/channel_layout.h"
-#include "libavutil/opt.h"
-#include "libswresample/swresample.h"
-}
-
-using namespace ActiveAE;
-
-CActiveAEResample::CActiveAEResample()
-{
- m_pContext = NULL;
- m_loaded = true;
-}
-
-CActiveAEResample::~CActiveAEResample()
-{
- if (m_pContext)
- swr_free(&m_pContext);
-}
-
-bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
-{
- if (!m_loaded)
- return false;
-
- m_dst_chan_layout = dst_chan_layout;
- m_dst_channels = dst_channels;
- m_dst_rate = dst_rate;
- m_dst_fmt = dst_fmt;
- m_dst_bits = dst_bits;
- m_dst_dither_bits = dst_dither;
- m_src_chan_layout = src_chan_layout;
- m_src_channels = src_channels;
- m_src_rate = src_rate;
- m_src_fmt = src_fmt;
- m_src_bits = src_bits;
- m_src_dither_bits = src_dither;
-
- if (m_dst_chan_layout == 0)
- m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels);
- if (m_src_chan_layout == 0)
- m_src_chan_layout = av_get_default_channel_layout(m_src_channels);
-
- m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate,
- m_src_chan_layout, m_src_fmt, m_src_rate,
- 0, NULL);
-
- if(!m_pContext)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed");
- return false;
- }
-
- if(quality == AE_QUALITY_HIGH)
- {
- av_opt_set_double(m_pContext, "cutoff", 1.0, 0);
- av_opt_set_int(m_pContext,"filter_size", 256, 0);
- }
- else if(quality == AE_QUALITY_MID)
- {
- // 0.97 is default cutoff so use (1.0 - 0.97) / 2.0 + 0.97
- av_opt_set_double(m_pContext, "cutoff", 0.985, 0);
- av_opt_set_int(m_pContext,"filter_size", 64, 0);
- }
- else if(quality == AE_QUALITY_LOW)
- {
- av_opt_set_double(m_pContext, "cutoff", 0.97, 0);
- av_opt_set_int(m_pContext,"filter_size", 32, 0);
- }
-
- if (m_dst_fmt == AV_SAMPLE_FMT_S32 || m_dst_fmt == AV_SAMPLE_FMT_S32P)
- {
- av_opt_set_int(m_pContext, "output_sample_bits", m_dst_bits, 0);
- }
-
- // tell resampler to clamp float values
- // not required for sink stage (remapLayout == true)
- if ((m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP) &&
- (m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP) &&
- !remapLayout && normalize)
- {
- av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
- }
-
- if (remapLayout)
- {
- // one-to-one mapping of channels
- // remapLayout is the layout of the sink, if the channel is in our src layout
- // the channel is mapped by setting coef 1.0
- memset(m_rematrix, 0, sizeof(m_rematrix));
- m_dst_chan_layout = 0;
- for (unsigned int out=0; out<remapLayout->Count(); out++)
- {
- m_dst_chan_layout += (uint64_t) (1 << out);
- int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout);
- if (idx >= 0)
- {
- m_rematrix[out][idx] = 1.0;
- }
- }
-
- av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0);
- av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0);
-
- if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
- return false;
- }
- }
- // stereo upmix
- else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
- {
- memset(m_rematrix, 0, sizeof(m_rematrix));
- for (int out=0; out<m_dst_channels; out++)
- {
- uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
- switch(out_chan)
- {
- case AV_CH_FRONT_LEFT:
- case AV_CH_BACK_LEFT:
- case AV_CH_SIDE_LEFT:
- m_rematrix[out][0] = 1.0;
- break;
- case AV_CH_FRONT_RIGHT:
- case AV_CH_BACK_RIGHT:
- case AV_CH_SIDE_RIGHT:
- m_rematrix[out][1] = 1.0;
- break;
- case AV_CH_FRONT_CENTER:
- m_rematrix[out][0] = 0.5;
- m_rematrix[out][1] = 0.5;
- break;
- case AV_CH_LOW_FREQUENCY:
- m_rematrix[out][0] = 0.5;
- m_rematrix[out][1] = 0.5;
- break;
- default:
- break;
- }
- }
-
- if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
- return false;
- }
- }
-
- if(swr_init(m_pContext) < 0)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Init - init resampler failed");
- return false;
- }
- return true;
-}
-
-int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio)
-{
- if (ratio != 1.0)
- {
- if (swr_set_compensation(m_pContext,
- (dst_samples*ratio-dst_samples)*m_dst_rate/m_src_rate,
- dst_samples*m_dst_rate/m_src_rate) < 0)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Resample - set compensation failed");
- return 0;
- }
- }
-
- int ret = swr_convert(m_pContext, dst_buffer, dst_samples, (const uint8_t**)src_buffer, src_samples);
- if (ret < 0)
- {
- CLog::Log(LOGERROR, "CActiveAEResample::Resample - resample failed");
- return 0;
- }
-
- // special handling for S24 formats which are carried in S32
- if (m_dst_fmt == AV_SAMPLE_FMT_S32 || m_dst_fmt == AV_SAMPLE_FMT_S32P)
- {
- // S24NE3
- if (m_dst_bits == 24 && m_dst_dither_bits == -8)
- {
- int planes = av_sample_fmt_is_planar(m_dst_fmt) ? m_dst_channels : 1;
- int samples = ret * m_dst_channels / planes;
- uint8_t *src, *dst;
- for (int i=0; i<planes; i++)
- {
- src = dst = dst_buffer[i];
- for (int j=0; j<samples; j++)
- {
-#ifndef WORDS_BIGENDIAN
- src++;
-#endif
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = *src++;
-#ifdef WORDS_BIGENDIAN
- src++;
-#endif
- }
- }
- }
- // shift bits if destination format requires it, swr_resamples aligns to the left
- // Example:
- // ALSA uses SNE24NE that means 24 bit load in 32 bit package and 0 dither bits
- // WASAPI uses SNE24NEMSB which is 24 bit load in 32 bit package and 8 dither bits
- // dither bits are always assumed from the right
- // FFmpeg internally calculates with S24NEMSB which means, that we need to shift the
- // data 8 bits to the right in order to get the correct alignment of 0 dither bits
- // if we want to use ALSA as output. For WASAPI nothing had to be done.
- // SNE24NEMSB 1 1 1 0 >> 8 = 0 1 1 1 = SNE24NE
- else if (m_dst_bits != 32 && (m_dst_dither_bits + m_dst_bits) != 32)
- {
- int planes = av_sample_fmt_is_planar(m_dst_fmt) ? m_dst_channels : 1;
- int samples = ret * m_dst_channels / planes;
- for (int i=0; i<planes; i++)
- {
- uint32_t* buf = (uint32_t*)dst_buffer[i];
- for (int j=0; j<samples; j++)
- {
- *buf = *buf >> (32 - m_dst_bits - m_dst_dither_bits);
- buf++;
- }
- }
- }
- }
- return ret;
-}
-
-int64_t CActiveAEResample::GetDelay(int64_t base)
-{
- return swr_get_delay(m_pContext, base);
-}
-
-int CActiveAEResample::GetBufferedSamples()
-{
- return av_rescale_rnd(swr_get_delay(m_pContext, m_src_rate),
- m_dst_rate, m_src_rate, AV_ROUND_UP);
-}
-
-int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate)
-{
- return av_rescale_rnd(src_samples, dst_rate, src_rate, AV_ROUND_UP);
-}
-
-int CActiveAEResample::GetSrcBufferSize(int samples)
-{
- return av_samples_get_buffer_size(NULL, m_src_channels, samples, m_src_fmt, 1);
-}
-
-int CActiveAEResample::GetDstBufferSize(int samples)
-{
- return av_samples_get_buffer_size(NULL, m_dst_channels, samples, m_dst_fmt, 1);
-}
-
-uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info)
-{
- uint64_t channelLayout = 0;
- if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT;
- if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT;
- if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER;
- if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY;
- if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT;
- if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT;
- if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
- if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
- if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER;
- if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT;
- if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT;
- if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER;
- if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT;
- if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER;
- if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT;
- if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT;
- if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER;
- if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT;
-
- return channelLayout;
-}
-
-//CAEChannelInfo CActiveAEResample::GetAEChannelLayout(uint64_t layout)
-//{
-// CAEChannelInfo channelLayout;
-// channelLayout.Reset();
-//
-// if (layout & AV_CH_FRONT_LEFT ) channelLayout += AE_CH_FL ;
-// if (layout & AV_CH_FRONT_RIGHT ) channelLayout += AE_CH_FR ;
-// if (layout & AV_CH_FRONT_CENTER ) channelLayout += AE_CH_FC ;
-// if (layout & AV_CH_LOW_FREQUENCY ) channelLayout += AE_CH_LFE ;
-// if (layout & AV_CH_BACK_LEFT ) channelLayout += AE_CH_BL ;
-// if (layout & AV_CH_BACK_RIGHT ) channelLayout += AE_CH_BR ;
-// if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelLayout += AE_CH_FLOC;
-// if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelLayout += AE_CH_FROC;
-// if (layout & AV_CH_BACK_CENTER ) channelLayout += AE_CH_BC ;
-// if (layout & AV_CH_SIDE_LEFT ) channelLayout += AE_CH_SL ;
-// if (layout & AV_CH_SIDE_RIGHT ) channelLayout += AE_CH_SR ;
-// if (layout & AV_CH_TOP_CENTER ) channelLayout += AE_CH_TC ;
-// if (layout & AV_CH_TOP_FRONT_LEFT ) channelLayout += AE_CH_TFL ;
-// if (layout & AV_CH_TOP_FRONT_CENTER ) channelLayout += AE_CH_TFC ;
-// if (layout & AV_CH_TOP_FRONT_RIGHT ) channelLayout += AE_CH_TFR ;
-// if (layout & AV_CH_TOP_BACK_LEFT ) channelLayout += AE_CH_BL ;
-// if (layout & AV_CH_TOP_BACK_CENTER ) channelLayout += AE_CH_BC ;
-// if (layout & AV_CH_TOP_BACK_RIGHT ) channelLayout += AE_CH_BR ;
-//
-// return channelLayout;
-//}
-
-AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format)
-{
- if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8;
- else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16;
- else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32;
- else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
- else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32;
- else if (format == AE_FMT_S24NE3) return AV_SAMPLE_FMT_S32;
- else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT;
- else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
-
- else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P;
- else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P;
- else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P;
- else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
- else if (format == AE_FMT_S24NE4MSBP)return AV_SAMPLE_FMT_S32P;
- else if (format == AE_FMT_S24NE3P) return AV_SAMPLE_FMT_S32P;
- else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP;
- else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
-
- if (AE_IS_PLANAR(format))
- return AV_SAMPLE_FMT_FLTP;
- else
- return AV_SAMPLE_FMT_FLT;
-}
-
-uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel)
-{
- switch (aechannel)
- {
- case AE_CH_FL: return AV_CH_FRONT_LEFT;
- case AE_CH_FR: return AV_CH_FRONT_RIGHT;
- case AE_CH_FC: return AV_CH_FRONT_CENTER;
- case AE_CH_LFE: return AV_CH_LOW_FREQUENCY;
- case AE_CH_BL: return AV_CH_BACK_LEFT;
- case AE_CH_BR: return AV_CH_BACK_RIGHT;
- case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER;
- case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER;
- case AE_CH_BC: return AV_CH_BACK_CENTER;
- case AE_CH_SL: return AV_CH_SIDE_LEFT;
- case AE_CH_SR: return AV_CH_SIDE_RIGHT;
- case AE_CH_TC: return AV_CH_TOP_CENTER;
- case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT;
- case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER;
- case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT;
- case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT;
- case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER;
- case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT;
- default:
- return 0;
- }
-}
-
-int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout)
-{
- return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
-}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
deleted file mode 100644
index a471e02..0000000
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2010-2013 Team XBMC
- * http://xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "cores/AudioEngine/Utils/AEChannelInfo.h"
-#include "cores/AudioEngine/Utils/AEAudioFormat.h"
-#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
-#include "cores/AudioEngine/Interfaces/AE.h"
-
-extern "C" {
-#include "libavutil/avutil.h"
-#include "libswresample/swresample.h"
-}
-
-namespace ActiveAE
-{
-
-class CActiveAEResample
-{
-public:
- CActiveAEResample();
- virtual ~CActiveAEResample();
- bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
- int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
- int64_t GetDelay(int64_t base);
- int GetBufferedSamples();
- int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate);
- int GetSrcBufferSize(int samples);
- int GetDstBufferSize(int samples);
- static uint64_t GetAVChannelLayout(CAEChannelInfo &info);
-// static CAEChannelInfo GetAEChannelLayout(uint64_t layout);
- static AVSampleFormat GetAVSampleFormat(AEDataFormat format);
- static uint64_t GetAVChannel(enum AEChannel aechannel);
- int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout);
-
-protected:
- bool m_loaded;
- uint64_t m_src_chan_layout, m_dst_chan_layout;
- int m_src_rate, m_dst_rate;
- int m_src_channels, m_dst_channels;
- AVSampleFormat m_src_fmt, m_dst_fmt;
- int m_src_bits, m_dst_bits;
- int m_src_dither_bits, m_dst_dither_bits;
- SwrContext *m_pContext;
- double m_rematrix[AE_CH_MAX][AE_CH_MAX];
-};
-
-}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
new file mode 100644
index 0000000..8107f44
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#include "ActiveAEResampleFFMPEG.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
+#include "settings/Settings.h"
+#include "utils/log.h"
+
+extern "C" {
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libswresample/swresample.h"
+}
+
+using namespace ActiveAE;
+
+CActiveAEResampleFFMPEG::CActiveAEResampleFFMPEG()
+{
+ m_pContext = NULL;
+ m_loaded = true;
+}
+
+CActiveAEResampleFFMPEG::~CActiveAEResampleFFMPEG()
+{
+ if (m_pContext)
+ swr_free(&m_pContext);
+}
+
+bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
+{
+ if (!m_loaded)
+ return false;
+
+ m_dst_chan_layout = dst_chan_layout;
+ m_dst_channels = dst_channels;
+ m_dst_rate = dst_rate;
+ m_dst_fmt = dst_fmt;
+ m_dst_bits = dst_bits;
+ m_dst_dither_bits = dst_dither;
+ m_src_chan_layout = src_chan_layout;
+ m_src_channels = src_channels;
+ m_src_rate = src_rate;
+ m_src_fmt = src_fmt;
+ m_src_bits = src_bits;
+ m_src_dither_bits = src_dither;
+
+ if (m_dst_chan_layout == 0)
+ m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels);
+ if (m_src_chan_layout == 0)
+ m_src_chan_layout = av_get_default_channel_layout(m_src_channels);
+
+ m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate,
+ m_src_chan_layout, m_src_fmt, m_src_rate,
+ 0, NULL);
+
+ if(!m_pContext)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed");
+ return false;
+ }
+
+ if(quality == AE_QUALITY_HIGH)
+ {
+ av_opt_set_double(m_pContext, "cutoff", 1.0, 0);
+ av_opt_set_int(m_pContext,"filter_size", 256, 0);
+ }
+ else if(quality == AE_QUALITY_MID)
+ {
+ // 0.97 is default cutoff so use (1.0 - 0.97) / 2.0 + 0.97
+ av_opt_set_double(m_pContext, "cutoff", 0.985, 0);
+ av_opt_set_int(m_pContext,"filter_size", 64, 0);
+ }
+ else if(quality == AE_QUALITY_LOW)
+ {
+ av_opt_set_double(m_pContext, "cutoff", 0.97, 0);
+ av_opt_set_int(m_pContext,"filter_size", 32, 0);
+ }
+
+ if (m_dst_fmt == AV_SAMPLE_FMT_S32 || m_dst_fmt == AV_SAMPLE_FMT_S32P)
+ {
+ av_opt_set_int(m_pContext, "output_sample_bits", m_dst_bits, 0);
+ }
+
+ // tell resampler to clamp float values
+ // not required for sink stage (remapLayout == true)
+ if ((m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP) &&
+ (m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP) &&
+ !remapLayout && normalize)
+ {
+ av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
+ }
+
+ if (remapLayout)
+ {
+ // one-to-one mapping of channels
+ // remapLayout is the layout of the sink, if the channel is in our src layout
+ // the channel is mapped by setting coef 1.0
+ memset(m_rematrix, 0, sizeof(m_rematrix));
+ m_dst_chan_layout = 0;
+ for (unsigned int out=0; out<remapLayout->Count(); out++)
+ {
+ m_dst_chan_layout += (uint64_t) (1 << out);
+ int idx = CAEResampleFactory::GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout);
+ if (idx >= 0)
+ {
+ m_rematrix[out][idx] = 1.0;
+ }
+ }
+
+ av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0);
+ av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0);
+
+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed");
+ return false;
+ }
+ }
+ // stereo upmix
+ else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
+ {
+ memset(m_rematrix, 0, sizeof(m_rematrix));
+ for (int out=0; out<m_dst_channels; out++)
+ {
+ uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
+ switch(out_chan)
+ {
+ case AV_CH_FRONT_LEFT:
+ case AV_CH_BACK_LEFT:
+ case AV_CH_SIDE_LEFT:
+ m_rematrix[out][0] = 1.0;
+ break;
+ case AV_CH_FRONT_RIGHT:
+ case AV_CH_BACK_RIGHT:
+ case AV_CH_SIDE_RIGHT:
+ m_rematrix[out][1] = 1.0;
+ break;
+ case AV_CH_FRONT_CENTER:
+ m_rematrix[out][0] = 0.5;
+ m_rematrix[out][1] = 0.5;
+ break;
+ case AV_CH_LOW_FREQUENCY:
+ m_rematrix[out][0] = 0.5;
+ m_rematrix[out][1] = 0.5;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed");
+ return false;
+ }
+ }
+
+ if(swr_init(m_pContext) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - init resampler failed");
+ return false;
+ }
+ return true;
+}
+
+int CActiveAEResampleFFMPEG::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio)
+{
+ if (ratio != 1.0)
+ {
+ if (swr_set_compensation(m_pContext,
+ (dst_samples*ratio-dst_samples)*m_dst_rate/m_src_rate,
+ dst_samples*m_dst_rate/m_src_rate) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Resample - set compensation failed");
+ return 0;
+ }
+ }
+
+ int ret = swr_convert(m_pContext, dst_buffer, dst_samples, (const uint8_t**)src_buffer, src_samples);
+ if (ret < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Resample - resample failed");
+ return 0;
+ }
+
+ // special handling for S24 formats which are carried in S32
+ if (m_dst_fmt == AV_SAMPLE_FMT_S32 || m_dst_fmt == AV_SAMPLE_FMT_S32P)
+ {
+ // S24NE3
+ if (m_dst_bits == 24 && m_dst_dither_bits == -8)
+ {
+ int planes = av_sample_fmt_is_planar(m_dst_fmt) ? m_dst_channels : 1;
+ int samples = ret * m_dst_channels / planes;
+ uint8_t *src, *dst;
+ for (int i=0; i<planes; i++)
+ {
+ src = dst = dst_buffer[i];
+ for (int j=0; j<samples; j++)
+ {
+#ifndef WORDS_BIGENDIAN
+ src++;
+#endif
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+#ifdef WORDS_BIGENDIAN
+ src++;
+#endif
+ }
+ }
+ }
+ // shift bits if destination format requires it, swr_resamples aligns to the left
+ // Example:
+ // ALSA uses SNE24NE that means 24 bit load in 32 bit package and 0 dither bits
+ // WASAPI uses SNE24NEMSB which is 24 bit load in 32 bit package and 8 dither bits
+ // dither bits are always assumed from the right
+ // FFmpeg internally calculates with S24NEMSB which means, that we need to shift the
+ // data 8 bits to the right in order to get the correct alignment of 0 dither bits
+ // if we want to use ALSA as output. For WASAPI nothing had to be done.
+ // SNE24NEMSB 1 1 1 0 >> 8 = 0 1 1 1 = SNE24NE
+ else if (m_dst_bits != 32 && (m_dst_dither_bits + m_dst_bits) != 32)
+ {
+ int planes = av_sample_fmt_is_planar(m_dst_fmt) ? m_dst_channels : 1;
+ int samples = ret * m_dst_channels / planes;
+ for (int i=0; i<planes; i++)
+ {
+ uint32_t* buf = (uint32_t*)dst_buffer[i];
+ for (int j=0; j<samples; j++)
+ {
+ *buf = *buf >> (32 - m_dst_bits - m_dst_dither_bits);
+ buf++;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+int64_t CActiveAEResampleFFMPEG::GetDelay(int64_t base)
+{
+ return swr_get_delay(m_pContext, base);
+}
+
+int CActiveAEResampleFFMPEG::GetBufferedSamples()
+{
+ return av_rescale_rnd(swr_get_delay(m_pContext, m_src_rate),
+ m_dst_rate, m_src_rate, AV_ROUND_UP);
+}
+
+int CActiveAEResampleFFMPEG::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate)
+{
+ return av_rescale_rnd(src_samples, dst_rate, src_rate, AV_ROUND_UP);
+}
+
+int CActiveAEResampleFFMPEG::GetSrcBufferSize(int samples)
+{
+ return av_samples_get_buffer_size(NULL, m_src_channels, samples, m_src_fmt, 1);
+}
+
+int CActiveAEResampleFFMPEG::GetDstBufferSize(int samples)
+{
+ return av_samples_get_buffer_size(NULL, m_dst_channels, samples, m_dst_fmt, 1);
+}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h
new file mode 100644
index 0000000..2f11c8e
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h
@@ -0,0 +1,62 @@
+#pragma once
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "cores/AudioEngine/Utils/AEChannelInfo.h"
+#include "cores/AudioEngine/Utils/AEAudioFormat.h"
+#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
+#include "cores/AudioEngine/Interfaces/AE.h"
+#include "cores/AudioEngine/Interfaces/AEResample.h"
+
+extern "C" {
+#include "libavutil/avutil.h"
+#include "libswresample/swresample.h"
+}
+
+namespace ActiveAE
+{
+
+class CActiveAEResampleFFMPEG : public IAEResample
+{
+public:
+ const char *GetName() { return "ActiveAEResampleFFMPEG"; }
+ CActiveAEResampleFFMPEG();
+ virtual ~CActiveAEResampleFFMPEG();
+ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
+ int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
+ int64_t GetDelay(int64_t base);
+ int GetBufferedSamples();
+ int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate);
+ int GetSrcBufferSize(int samples);
+ int GetDstBufferSize(int samples);
+
+protected:
+ bool m_loaded;
+ uint64_t m_src_chan_layout, m_dst_chan_layout;
+ int m_src_rate, m_dst_rate;
+ int m_src_channels, m_dst_channels;
+ AVSampleFormat m_src_fmt, m_dst_fmt;
+ int m_src_bits, m_dst_bits;
+ int m_src_dither_bits, m_dst_dither_bits;
+ SwrContext *m_pContext;
+ double m_rematrix[AE_CH_MAX][AE_CH_MAX];
+};
+
+}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
index d9f4a43..52e87a0 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
@@ -24,6 +24,7 @@
#include "cores/AudioEngine/Utils/AEUtil.h"
#include "utils/EndianSwap.h"
#include "ActiveAE.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
#include "settings/Settings.h"
@@ -754,10 +755,10 @@ void CActiveAESink::OpenSink()
// init sample of silence
SampleConfig config;
- config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
+ config.fmt = CAEResampleFactory::GetAVSampleFormat(m_sinkFormat.m_dataFormat);
config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat);
config.dither_bits = CAEUtil::DataFormatToDitherBits(m_sinkFormat.m_dataFormat);
- config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
+ config.channel_layout = CAEResampleFactory::GetAVChannelLayout(m_sinkFormat.m_channelLayout);
config.channels = m_sinkFormat.m_channelLayout.Count();
config.sample_rate = m_sinkFormat.m_sampleRate;
@@ -890,8 +891,8 @@ void CActiveAESink::GenerateNoise()
}
SampleConfig config = m_sampleOfSilence.pkt->config;
- CActiveAEResample resampler;
- resampler.Init(config.channel_layout,
+ IAEResample *resampler = CAEResampleFactory::Create();
+ resampler->Init(config.channel_layout,
config.channels,
config.sample_rate,
config.fmt,
@@ -904,10 +905,11 @@ void CActiveAESink::GenerateNoise()
CAEUtil::DataFormatToUsedBits(m_sinkFormat.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_sinkFormat.m_dataFormat),
false, false, NULL, AE_QUALITY_UNKNOWN);
- resampler.Resample(m_sampleOfSilence.pkt->data, m_sampleOfSilence.pkt->max_nb_samples,
+ resampler->Resample(m_sampleOfSilence.pkt->data, m_sampleOfSilence.pkt->max_nb_samples,
(uint8_t**)&noise, m_sampleOfSilence.pkt->max_nb_samples, 1.0);
_aligned_free(noise);
+ delete resampler;
#endif
}
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
index 0650a70..cf137b6 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
@@ -25,7 +25,7 @@
#include "cores/AudioEngine/Interfaces/AE.h"
#include "cores/AudioEngine/Interfaces/AESink.h"
#include "cores/AudioEngine/AESinkFactory.h"
-#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h"
+#include "cores/AudioEngine/Interfaces/AEResample.h"
namespace ActiveAE
{
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h
index 01aafe3..fbee6b2 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h
@@ -20,7 +20,7 @@
*/
#include "cores/AudioEngine/Interfaces/AESound.h"
-#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
#include "filesystem/File.h"
class DllAvUtil;
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
index 7acc0d0..09d430c 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
@@ -25,6 +25,7 @@
#include "cores/AudioEngine/AEFactory.h"
#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
#include "ActiveAE.h"
#include "ActiveAEStream.h"
@@ -94,7 +95,7 @@ void CActiveAEStream::InitRemapper()
for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
{
avLast = avCur;
- avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
+ avCur = CAEResampleFactory::GetAVChannel(m_format.m_channelLayout[i]);
if(avCur < avLast)
{
needRemap = true;
@@ -106,8 +107,8 @@ void CActiveAEStream::InitRemapper()
{
CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
- m_remapper = new CActiveAEResample();
- uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
+ m_remapper = CAEResampleFactory::Create();
+ uint64_t avLayout = CAEResampleFactory::GetAVChannelLayout(m_format.m_channelLayout);
// build layout according to ffmpeg channel order
// we need this for reference
@@ -118,7 +119,7 @@ void CActiveAEStream::InitRemapper()
{
for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
{
- idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
+ idx = CAEResampleFactory::GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
if (idx == (int)i)
{
ffmpegLayout += m_format.m_channelLayout[j];
@@ -134,7 +135,7 @@ void CActiveAEStream::InitRemapper()
{
for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
{
- idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
+ idx = CAEResampleFactory::GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
if (idx == (int)i)
{
remapLayout += ffmpegLayout[j];
@@ -147,13 +148,13 @@ void CActiveAEStream::InitRemapper()
m_remapper->Init(avLayout,
m_format.m_channelLayout.Count(),
m_format.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
avLayout,
m_format.m_channelLayout.Count(),
m_format.m_sampleRate,
- CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+ CAEResampleFactory::GetAVSampleFormat(m_format.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
CAEUtil::DataFormatToDitherBits(m_format.m_dataFormat),
false,
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h
index 70e8107..09fda0f 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h
@@ -98,7 +98,7 @@ class CActiveAEStream : public IAEStream
int m_leftoverBytes;
CSampleBuffer *m_currentBuffer;
CSoundPacket *m_remapBuffer;
- CActiveAEResample *m_remapper;
+ IAEResample *m_remapper;
int m_clockId;
// only accessed by engine
diff --git a/xbmc/cores/AudioEngine/Interfaces/AEResample.h b/xbmc/cores/AudioEngine/Interfaces/AEResample.h
new file mode 100644
index 0000000..dbe39bf
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Interfaces/AEResample.h
@@ -0,0 +1,53 @@
+#pragma once
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#include "cores/AudioEngine/Utils/AEChannelInfo.h"
+#include "cores/AudioEngine/Utils/AEAudioFormat.h"
+#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
+#include "cores/AudioEngine/Interfaces/AE.h"
+
+extern "C" {
+#include "libavutil/avutil.h"
+#include "libswresample/swresample.h"
+}
+
+namespace ActiveAE
+{
+
+class IAEResample
+{
+public:
+ /* return the name of this sync for logging */
+ virtual const char *GetName() = 0;
+ IAEResample() {}
+ virtual ~IAEResample() {}
+ virtual bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality) = 0;
+ virtual int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio) = 0;
+ virtual int64_t GetDelay(int64_t base) = 0;
+ virtual int GetBufferedSamples() = 0;
+ virtual int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate) = 0;
+ virtual int GetSrcBufferSize(int samples) = 0;
+ virtual int GetDstBufferSize(int samples) = 0;
+};
+
+}
diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in
index 581249e..b58db3e 100644
--- a/xbmc/cores/AudioEngine/Makefile.in
+++ b/xbmc/cores/AudioEngine/Makefile.in
@@ -26,11 +26,13 @@ SRCS += Sinks/AESinkProfiler.cpp
SRCS += Sinks/AESinkPi.cpp
+SRCS += AEResampleFactory.cpp
+
SRCS += Engines/ActiveAE/ActiveAE.cpp
SRCS += Engines/ActiveAE/ActiveAESink.cpp
SRCS += Engines/ActiveAE/ActiveAEStream.cpp
SRCS += Engines/ActiveAE/ActiveAESound.cpp
-SRCS += Engines/ActiveAE/ActiveAEResample.cpp
+SRCS += Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp
ifeq (@USE_ANDROID@,1)
diff --git a/xbmc/cores/paplayer/DVDPlayerCodec.cpp b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
index c619b32..130d4f95 100644
--- a/xbmc/cores/paplayer/DVDPlayerCodec.cpp
+++ b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
@@ -20,7 +20,7 @@
#include "DVDPlayerCodec.h"
#include "cores/AudioEngine/Utils/AEUtil.h"
-#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
#include "cores/dvdplayer/DVDInputStreams/DVDFactoryInputStream.h"
#include "cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h"
@@ -234,17 +234,17 @@ bool DVDPlayerCodec::Init(const std::string &strFile, unsigned int filecache)
if (NeedConvert(m_DataFormat))
{
m_needConvert = true;
- m_pResampler = new ActiveAE::CActiveAEResample();
- m_pResampler->Init(ActiveAE::CActiveAEResample::GetAVChannelLayout(m_ChannelInfo),
+ m_pResampler = ActiveAE::CAEResampleFactory::Create();
+ m_pResampler->Init(ActiveAE::CAEResampleFactory::GetAVChannelLayout(m_ChannelInfo),
m_ChannelInfo.Count(),
m_SampleRate,
- ActiveAE::CActiveAEResample::GetAVSampleFormat(AE_FMT_FLOAT),
+ ActiveAE::CAEResampleFactory::GetAVSampleFormat(AE_FMT_FLOAT),
CAEUtil::DataFormatToUsedBits(AE_FMT_FLOAT),
CAEUtil::DataFormatToDitherBits(AE_FMT_FLOAT),
- ActiveAE::CActiveAEResample::GetAVChannelLayout(m_ChannelInfo),
+ ActiveAE::CAEResampleFactory::GetAVChannelLayout(m_ChannelInfo),
m_ChannelInfo.Count(),
m_SampleRate,
- ActiveAE::CActiveAEResample::GetAVSampleFormat(m_DataFormat),
+ ActiveAE::CAEResampleFactory::GetAVSampleFormat(m_DataFormat),
CAEUtil::DataFormatToUsedBits(m_DataFormat),
CAEUtil::DataFormatToDitherBits(m_DataFormat),
false,
diff --git a/xbmc/cores/paplayer/DVDPlayerCodec.h b/xbmc/cores/paplayer/DVDPlayerCodec.h
index 469e2ff..576fb97 100644
--- a/xbmc/cores/paplayer/DVDPlayerCodec.h
+++ b/xbmc/cores/paplayer/DVDPlayerCodec.h
@@ -29,7 +29,7 @@
namespace ActiveAE
{
- class CActiveAEResample;
+ class IAEResample;
};
class DVDPlayerCodec : public ICodec
@@ -71,7 +71,7 @@ class DVDPlayerCodec : public ICodec
bool m_bInited;
bool m_bCanSeek;
- ActiveAE::CActiveAEResample *m_pResampler;
+ ActiveAE::IAEResample *m_pResampler;
uint8_t *m_audioPlanes[8];
int m_planes;
bool m_needConvert;
From d574a64ad703984f46204bac05d05ce361415aed Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 30 Dec 2013 12:02:14 +0000
Subject: [PATCH 94/99] [rbp] Hardware accelerated resampling
This replaces the format conversion, up/down mixing and resampling code from ActiveAE with a GPU accelerated version.
Should significantly reduce CPU when using paplayer or dvdplayer.
Requires updated firmware
---
.../Engines/ActiveAE/ActiveAEResamplePi.cpp | 563 +++++++++++++++++++++
.../Engines/ActiveAE/ActiveAEResamplePi.h | 71 +++
xbmc/cores/AudioEngine/Makefile.in | 1 +
3 files changed, 635 insertions(+)
create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
new file mode 100644
index 0000000..77ed266
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#if defined(TARGET_RASPBERRY_PI)
+
+#include "ActiveAEResamplePi.h"
+#include "cores/AudioEngine/AEResampleFactory.h"
+#include "linux/RBP.h"
+#include "settings/Settings.h"
+#include "utils/log.h"
+
+extern "C" {
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libswresample/swresample.h"
+}
+
+//#define DEBUG_VERBOSE
+
+#define CLASSNAME "CActiveAEResamplePi"
+
+#define BUFFERSIZE (32*1024*2*8)
+
+//#define BENCHMARKING
+#ifdef BENCHMARKING
+#define LOGTIMEINIT(f) \
+ struct timespec now; \
+ uint64_t Start, End; \
+ clock_gettime(CLOCK_MONOTONIC, &now); \
+ Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
+ const char *_filename = f;
+
+#define LOGTIME(n) \
+ clock_gettime(CLOCK_MONOTONIC, &now); \
+ End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
+ CLog::Log(LOGNOTICE, "ActiveAE::%s %d - resample %s took %.0fms", __FUNCTION__, n, _filename, (End-Start)*1e-6); \
+ Start=End;
+#else
+#define LOGTIMEINIT(f)
+#define LOGTIME(n)
+#endif
+
+using namespace ActiveAE;
+
+CActiveAEResamplePi::CActiveAEResamplePi()
+{
+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
+
+ m_Initialized = false;
+ m_last_src_fmt = AV_SAMPLE_FMT_NONE;
+ m_last_dst_fmt = AV_SAMPLE_FMT_NONE;
+ m_last_src_channels = 0;
+ m_last_dst_channels = 0;
+ m_encoded_buffer = NULL;
+}
+
+CActiveAEResamplePi::~CActiveAEResamplePi()
+{
+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
+ DeInit();
+}
+
+void CActiveAEResamplePi::DeInit()
+{
+ CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
+ if (m_Initialized)
+ {
+ m_omx_mixer.FlushAll();
+ m_omx_mixer.Deinitialize();
+ m_Initialized = false;
+ }
+}
+
+static int format_to_bits(AVSampleFormat fmt)
+{
+ switch (fmt)
+ {
+ case AV_SAMPLE_FMT_U8:
+ case AV_SAMPLE_FMT_U8P:
+ return 8;
+ case AV_SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S16P:
+ return 16;
+ case AV_SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_S32P:
+ case AV_SAMPLE_FMT_FLT:
+ case AV_SAMPLE_FMT_FLTP:
+ return 32;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+bool CActiveAEResamplePi::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
+{
+ LOGTIMEINIT("x");
+
+ CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix);
+
+ // replace passed in number of bits with correct ones
+ src_bits = format_to_bits(src_fmt);
+ dst_bits = format_to_bits(dst_fmt);
+
+ m_dst_chan_layout = dst_chan_layout;
+ m_dst_channels = dst_channels;
+ m_dst_rate = dst_rate;
+ m_dst_fmt = dst_fmt;
+ m_dst_bits = dst_bits;
+ m_src_chan_layout = src_chan_layout;
+ m_src_channels = src_channels;
+ m_src_rate = src_rate;
+ m_src_fmt = src_fmt;
+ m_src_bits = src_bits;
+
+ if (m_dst_chan_layout == 0)
+ m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels);
+ if (m_src_chan_layout == 0)
+ m_src_chan_layout = av_get_default_channel_layout(m_src_channels);
+
+ OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix;
+ OMX_INIT_STRUCTURE(mix);
+
+ assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64);
+
+ LOGTIME(1);
+// this code is just uses ffmpeg to produce the 8x8 mixing matrix
+{
+ // dummy sample rate and format, as we only care about channel mapping
+ SwrContext *m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000,
+ m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL);
+ if (!m_pContext)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResamplePi::Init - create context failed");
+ return false;
+ }
+ // tell resampler to clamp float values
+ // not required for sink stage (remapLayout == true)
+ if (!remapLayout && normalize)
+ {
+ av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
+ }
+
+ if (remapLayout)
+ {
+ // one-to-one mapping of channels
+ // remapLayout is the layout of the sink, if the channel is in our src layout
+ // the channel is mapped by setting coef 1.0
+ double m_rematrix[AE_CH_MAX][AE_CH_MAX];
+ memset(m_rematrix, 0, sizeof(m_rematrix));
+ m_dst_chan_layout = 0;
+ for (unsigned int out=0; out<remapLayout->Count(); out++)
+ {
+ m_dst_chan_layout += (uint64_t) (1 << out);
+ int idx = CAEResampleFactory::GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout);
+ if (idx >= 0)
+ {
+ m_rematrix[out][idx] = 1.0;
+ }
+ }
+
+ av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0);
+ av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0);
+
+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResamplePi::Init - setting channel matrix failed");
+ return false;
+ }
+ }
+ // stereo upmix
+ else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
+ {
+ double m_rematrix[AE_CH_MAX][AE_CH_MAX];
+ memset(m_rematrix, 0, sizeof(m_rematrix));
+ for (int out=0; out<m_dst_channels; out++)
+ {
+ uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
+ switch(out_chan)
+ {
+ case AV_CH_FRONT_LEFT:
+ case AV_CH_BACK_LEFT:
+ case AV_CH_SIDE_LEFT:
+ m_rematrix[out][0] = 1.0;
+ break;
+ case AV_CH_FRONT_RIGHT:
+ case AV_CH_BACK_RIGHT:
+ case AV_CH_SIDE_RIGHT:
+ m_rematrix[out][1] = 1.0;
+ break;
+ case AV_CH_FRONT_CENTER:
+ m_rematrix[out][0] = 0.5;
+ m_rematrix[out][1] = 0.5;
+ break;
+ case AV_CH_LOW_FREQUENCY:
+ m_rematrix[out][0] = 0.5;
+ m_rematrix[out][1] = 0.5;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResamplePi::Init - setting channel matrix failed");
+ return false;
+ }
+ }
+
+ if (swr_init(m_pContext) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResamplePi::Init - init resampler failed");
+ return false;
+ }
+
+ const int samples = 8;
+ uint8_t *output, *input;
+ av_samples_alloc(&output, NULL, m_dst_channels, samples, AV_SAMPLE_FMT_FLT, 1);
+ av_samples_alloc(&input , NULL, m_src_channels, samples, AV_SAMPLE_FMT_FLT, 1);
+
+ // Produce "identity" samples
+ float *f = (float *)input;
+ for (int j=0; j < samples; j++)
+ for (int i=0; i < m_src_channels; i++)
+ *f++ = i == j ? 1.0f : 0.0f;
+
+ int ret = swr_convert(m_pContext, &output, samples, (const uint8_t **)&input, samples);
+ if (ret < 0)
+ CLog::Log(LOGERROR, "CActiveAEResamplePi::Resample - resample failed");
+
+ f = (float *)output;
+ for (int j=0; j < samples; j++)
+ for (int i=0; i < m_dst_channels; i++)
+ mix.coeff[8*i+j] = *f++ * (1<<16);
+
+ for (int j=0; j < 8; j++)
+ {
+ char s[128] = {}, *t=s;
+ for (int i=0; i < 8; i++)
+ t += sprintf(t, "% 6.2f ", mix.coeff[j*8+i] * (1.0/0x10000));
+ CLog::Log(LOGINFO, "%s::%s %s", CLASSNAME, __func__, s);
+ }
+ av_freep(&input);
+ av_freep(&output);
+ swr_free(&m_pContext);
+}
+ LOGTIME(2);
+
+ // This may be called before Application calls g_RBP.Initialise, so call it here too
+ g_RBP.Initialize();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if (!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit))
+ CLog::Log(LOGERROR, "%s::%s - m_omx_mixer.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(3);
+
+ // audio_mixer only supports up to 192kHz, however as long as ratio of samplerates remains the same we can lie
+ while (src_rate > 192000 || dst_rate > 192000)
+ src_rate >>= 1, dst_rate >>= 1;
+
+ OMX_INIT_STRUCTURE(m_pcm_input);
+ m_pcm_input.nPortIndex = m_omx_mixer.GetInputPort();
+ m_pcm_input.eNumData = OMX_NumericalDataSigned;
+ m_pcm_input.eEndian = OMX_EndianLittle;
+ m_pcm_input.bInterleaved = OMX_TRUE;
+ m_pcm_input.nBitPerSample = m_src_bits;
+ // 0x8000 = float, 0x10000 = planar
+ uint32_t flags = 0;
+ if (m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP)
+ flags |= 0x8000;
+ if (m_src_fmt >= AV_SAMPLE_FMT_U8P)
+ flags |= 0x10000;
+ m_pcm_input.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags;
+ m_pcm_input.nChannels = src_channels;
+ m_pcm_input.nSamplingRate = src_rate;
+
+ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer in SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ OMX_INIT_STRUCTURE(m_pcm_output);
+ m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort();
+ m_pcm_output.eNumData = OMX_NumericalDataSigned;
+ m_pcm_output.eEndian = OMX_EndianLittle;
+ m_pcm_output.bInterleaved = OMX_TRUE;
+ m_pcm_output.nBitPerSample = m_dst_bits;
+ flags = 0;
+ if (m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP)
+ flags |= 0x8000;
+ if (m_dst_fmt >= AV_SAMPLE_FMT_U8P)
+ flags |= 0x10000;
+ m_pcm_output.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags;
+ m_pcm_output.nChannels = dst_channels;
+ m_pcm_output.nSamplingRate = dst_rate;
+
+ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer out SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(4);
+
+ mix.nPortIndex = m_omx_mixer.GetInputPort();
+ omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
+ CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ // set up the number/size of buffers for decoder input
+ OMX_PARAM_PORTDEFINITIONTYPE port_param;
+ OMX_INIT_STRUCTURE(port_param);
+ port_param.nPortIndex = m_omx_mixer.GetInputPort();
+
+ omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
+ port_param.nBufferSize = BUFFERSIZE;
+
+ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(5);
+
+ omx_err = m_omx_mixer.AllocInputBuffers();
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(6);
+
+ // set up the number/size of buffers for decoder output
+ OMX_INIT_STRUCTURE(port_param);
+ port_param.nPortIndex = m_omx_mixer.GetOutputPort();
+
+ omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
+ port_param.nBufferSize = BUFFERSIZE;
+
+ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(7);
+
+ omx_err = m_omx_mixer.AllocOutputBuffers();
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(8);
+
+ omx_err = m_omx_mixer.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "%s:%s - m_omx_mixer OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+ LOGTIME(9);
+
+ m_Initialized = true;
+
+ return true;
+}
+
+
+static void copy_planes(uint8_t **dst_buffer, int d_pitch, int d_planes, int d_samplesize, int offset, uint8_t *src_buffer, int src_samples)
+{
+ int planesize = src_samples * d_samplesize / d_planes;
+ for (int i=0; i < d_planes; i++)
+ memcpy(dst_buffer[i] + offset * d_pitch, src_buffer + i * planesize, planesize);
+}
+
+int CActiveAEResamplePi::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio)
+{
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s samples:%d->%d (%.2f)", CLASSNAME, __func__, src_samples, dst_samples, ratio);
+ #endif
+ if (!m_Initialized)
+ return 0;
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ const int s_planes = m_src_fmt >= AV_SAMPLE_FMT_U8P ? m_src_channels : 1;
+ const int d_planes = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? m_dst_channels : 1;
+ const int s_chans = m_src_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_src_channels;
+ const int d_chans = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_dst_channels;
+ const int s_pitch = s_chans * m_src_bits >> 3;
+ const int d_pitch = d_chans * m_dst_bits >> 3;
+
+ const int s_samplesize = m_src_channels * m_src_bits >> 3;
+ const int d_samplesize = m_dst_channels * m_dst_bits >> 3;
+ const int max_src_samples = BUFFERSIZE / s_samplesize;
+ const int max_dst_samples = (long long)(BUFFERSIZE / d_samplesize) * m_src_rate / (m_dst_rate + m_src_rate-1);
+
+ int sent = 0;
+ int received = 0;
+
+ if (m_encoded_buffer && m_encoded_buffer->nFilledLen)
+ {
+ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset;
+ int samples = std::min(samples_available, dst_samples - received);
+ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer + m_encoded_buffer->nOffset * d_pitch, samples);
+ received += samples;
+ samples_available -= samples;
+ if (samples_available > 0)
+ m_encoded_buffer->nOffset += samples;
+ else
+ m_encoded_buffer = NULL;
+ }
+ assert(!m_encoded_buffer);
+ while (sent < src_samples)
+ {
+ OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
+
+ omx_buffer = m_omx_mixer.GetInputBuffer(1000);
+ if (omx_buffer == NULL)
+ return false;
+
+ int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent);
+
+ omx_buffer->nOffset = 0;
+ omx_buffer->nFlags = OMX_BUFFERFLAG_EOS;
+ omx_buffer->nFilledLen = send * s_samplesize;
+
+ assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
+
+ if (omx_buffer->nFilledLen)
+ {
+ int planesize = omx_buffer->nFilledLen / s_planes;
+ for (int i=0; i < s_planes; i++)
+ memcpy((uint8_t *)omx_buffer->pBuffer + i * planesize, src_buffer[i] + sent * s_pitch, planesize);
+ sent += send;
+ }
+
+ omx_err = m_omx_mixer.EmptyThisBuffer(omx_buffer);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ m_encoded_buffer = m_omx_mixer.GetOutputBuffer();
+
+ if (!m_encoded_buffer)
+ {
+ CLog::Log(LOGERROR, "%s::%s no output buffer", CLASSNAME, __func__);
+ return false;
+ }
+ omx_err = m_omx_mixer.FillThisBuffer(m_encoded_buffer);
+ if (omx_err != OMX_ErrorNone)
+ return false;
+
+ omx_err = m_omx_mixer.WaitForOutputDone(1000);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.WaitForOutputDone result(0x%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+ assert(m_encoded_buffer->nFilledLen > 0 && m_encoded_buffer->nFilledLen <= m_encoded_buffer->nAllocLen);
+
+ if (m_omx_mixer.BadState())
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.BadState", CLASSNAME, __func__);
+ return false;
+ }
+
+ if (m_encoded_buffer->nFilledLen)
+ {
+ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize;
+ int samples = std::min(samples_available, dst_samples - received);
+ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer, samples);
+ received += samples;
+ samples_available -= samples;
+ if (samples_available > 0)
+ m_encoded_buffer->nOffset += samples;
+ else
+ m_encoded_buffer = NULL;
+ }
+ }
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__,
+ (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received);
+ #endif
+ assert(received <= dst_samples);
+ return received;
+}
+
+int64_t CActiveAEResamplePi::GetDelay(int64_t base)
+{
+ int ret = m_dst_rate ? 1000 * GetBufferedSamples() / m_dst_rate : 0;
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
+ #endif
+ return ret;
+}
+
+int CActiveAEResamplePi::GetBufferedSamples()
+{
+ int samples = 0;
+ if (m_encoded_buffer)
+ {
+ const int d_samplesize = m_dst_channels * m_dst_bits >> 3;
+ samples = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset;
+ }
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, samples);
+ #endif
+ return samples;
+}
+
+int CActiveAEResamplePi::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate)
+{
+ int ret = ((long long)src_samples * dst_rate + src_rate-1) / src_rate;
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
+ #endif
+ return ret;
+}
+
+int CActiveAEResamplePi::GetSrcBufferSize(int samples)
+{
+ int ret = 0;
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
+ #endif
+ return ret;
+}
+
+int CActiveAEResamplePi::GetDstBufferSize(int samples)
+{
+ int ret = CalcDstSampleCount(samples, m_dst_rate, m_src_rate);
+ #ifdef DEBUG_VERBOSE
+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
+ #endif
+ return ret;
+}
+
+#endif
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
new file mode 100644
index 0000000..9e61f37
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
@@ -0,0 +1,71 @@
+#pragma once
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#include "cores/AudioEngine/Utils/AEChannelInfo.h"
+#include "cores/AudioEngine/Utils/AEAudioFormat.h"
+#include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
+#include "cores/AudioEngine/Interfaces/AE.h"
+#include "cores/AudioEngine/Interfaces/AEResample.h"
+
+extern "C" {
+#include "libavutil/avutil.h"
+#include "libswresample/swresample.h"
+}
+
+#include "linux/OMXCore.h"
+
+namespace ActiveAE
+{
+
+class CActiveAEResamplePi : public IAEResample
+{
+public:
+ const char *GetName() { return "ActiveAEResamplePi"; }
+ CActiveAEResamplePi();
+ virtual ~CActiveAEResamplePi();
+ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
+ int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
+ int64_t GetDelay(int64_t base);
+ int GetBufferedSamples();
+ int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate);
+ int GetSrcBufferSize(int samples);
+ int GetDstBufferSize(int samples);
+
+protected:
+ void DeInit();
+ uint64_t m_src_chan_layout, m_dst_chan_layout;
+ int m_src_rate, m_dst_rate;
+ int m_src_channels, m_dst_channels;
+ AVSampleFormat m_src_fmt, m_dst_fmt;
+ int m_src_bits, m_dst_bits;
+
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output;
+ COMXCoreComponent m_omx_mixer;
+ bool m_Initialized;
+ AVSampleFormat m_last_src_fmt, m_last_dst_fmt;
+ int m_last_src_channels, m_last_dst_channels;
+ OMX_BUFFERHEADERTYPE *m_encoded_buffer;
+};
+
+}
diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in
index b58db3e..efb44cc 100644
--- a/xbmc/cores/AudioEngine/Makefile.in
+++ b/xbmc/cores/AudioEngine/Makefile.in
@@ -33,6 +33,7 @@ SRCS += Engines/ActiveAE/ActiveAESink.cpp
SRCS += Engines/ActiveAE/ActiveAEStream.cpp
SRCS += Engines/ActiveAE/ActiveAESound.cpp
SRCS += Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
+SRCS += Engines/ActiveAE/ActiveAEResamplePi.cpp
SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp
ifeq (@USE_ANDROID@,1)
From f2874956b54c197cbe22292d62bfcf6e6ac39e04 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 3 Oct 2014 18:14:04 +0100
Subject: [PATCH 95/99] settings: Add acceleration option for resampling
---
language/English/strings.po | 10 ++++++++++
system/settings/rbp.xml | 7 +++++++
xbmc/cores/AudioEngine/AEResampleFactory.cpp | 8 ++++++++
3 files changed, 25 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index 989cfcc..58ee88f 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15998,3 +15998,13 @@ msgstr ""
msgctxt "#38006"
msgid "Adjust PLL"
msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38010"
+msgid "Use accelerated resampling"
+msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38011"
+msgid "This setting reduces CPU by handling audio resampling on the GPU"
+msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 9ecae65..a7a0e50 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -61,6 +61,13 @@
<control type="edit" format="integer" />
</setting>
</group>
+ <group id="3">
+ <setting id="videoplayer.resamplepi" type="boolean" label="38010" help="38011">
+ <level>2</level>
+ <default>true</default>
+ <control type="toggle" />
+ </setting>
+ </group>
</category>
</section>
diff --git a/xbmc/cores/AudioEngine/AEResampleFactory.cpp b/xbmc/cores/AudioEngine/AEResampleFactory.cpp
index a0aef34..03e3ddb 100644
--- a/xbmc/cores/AudioEngine/AEResampleFactory.cpp
+++ b/xbmc/cores/AudioEngine/AEResampleFactory.cpp
@@ -18,8 +18,12 @@
*
*/
+#include "settings/Settings.h"
#include "AEResampleFactory.h"
#include "Engines/ActiveAE/ActiveAEResampleFFMPEG.h"
+#if defined(TARGET_RASPBERRY_PI)
+ #include "Engines/ActiveAE/ActiveAEResamplePi.h"
+#endif
extern "C" {
#include "libavutil/channel_layout.h"
@@ -32,6 +36,10 @@ namespace ActiveAE
IAEResample *CAEResampleFactory::Create()
{
+#if defined(TARGET_RASPBERRY_PI)
+ if (CSettings::Get().GetBool("videoplayer.resamplepi"))
+ return new CActiveAEResamplePi();
+#endif
return new CActiveAEResampleFFMPEG();
}
From 52f41c5bf98b71418a754a0d1a41c6d7371fde0b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 24 Sep 2014 23:13:52 +0100
Subject: [PATCH 96/99] [audio] Add settings option to boost centre channel
when downmixing
This allows a dB volume increase to be added to centre channel.
This can help improve dialgue in the presence of background music/effects.
It can go up to 30dB for testing purposes, but value of 6 is probably more reasonable.
It is recommended to ensure "Normalise levels on downmix" is enabled when boosting by large values to avoid clipping.
Should work with Pi Sink (dvdplayer/paplayer) and omxplayer
---
language/English/strings.po | 14 ++++++++++++++
system/settings/settings.xml | 12 ++++++++++++
.../Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp | 6 ++++++
.../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp | 6 ++++++
xbmc/cores/omxplayer/OMXAudio.cpp | 6 ++++++
5 files changed, 44 insertions(+)
diff --git a/language/English/strings.po b/language/English/strings.po
index 58ee88f..6cb308c 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -15999,6 +15999,20 @@ msgctxt "#38006"
msgid "Adjust PLL"
msgstr ""
+#: system/settings/settings.xml
+msgctxt "#38007"
+msgid "Boost centre channel when downmixing"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38008"
+msgid "Increase this value to make the dialogue louder compared to background sounds when downmixing multichannel audio"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38009"
+msgid "%i dB"
+
#: system/settings/rbp.xml
msgctxt "#38010"
msgid "Use accelerated resampling"
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 14f18d9..c8a7d3b 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2449,6 +2449,18 @@
<default>true</default>
<control type="toggle" />
</setting>
+ <setting id="audiooutput.boostcenter" type="integer" label="38007" help="38008">
+ <level>2</level>
+ <default>0</default>
+ <constraints>
+ <minimum>0</minimum>
+ <step>1</step>
+ <maximum>30</maximum>
+ </constraints>
+ <control type="spinner" format="string">
+ <formatlabel>38009</formatlabel>
+ </control>
+ </setting>
<setting id="audiooutput.processquality" type="integer" label="13505" help="36169">
<requirement>HAS_AE_QUALITY_LEVELS</requirement>
<level>2</level>
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
index 8107f44..79f2a0f 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
@@ -108,6 +108,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i
{
av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
}
+ int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+ if (boost_center)
+ {
+ float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+ av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+ }
if (remapLayout)
{
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
index 77ed266..7a25964 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
@@ -159,6 +159,12 @@ bool CActiveAEResamplePi::Init(uint64_t dst_chan_layout, int dst_channels, int d
{
av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
}
+ int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+ if (boost_center)
+ {
+ float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+ av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+ }
if (remapLayout)
{
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index f0ae0cc..c0931b0 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -682,6 +682,12 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
{
av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
}
+ int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+ if (boost_center)
+ {
+ float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+ av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+ }
// stereo upmix
if (upmix && m_src_channels == 2 && m_dst_channels > 2)
From d2cc69cecc28c00513a1eb5497ebc97d9344a670 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 3 Oct 2014 18:38:07 +0100
Subject: [PATCH 97/99] [omxcore] Skip out of flush on error
---
xbmc/linux/OMXCore.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp
index 4ae29ba..4caa304 100644
--- a/xbmc/linux/OMXCore.cpp
+++ b/xbmc/linux/OMXCore.cpp
@@ -419,7 +419,7 @@ void COMXCoreComponent::FlushAll()
void COMXCoreComponent::FlushInput()
{
- if(!m_handle)
+ if(!m_handle || m_resource_error)
return;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
@@ -436,7 +436,7 @@ void COMXCoreComponent::FlushInput()
void COMXCoreComponent::FlushOutput()
{
- if(!m_handle)
+ if(!m_handle || m_resource_error)
return;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
From 702755b0ba747a1c5a33f3c5a52997c4d9f25381 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 3 Oct 2014 18:40:06 +0100
Subject: [PATCH 98/99] [SinkPi] Handle multichannel layout more like OMXAudio
---
xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
index 89684e4..fd9a03d 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
@@ -92,9 +92,9 @@ static void SetAudioProps(bool stream_channels, uint32_t channel_map)
CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map);
}
-static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
+static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough)
{
- unsigned int channels = format.m_channelLayout.Count();
+ unsigned int channels = channelLayout.Count();
uint32_t channel_map = 0;
if (passthrough)
return 0;
@@ -133,12 +133,12 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
// According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
// but no BR BL channels, we use the wide map in order to open only the num of channels really
// needed.
- if (format.m_channelLayout.HasChannel(AE_CH_BL) && !format.m_channelLayout.HasChannel(AE_CH_SL))
+ if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL))
map = map_back;
for (unsigned int i = 0; i < channels; ++i)
{
- AEChannel c = format.m_channelLayout[i];
+ AEChannel c = channelLayout[i];
unsigned int chan = 0;
if ((unsigned int)c < sizeof map_normal / sizeof *map_normal)
chan = map[(unsigned int)c];
@@ -169,9 +169,9 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
0xff, // 7
0x13, // 7.1
};
- uint8_t cea = format.m_channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
+ uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
if (cea == 0xff)
- CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, format.m_channelLayout.HasChannel(AE_CH_LFE), channels);
+ CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels);
channel_map |= cea << 24;
@@ -208,7 +208,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER / NUM_OMX_BUFFERS;
format.m_frameSamples = format.m_frames * channels;
- SetAudioProps(m_passthrough, GetChannelMap(format, m_passthrough));
+ SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough));
m_format = format;
m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate);
From b5a13e0d867266a424c28b04c48df46f8b83b985 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 4 Oct 2014 14:20:59 +0100
Subject: [PATCH 99/99] [vobsub] Fix for incorrect colours with vobsubs and
GLES
Fixes #15146
The code provides the overlay texture in BGRA format, which it informs GL about.
However GLES does not support BGRA, and just claims it is RGBA which results in a red/blue swap.
So this code path needs a red/blue swap.
---
xbmc/cores/VideoRenderers/OverlayRendererGL.cpp | 29 ++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
index a7a2552..ba60958 100644
--- a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
@@ -70,8 +70,35 @@ static void LoadTexture(GLenum target
}
#ifdef HAS_GLES
+
+ /** OpenGL ES does not support BGR **/
+ if (externalFormat == GL_RGBA)
+ {
+ int bytesPerLine = bytesPerPixel * width;
+
+ pixelVector = (char *)malloc(bytesPerLine * height);
+
+ const char *src = (const char*)pixels;
+ char *dst = pixelVector;
+ for (int y = 0;y < height;++y)
+ {
+ src = (const char*)pixels + y * stride;
+ dst = pixelVector + y * bytesPerLine;
+
+ for (unsigned int i = 0; i < width; i++, src+=4, dst+=4)
+ {
+ dst[0] = src[2];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[3];
+ }
+ }
+
+ pixelData = pixelVector;
+ stride = width;
+ }
/** OpenGL ES does not support strided texture input. Make a copy without stride **/
- if (stride != width)
+ else if (stride != width)
{
int bytesPerLine = bytesPerPixel * width;