Skip to content

Commit

Permalink
changed: improve visualization handling.
Browse files Browse the repository at this point in the history
- introduce a manager for instances of visualisation addons
- use this to detach a visualisation's lifecycle from a visualisation
  gui control's life cycle
- introduce multiple slots for visualization - allowing multiple
  displayed at the same time. this is exposed to skinners through the
  subtags 'slot' (just some number) and 'id' (the add-on id for the
  visualization).

add-ons needs to be updated, as the API changes. we have to change the Start()
method to pass screen info since this is now called once per gui control
instance. Likewise Stop() is called when the gui control is killed.

Create() is called at the beginning of the life cycle, and Create()
at the end. These are called exactly once.
  • Loading branch information
notspiff authored and FernetMenta committed Sep 17, 2015
1 parent bdb53ca commit 698eea7
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 58 deletions.
4 changes: 2 additions & 2 deletions addons/library.kodi.guilib/libKODI_guilib.h
Expand Up @@ -825,13 +825,13 @@ class CAddonGUIRenderingControl
virtual ~CAddonGUIRenderingControl();
virtual void Init();

virtual bool Create(int x, int y, int w, int h, void *device);
virtual bool Create(int x, int y, int w, int h, float ratio);
virtual void Render();
virtual void Stop();
virtual bool Dirty();

GUIHANDLE m_cbhdl;
bool (*CBCreate)(GUIHANDLE cbhdl, int x, int y, int w, int h, void *device);
bool (*CBCreate)(GUIHANDLE cbhdl, int x, int y, int w, int h, float ratio);
void (*CBRender)(GUIHANDLE cbhdl);
void (*CBStop)(GUIHANDLE cbhdl);
bool (*CBDirty)(GUIHANDLE cbhdl);
Expand Down
8 changes: 4 additions & 4 deletions lib/addons/library.kodi.guilib/libKODI_guilib.cpp
Expand Up @@ -932,10 +932,10 @@ DLLEXPORT void GUI_control_release_rendering(CAddonGUIRenderingControl* p)
delete p;
}

DLLEXPORT bool GUI_control_rendering_create(GUIHANDLE handle, int x, int y, int w, int h, void *device)
DLLEXPORT bool GUI_control_rendering_create(GUIHANDLE handle, int x, int y, int w, int h, float ratio)
{
CAddonGUIRenderingControl *pControl = (CAddonGUIRenderingControl*) handle;
return pControl->Create(x,y,w,h,device);
return pControl->Create(x,y,w,h,ratio);
}

DLLEXPORT void GUI_control_rendering_render(GUIHANDLE handle)
Expand Down Expand Up @@ -975,12 +975,12 @@ void CAddonGUIRenderingControl::Init()
((CB_GUILib*)m_cb)->RenderAddon_SetCallbacks(((AddonCB*)m_Handle)->addonData, m_RenderingHandle, this, GUI_control_rendering_create, GUI_control_rendering_render, GUI_control_rendering_stop, GUI_control_rendering_dirty);
}

bool CAddonGUIRenderingControl::Create(int x, int y, int w, int h, void *device)
bool CAddonGUIRenderingControl::Create(int x, int y, int w, int h, float ratio)
{
if (!CBCreate)
return false;

return CBCreate(m_cbhdl, x, y, w, h, device);
return CBCreate(m_cbhdl, x, y, w, h, ratio);
}

void CAddonGUIRenderingControl::Render()
Expand Down
3 changes: 3 additions & 0 deletions xbmc/Application.cpp
Expand Up @@ -168,6 +168,7 @@
#include "addons/AddonInstaller.h"
#include "addons/AddonManager.h"
#include "addons/RepositoryUpdater.h"
#include "addons/Visualisation.h"
#include "music/tags/MusicInfoTag.h"
#include "music/tags/MusicInfoTagLoaderFactory.h"
#include "CompileInfo.h"
Expand Down Expand Up @@ -4680,6 +4681,8 @@ void CApplication::ProcessSlow()
CSFTPSessionManager::ClearOutIdleSessions();
#endif

CVisualisationManager::GetInstance().ClearOutIdle();

g_mediaManager.ProcessEvents();

