mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
11741 lines
460 KiB
Diff
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="<actor><name>\2</name><role>\3</role></actor>" dest="4+">
|
|
<expression repeat="yes" noclean="1,2,3"><Actor>.*?<Image>([^<]*)</Image>.*?<Name>([^<]*)</Name>.*?<Role>([^<]*)</expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$2" output="<chain function="GetArt">\1</chain>" dest="4+">
|
|
+ <expression/>
|
|
+ </RegExp>
|
|
+ <RegExp input="$$3" output="\1" dest="6">
|
|
+ <expression>.*/(.*).zip</expression>
|
|
+ </RegExp>
|
|
+ <RegExp input="$$3" output="<episodeguide><url cache="$$2-$$6.xml">\1</url></episodeguide>" dest="4+">
|
|
+ <expression/>
|
|
+ </RegExp>
|
|
+ <expression noclean="1"/>
|
|
+ </RegExp>
|
|
+ </GetDetails>
|
|
+
|
|
+ <GetArt dest="3">
|
|
+ <RegExp input="$$4" output="<details>\1</details>" dest="3">
|
|
+ <RegExp input="$$1" output="<url function="ParseArt" cache="\1-banners.xml">http://thetvdb.com/api/1D62F2F90030C444/series/\1/banners.xml</url>" dest="4">
|
|
+ <expression/>
|
|
+ </RegExp>
|
|
+ <expression noclean="1"/>
|
|
+ </RegExp>
|
|
+ </GetArt>
|
|
+ <ParseArt dest="3">
|
|
+ <RegExp input="$$4" output="<details>\1</details>" dest="3">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>$INFO[language]</Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>$INFO[language]</Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>blank</BannerType2>[^<]*<Language></Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="poster" type="season" season="\2">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="poster" type="season" season="\2">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="poster" type="season" season="\3">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="poster" type="season" season="\3">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner" type="season" season="\2">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner" type="season" season="\2">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="banner" type="season" season="\3">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="banner" type="season" season="\3">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="poster">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="poster">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb aspect="poster" type="season" season="-1">http://thetvdb.com/banners/\1</thumb>" dest="4+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType></expression>
|
|
</RegExp>
|
|
- <RegExp conditional="fanart" input="$$7" output="<fanart url="http://thetvdb.com/banners/">\1</fanart>" dest="4+">
|
|
- <RegExp input="$$5" output="<thumb dim="\2" colors="\3" preview="_cache/\1">\1</thumb>" dest="7+">
|
|
+ <RegExp conditional="fanart" input="$$5" output="<fanart url="http://thetvdb.com/banners/">\1</fanart>" dest="4+">
|
|
+ <RegExp input="$$1" output="<thumb dim="\2" colors="\3" preview="_cache/\1">\1</thumb>" dest="5">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>$INFO[language]</Language></expression>
|
|
</RegExp>
|
|
- <RegExp input="$$5" output="<thumb dim="\2" colors="\3" preview="_cache/\1">\1</thumb>" dest="7+">
|
|
+ <RegExp input="$$1" output="<thumb dim="\2" colors="\3" preview="_cache/\1">\1</thumb>" dest="5+">
|
|
<expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>((?!$INFO[language])[a-z])*</Language></expression>
|
|
</RegExp>
|
|
<expression noclean="1"/>
|
|
</RegExp>
|
|
- <RegExp input="$$3" output="\1" dest="6">
|
|
- <expression>.*/(.*).zip</expression>
|
|
- </RegExp>
|
|
- <RegExp input="$$3" output="<episodeguide><url cache="$$2-$$6.xml">\1</url></episodeguide>" 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 ¤t, 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 ¤tMode, 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;
|
|
|