CAEFactory::GarbageCollect();
Expand Down
2 changes: 1 addition & 1 deletion xbmc/addons/AddonCallbacks.h
Expand Up @@ -195,7 +195,7 @@ typedef void (*GUIListItem_SetInfo)(void *addonData, GUIHANDLE handle, co
typedef void (*GUIListItem_SetProperty)(void *addonData, GUIHANDLE handle, const char *key, const char *value);
typedef const char* (*GUIListItem_GetProperty)(void *addonData, GUIHANDLE handle, const char *key);
typedef void (*GUIListItem_SetPath)(void *addonData, GUIHANDLE handle, const char *path);
typedef void (*GUIRenderAddon_SetCallbacks)(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
typedef void (*GUIRenderAddon_SetCallbacks)(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,float), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
typedef void (*GUIRenderAddon_Delete)(void *addonData, GUIHANDLE handle);
typedef void (*GUIRenderAddon_MarkDirty)(void *addonData, GUIHANDLE handle);

Expand Down
6 changes: 3 additions & 3 deletions xbmc/addons/AddonCallbacksGUI.cpp
Expand Up @@ -1632,7 +1632,7 @@ void CAddonCallbacksGUI::ListItem_SetPath(void *addonData, GUIHANDLE handle, con
((CFileItem*)handle)->SetPath(path);
}

void CAddonCallbacksGUI::RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE))
void CAddonCallbacksGUI::RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,float), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE))
{
CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
if (!helper || !handle)
Expand Down Expand Up @@ -2236,11 +2236,11 @@ CGUIAddonRenderingControl::CGUIAddonRenderingControl(CGUIRenderingControl *pCont
m_refCount{1}
{ }

bool CGUIAddonRenderingControl::Create(int x, int y, int w, int h, void *device)
bool CGUIAddonRenderingControl::Create(int x, int y, int w, int h, float ratio)
{
if (CBCreate)
{
if (CBCreate(m_clientHandle, x, y, w, h, device))
if (CBCreate(m_clientHandle, x, y, w, h, ratio))
{
m_refCount++;
return true;
Expand Down
6 changes: 3 additions & 3 deletions xbmc/addons/AddonCallbacksGUI.h
Expand Up @@ -141,7 +141,7 @@ class CAddonCallbacksGUI
static void ListItem_SetProperty(void *addonData, GUIHANDLE handle, const char *key, const char *value);
static const char * ListItem_GetProperty(void *addonData, GUIHANDLE handle, const char *key);
static void ListItem_SetPath(void *addonData, GUIHANDLE handle, const char *path);
static void RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
static void RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,float), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
static void RenderAddon_Delete(void *addonData, GUIHANDLE handle);
static void RenderAddon_MarkDirty(void *addonData, GUIHANDLE handle);

Expand Down Expand Up @@ -253,13 +253,13 @@ friend class CAddonCallbacksGUI;
public:
CGUIAddonRenderingControl(CGUIRenderingControl *pControl);
virtual ~CGUIAddonRenderingControl() {}
virtual bool Create(int x, int y, int w, int h, void *device);
virtual bool Create(int x, int y, int w, int h, float ratio);
virtual void Render();
virtual void Stop();
virtual bool IsDirty();
virtual void Delete();
protected:
bool (*CBCreate) (GUIHANDLE cbhdl, int x, int y, int w, int h, void *device);
bool (*CBCreate) (GUIHANDLE cbhdl, int x, int y, int w, int h, float ratio);
void (*CBRender)(GUIHANDLE cbhdl);
void (*CBStop)(GUIHANDLE cbhdl);
bool (*CBDirty)(GUIHANDLE cbhdl);
Expand Down
91 changes: 67 additions & 24 deletions xbmc/addons/Visualisation.cpp
Expand Up @@ -62,40 +62,21 @@ void CAudioBuffer::Set(const float* psBuffer, int iSize)
for (int i = iSize; i < m_iLen; ++i) m_pBuffer[i] = 0;
}

bool CVisualisation::Create(int x, int y, int w, int h, void *device)
bool CVisualisation::Create()
{
m_pInfo = new VIS_PROPS;
#ifdef HAS_DX
m_pInfo->device = g_Windowing.Get3D11Context();
#else
m_pInfo->device = NULL;
#endif
m_pInfo->x = x;
m_pInfo->y = y;
m_pInfo->width = w;
m_pInfo->height = h;
m_pInfo->pixelRatio = g_graphicsContext.GetResInfo().fPixelRatio;

m_pInfo->name = strdup(Name().c_str());
m_pInfo->presets = strdup(CSpecialProtocol::TranslatePath(Path()).c_str());
m_pInfo->profile = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
m_pInfo->submodule = NULL;

if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create() == ADDON_STATUS_OK)
{
// Start the visualisation
std::string strFile = URIUtils::GetFileName(g_application.CurrentFile());
CLog::Log(LOGDEBUG, "Visualisation::Start()\n");
try
{
m_pStruct->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile.c_str());
}
catch (std::exception e)
{
HandleException(e, "m_pStruct->Start() (CVisualisation::Create)");
return false;
}

m_hasPresets = GetPresets();

if (GetSubModules())
Expand All @@ -105,22 +86,34 @@ bool CVisualisation::Create(int x, int y, int w, int h, void *device)

CreateBuffers();

CAEFactory::RegisterAudioCallback(this);

return true;
}
return false;
}

void CVisualisation::Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName)
bool CVisualisation::Create(int x, int y, int width, int height, float fPixelRatio)
{
std::string strFile = URIUtils::GetFileName(g_application.CurrentFile());
Start(x, y, width, height, fPixelRatio, m_iChannels,
m_iSamplesPerSec, m_iBitsPerSample, strFile);
}

void CVisualisation::Start(int x, int y, int width, int height, float pixelRatio,
int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName)
{
// notify visz. that new song has been started
// pass it the nr of audio channels, sample rate, bits/sample and offcourse the songname
// and the screen info

// Start the visualisation
if (Initialized())
{
CAEFactory::RegisterAudioCallback(this);

try
{
m_pStruct->Start(iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str());
m_pStruct->Start(x, y, width, height, pixelRatio,
iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str());
}
catch (std::exception e)
{
Expand Down Expand Up @@ -473,3 +466,53 @@ std::string CVisualisation::GetPresetName()
return "";
}


CVisualisationManager::CVisualisationManager()
{
}

CVisualisationManager& CVisualisationManager::GetInstance()
{
static CVisualisationManager instance;

return instance;
}

VisualisationPtr CVisualisationManager::GetAddon(const std::string& id, int slot)
{
if (m_addons.find(slot) == m_addons.end() ||
m_addons[slot].first->ID() != id)
{
AddonPtr addon;
CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_VIZ);
if (addon)
m_addons[slot].first = std::static_pointer_cast<CVisualisation>(addon);
else
return VisualisationPtr();
m_addons[slot].first->Create();
}

m_addons[slot].second.Stop();
return m_addons[slot].first;
}

void CVisualisationManager::Release(int slot)
{
m_addons[slot].second.StartZero();
}

void CVisualisationManager::ClearOutIdle()
{
std::vector<int> remove;
for (auto& it : m_addons)
{
if (it.second.second.GetElapsedSeconds() > 30)
remove.push_back(it.first);
}

for (auto& i : remove)
{
CLog::Log(LOGDEBUG, "Visualization %s in slot %i has been IDLE for 30 secs, stopping..", m_addons[i].first->ID().c_str(), i);
m_addons.erase(i);
}
}
35 changes: 33 additions & 2 deletions xbmc/addons/Visualisation.h
Expand Up @@ -24,6 +24,7 @@
#include "include/xbmc_vis_types.h"
#include "guilib/IRenderingCallback.h"
#include "utils/rfft.h"
#include "utils/Stopwatch.h"

#include <algorithm>
#include <map>
Expand Down Expand Up @@ -61,8 +62,10 @@ namespace ADDON
CVisualisation(const cp_extension_t *ext) : CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>(ext) {}
virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample);
virtual void OnAudioData(const float* pAudioData, int iAudioDataLength);
bool Create(int x, int y, int w, int h, void *device);
void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName);
bool Create();
virtual bool Create(int x, int y, int w, int h, float pixelRatio);
void Start(int x, int y, int w, int h, float pixelRatio,
int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName);
void AudioData(const float *pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
void Render();
void Stop();
Expand Down Expand Up @@ -113,4 +116,32 @@ namespace ADDON
// track information
std::string m_AlbumThumb;
};

typedef std::shared_ptr<CVisualisation> VisualisationPtr;

//! \brief Class managing visualisation instances.
class CVisualisationManager
{
public:
//! \brief Singleton accessor
static CVisualisationManager& GetInstance();

//! \brief Obtain an addon instance.
//! \param id ID of the addon to obtain.
//! \param slot Slot to put addon in.
VisualisationPtr GetAddon(const std::string& id, int slot=0);

//! \brief Release an addon.
//! \param slot Slot to release.
void Release(int slot);

//! \brief Clear out instances which have been idle for more than 30 secs.
void ClearOutIdle();
protected:
//! \brief Protected construction. Use singleton accessor.
CVisualisationManager();

//! \brief Mapsslot -> (addon, idle timer).
std::map<int, std::pair<VisualisationPtr, CStopWatch>> m_addons;
};
}
3 changes: 2 additions & 1 deletion xbmc/addons/include/xbmc_vis_dll.h
Expand Up @@ -27,7 +27,8 @@
extern "C"
{
// Functions that your visualisation must implement
void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName);
void Start(int x, int y, int width, int height, float pixelRatio,
int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName);
void AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
void Render();
bool OnAction(long action, const void *param);
Expand Down
9 changes: 3 additions & 6 deletions xbmc/addons/include/xbmc_vis_types.h
Expand Up @@ -37,11 +37,6 @@ extern "C"
struct VIS_PROPS
{
void *device;
int x;
int y;
int width;
int height;
float pixelRatio;
const char *name;
const char *presets;
const char *profile;
Expand Down Expand Up @@ -95,7 +90,9 @@ extern "C"

struct Visualisation
{
void (__cdecl* Start)(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName);
void (__cdecl* Start)(int x, int y, int width, int height, float pixelRatio,
int iChannels, int iSamplesPerSec, int iBitsPerSample,
const char* szSongName);
void (__cdecl* AudioData)(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
void (__cdecl* Render) ();
void (__cdecl* GetInfo)(VIS_INFO *info);
Expand Down
8 changes: 7 additions & 1 deletion xbmc/guilib/GUIControlFactory.cpp
Expand Up @@ -1473,7 +1473,13 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
}
break;
case CGUIControl::GUICONTROL_VISUALISATION:
control = new CGUIVisualisationControl(parentID, id, posX, posY, width, height);
{
int slot=0;
XMLUtils::GetInt(pControlNode, "slot", slot);
std::string aid;
XMLUtils::GetString(pControlNode, "id", aid);
control = new CGUIVisualisationControl(parentID, id, posX, posY, width, height, slot, aid);
}
break;
case CGUIControl::GUICONTROL_RENDERADDON:
control = new CGUIRenderingControl(parentID, id, posX, posY, width, height);
Expand Down
7 changes: 2 additions & 5 deletions xbmc/guilib/GUIRenderingControl.cpp
Expand Up @@ -57,11 +57,8 @@ bool CGUIRenderingControl::InitCallback(IRenderingCallback *callback)
if (x + w > g_graphicsContext.GetWidth()) w = g_graphicsContext.GetWidth() - x;
if (y + h > g_graphicsContext.GetHeight()) h = g_graphicsContext.GetHeight() - y;

void *device = NULL;
#if HAS_DX
device = g_Windowing.Get3D11Device();
#endif
if (callback->Create((int)(x+0.5f), (int)(y+0.5f), (int)(w+0.5f), (int)(h+0.5f), device))
if (callback->Create((int)(x+0.5f), (int)(y+0.5f), (int)(w+0.5f), (int)(h+0.5f),
g_graphicsContext.GetResInfo().fPixelRatio))
m_callback = callback;
else
return false;
Expand Down

0 comments on commit 698eea7

Please sign in to comment.