diff options
author | Alwin Esch <alwin.esch@web.de> | 2017-06-22 17:41:11 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-22 17:41:11 +0200 |
commit | 506419b7c11350537fce2dc4179da1c5dff6fa16 (patch) | |
tree | e9be3cf3afcef88236c44e43d95c4915bed6bb49 | |
parent | 1de7be400e9189d3c91c93ba1c84ff44f3e63a47 (diff) | |
parent | 428b378150d4104709279b48ed668acb09d92ad7 (diff) |
Merge pull request #12325 from AlwinEsch/change-inputstream
[inputstream] change addon interface to new C++ style
-rw-r--r-- | xbmc/addons/AddonBuilder.cpp | 7 | ||||
-rw-r--r-- | xbmc/addons/BinaryAddonCache.cpp | 1 | ||||
-rw-r--r-- | xbmc/addons/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/addons/InputStream.cpp | 481 | ||||
-rw-r--r-- | xbmc/addons/InputStream.h | 145 | ||||
-rw-r--r-- | xbmc/addons/interfaces/AddonInterfaces.cpp | 20 | ||||
-rw-r--r-- | xbmc/addons/interfaces/AddonInterfaces.h | 4 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h | 585 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_dll.h | 256 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h | 187 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_inputstream.h | 89 | ||||
-rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h | 8 | ||||
-rw-r--r-- | xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp | 31 | ||||
-rw-r--r-- | xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp | 365 | ||||
-rw-r--r-- | xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h | 87 |
15 files changed, 940 insertions, 1328 deletions
diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp index 7ce67db302..b39f0fc840 100644 --- a/xbmc/addons/AddonBuilder.cpp +++ b/xbmc/addons/AddonBuilder.cpp @@ -24,7 +24,6 @@ #include "addons/GameResource.h" #include "addons/ImageDecoder.h" #include "addons/ImageResource.h" -#include "addons/InputStream.h" #include "addons/LanguageResource.h" #include "addons/PluginSource.h" #include "addons/Repository.h" @@ -125,6 +124,7 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() case ADDON_ADSPDLL: case ADDON_AUDIOENCODER: case ADDON_IMAGEDECODER: + case ADDON_INPUTSTREAM: case ADDON_VIZ: case ADDON_SCREENSAVER: return std::make_shared<CAddonDll>(std::move(m_addonInfo)); @@ -132,8 +132,6 @@ std::shared_ptr<IAddon> CAddonBuilder::Build() return std::make_shared<PVR::CPVRClient>(std::move(m_addonInfo)); case ADDON_AUDIODECODER: return CAudioDecoder::FromExtension(std::move(m_addonInfo), m_extPoint); - case ADDON_INPUTSTREAM: - return CInputStream::FromExtension(std::move(m_addonInfo), m_extPoint); case ADDON_PERIPHERALDLL: return PERIPHERALS::CPeripheralAddon::FromExtension(std::move(m_addonInfo), m_extPoint); case ADDON_GAMEDLL: @@ -195,6 +193,7 @@ AddonPtr CAddonBuilder::FromProps(CAddonInfo addonInfo) case ADDON_ADSPDLL: case ADDON_AUDIOENCODER: case ADDON_IMAGEDECODER: + case ADDON_INPUTSTREAM: case ADDON_VIZ: case ADDON_SCREENSAVER: return AddonPtr(new CAddonDll(std::move(addonInfo))); @@ -214,8 +213,6 @@ AddonPtr CAddonBuilder::FromProps(CAddonInfo addonInfo) return AddonPtr(new CRepository(std::move(addonInfo))); case ADDON_CONTEXT_ITEM: return AddonPtr(new CContextMenuAddon(std::move(addonInfo))); - case ADDON_INPUTSTREAM: - return AddonPtr(new CInputStream(std::move(addonInfo))); case ADDON_PERIPHERALDLL: return AddonPtr(new PERIPHERALS::CPeripheralAddon(std::move(addonInfo), false, false)); //! @todo implement case ADDON_GAME_CONTROLLER: diff --git a/xbmc/addons/BinaryAddonCache.cpp b/xbmc/addons/BinaryAddonCache.cpp index b46fe738a4..f8775c2916 100644 --- a/xbmc/addons/BinaryAddonCache.cpp +++ b/xbmc/addons/BinaryAddonCache.cpp @@ -34,7 +34,6 @@ void CBinaryAddonCache::Init() { m_addonsToCache = { ADDON_AUDIODECODER, - ADDON_INPUTSTREAM, ADDON_PVRDLL, ADDON_GAMEDLL, ADDON_VFS, diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt index 92436e558a..8145bce0de 100644 --- a/xbmc/addons/CMakeLists.txt +++ b/xbmc/addons/CMakeLists.txt @@ -19,7 +19,6 @@ set(SOURCES Addon.cpp GUIWindowAddonBrowser.cpp ImageDecoder.cpp ImageResource.cpp - InputStream.cpp LanguageResource.cpp PluginSource.cpp PVRClient.cpp @@ -58,7 +57,6 @@ set(HEADERS Addon.h IAddon.h ImageDecoder.h ImageResource.h - InputStream.h LanguageResource.h PluginSource.h PVRClient.h diff --git a/xbmc/addons/InputStream.cpp b/xbmc/addons/InputStream.cpp deleted file mode 100644 index b013428f8f..0000000000 --- a/xbmc/addons/InputStream.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2016 Team Kodi - * - * 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 "InputStream.h" -#include "URL.h" -#include "filesystem/SpecialProtocol.h" -#include "utils/StringUtils.h" -#include "utils/log.h" -#include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" -#include "threads/SingleLock.h" -#include "utils/RegExp.h" -#include "utils/URIUtils.h" -#include "utils/Variant.h" - -namespace ADDON -{ - -std::map<std::string, CInputStream::Config> CInputStream::m_configMap; -CCriticalSection CInputStream::m_parentSection; - -std::unique_ptr<CInputStream> CInputStream::FromExtension(CAddonInfo addonInfo, const cp_extension_t* ext) -{ - std::string listitemprops = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@listitemprops"); - std::string extensions = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@extension"); - std::string protocols = CAddonMgr::GetInstance().GetExtValue(ext->configuration, "@protocols"); - std::string name(ext->plugin->identifier); - std::unique_ptr<CInputStream> istr(new CInputStream(addonInfo, name, listitemprops, - extensions, protocols)); - if (!CAddonMgr::GetInstance().IsAddonDisabled(addonInfo.ID())) - istr->CheckConfig(); - return istr; -} - -CInputStream::CInputStream(const CAddonInfo& addonInfo, - const std::string& name, - const std::string& listitemprops, - const std::string& extensions, - const std::string& protocols) -: CAddonDll(std::move(addonInfo)) -{ - m_fileItemProps = StringUtils::Tokenize(listitemprops, "|"); - for (auto &key : m_fileItemProps) - { - StringUtils::Trim(key); - key = name + "." + key; - } - - m_extensionsList = StringUtils::Tokenize(extensions, "|"); - for (auto &ext : m_extensionsList) - { - StringUtils::Trim(ext); - } - - m_protocolsList = StringUtils::Tokenize(protocols, "|"); - for (auto &ext : m_protocolsList) - { - StringUtils::Trim(ext); - } - - memset(&m_struct, 0, sizeof(m_struct)); - m_struct.toKodi.kodiInstance = this; - m_struct.toKodi.AllocateDemuxPacket = cb_allocate_demux_packet; - m_struct.toKodi.FreeDemuxPacket = cb_free_demux_packet; -} - -bool CInputStream::Create() -{ - return CAddonDll::Create(ADDON_INSTANCE_INPUTSTREAM, &m_struct, &m_struct.props) == ADDON_STATUS_OK; -} - -void CInputStream::SaveSettings() -{ - CAddon::SaveSettings(); - if (!m_bIsChild) - UpdateConfig(); -} - -void CInputStream::CheckConfig() -{ - bool hasConfig = false; - - { - CSingleLock lock(m_parentSection); - auto it = m_configMap.find(ID()); - hasConfig = it != m_configMap.end(); - } - - if (!m_bIsChild && !hasConfig) - UpdateConfig(); -} - -void CInputStream::UpdateConfig() -{ - std::string pathList; - ADDON_STATUS status = CAddonDll::Create(ADDON_INSTANCE_INPUTSTREAM, &m_struct, &m_struct.props); - - if (status != ADDON_STATUS_PERMANENT_FAILURE) - { - pathList = m_struct.toAddon.GetPathList(); - Destroy(); - } - - Config config; - config.m_pathList = StringUtils::Tokenize(pathList, "|"); - for (auto &path : config.m_pathList) - { - StringUtils::Trim(path); - } - - CSingleLock lock(m_parentSection); - auto it = m_configMap.find(ID()); - if (it == m_configMap.end()) - config.m_parentBusy = false; - else - config.m_parentBusy = it->second.m_parentBusy; - - config.m_ready = true; - if (status == ADDON_STATUS_PERMANENT_FAILURE) - config.m_ready = false; - - m_configMap[ID()] = config; -} - -bool CInputStream::UseParent() -{ - CSingleLock lock(m_parentSection); - - auto it = m_configMap.find(ID()); - if (it == m_configMap.end()) - return false; - if (it->second.m_parentBusy) - return false; - - it->second.m_parentBusy = true; - return true; -} - -bool CInputStream::Supports(const CFileItem &fileitem) -{ - { - CSingleLock lock(m_parentSection); - - auto it = m_configMap.find(ID()); - if (it == m_configMap.end()) - return false; - if (!it->second.m_ready) - return false; - } - - // check if a specific inputstream addon is requested - CVariant addon = fileitem.GetProperty("inputstreamaddon"); - if (!addon.isNull()) - { - if (addon.asString() != ID()) - return false; - else - return true; - } - - // check protocols - std::string protocol = fileitem.GetURL().GetProtocol(); - if (!protocol.empty()) - { - if (std::find(m_protocolsList.begin(), - m_protocolsList.end(), protocol) != m_protocolsList.end()) - return true; - } - - // check paths - CSingleLock lock(m_parentSection); - auto it = m_configMap.find(ID()); - if (it == m_configMap.end()) - return false; - - bool match = false; - for (auto &path : it->second.m_pathList) - { - if (path.empty()) - continue; - - CRegExp r(true, CRegExp::asciiOnly, path.c_str()); - if (r.RegFind(fileitem.GetPath().c_str()) == 0 && r.GetFindLen() > 5) - { - match = true; - break; - } - } - return match; -} - -bool CInputStream::Open(CFileItem &fileitem) -{ - INPUTSTREAM props; - std::map<std::string, std::string> propsMap; - for (auto &key : m_fileItemProps) - { - if (fileitem.GetProperty(key).isNull()) - continue; - propsMap[key] = fileitem.GetProperty(key).asString(); - } - - props.m_nCountInfoValues = 0; - for (auto &pair : propsMap) - { - props.m_ListItemProperties[props.m_nCountInfoValues].m_strKey = pair.first.c_str(); - props.m_ListItemProperties[props.m_nCountInfoValues].m_strValue = pair.second.c_str(); - props.m_nCountInfoValues++; - } - - props.m_strURL = fileitem.GetPath().c_str(); - - std::string libFolder = URIUtils::GetDirectory(m_parentLib); - std::string profileFolder = CSpecialProtocol::TranslatePath(Profile()); - props.m_libFolder = libFolder.c_str(); - props.m_profileFolder = profileFolder.c_str(); - - bool ret = m_struct.toAddon.Open(props); - if (ret) - m_caps = m_struct.toAddon.GetCapabilities(); - - UpdateStreams(); - return ret; -} - -void CInputStream::Close() -{ - m_struct.toAddon.Close(); - - if (!m_bIsChild) - { - CSingleLock lock(m_parentSection); - auto it = m_configMap.find(ID()); - if (it != m_configMap.end()) - it->second.m_parentBusy = false; - } -} - -// IDisplayTime -int CInputStream::GetTotalTime() -{ - return m_struct.toAddon.GetTotalTime(); -} - -int CInputStream::GetTime() -{ - return m_struct.toAddon.GetTime(); -} - -// IPosTime -bool CInputStream::PosTime(int ms) -{ - return m_struct.toAddon.PosTime(ms); -} - -// IDemux -void CInputStream::UpdateStreams() -{ - DisposeStreams(); - - INPUTSTREAM_IDS streamIDs = m_struct.toAddon.GetStreamIds(); - if (streamIDs.m_streamCount > INPUTSTREAM_IDS::MAX_STREAM_COUNT) - { - DisposeStreams(); - return; - } - - for (unsigned int i=0; i<streamIDs.m_streamCount; i++) - { - INPUTSTREAM_INFO stream = m_struct.toAddon.GetStream(streamIDs.m_streamIds[i]); - if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_NONE) - continue; - - std::string codecName(stream.m_codecName); - StringUtils::ToLower(codecName); - AVCodec *codec = avcodec_find_decoder_by_name(codecName.c_str()); - if (!codec) - continue; - - CDemuxStream *demuxStream; - - if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_AUDIO) - { - CDemuxStreamAudio *audioStream = new CDemuxStreamAudio(); - - audioStream->iChannels = stream.m_Channels; - audioStream->iSampleRate = stream.m_SampleRate; - audioStream->iBlockAlign = stream.m_BlockAlign; - audioStream->iBitRate = stream.m_BitRate; - audioStream->iBitsPerSample = stream.m_BitsPerSample; - demuxStream = audioStream; - } - else if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_VIDEO) - { - CDemuxStreamVideo *videoStream = new CDemuxStreamVideo(); - - videoStream->iFpsScale = stream.m_FpsScale; - videoStream->iFpsRate = stream.m_FpsRate; - videoStream->iWidth = stream.m_Width; - videoStream->iHeight = stream.m_Height; - videoStream->fAspect = stream.m_Aspect; - videoStream->stereo_mode = "mono"; - videoStream->iBitRate = stream.m_BitRate; - demuxStream = videoStream; - } - else if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_SUBTITLE) - { - //! @todo needs identifier in INPUTSTREAM_INFO - continue; - } - else - continue; - - demuxStream->codec = codec->id; - demuxStream->codecName = stream.m_codecInternalName; - demuxStream->uniqueId = streamIDs.m_streamIds[i]; - demuxStream->language[0] = stream.m_language[0]; - demuxStream->language[1] = stream.m_language[1]; - demuxStream->language[2] = stream.m_language[2]; - demuxStream->language[3] = stream.m_language[3]; - - if (stream.m_ExtraData && stream.m_ExtraSize) - { - demuxStream->ExtraData = new uint8_t[stream.m_ExtraSize]; - demuxStream->ExtraSize = stream.m_ExtraSize; - for (unsigned int j=0; j<stream.m_ExtraSize; j++) - demuxStream->ExtraData[j] = stream.m_ExtraData[j]; - } - - m_streams[demuxStream->uniqueId] = demuxStream; - } -} - -void CInputStream::DisposeStreams() -{ - for (auto &stream : m_streams) - delete stream.second; - m_streams.clear(); -} - -int CInputStream::GetNrOfStreams() const -{ - return m_streams.size(); -} - -CDemuxStream* CInputStream::GetStream(int iStreamId) -{ - std::map<int, CDemuxStream*>::iterator it = m_streams.find(iStreamId); - if (it != m_streams.end()) - return it->second; - - return nullptr; -} - -std::vector<CDemuxStream*> CInputStream::GetStreams() const -{ - std::vector<CDemuxStream*> streams; - - for (auto &stream : m_streams) - { - streams.push_back(stream.second); - } - - return streams; -} - -void CInputStream::EnableStream(int iStreamId, bool enable) -{ - std::map<int, CDemuxStream*>::iterator it = m_streams.find(iStreamId); - if (it == m_streams.end()) - return; - - m_struct.toAddon.EnableStream(it->second->uniqueId, enable); -} - -DemuxPacket* CInputStream::ReadDemux() -{ - DemuxPacket* pPacket = m_struct.toAddon.DemuxRead(); - - if (!pPacket) - { - return nullptr; - } - else if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO) - { - UpdateStreams(); - } - else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE) - { - UpdateStreams(); - } - - return pPacket; -} - -bool CInputStream::SeekTime(double time, bool backward, double* startpts) -{ - return m_struct.toAddon.DemuxSeekTime(time, backward, startpts); -} - -void CInputStream::AbortDemux() -{ - m_struct.toAddon.DemuxAbort(); -} - -void CInputStream::FlushDemux() -{ - m_struct.toAddon.DemuxFlush(); -} - -void CInputStream::SetSpeed(int iSpeed) -{ - m_struct.toAddon.DemuxSetSpeed(iSpeed); -} - -int CInputStream::ReadStream(uint8_t* buf, unsigned int size) -{ - return m_struct.toAddon.ReadStream(buf, size); -} - -int64_t CInputStream::SeekStream(int64_t offset, int whence) -{ - return m_struct.toAddon.SeekStream(offset, whence); -} - -int64_t CInputStream::PositionStream() -{ - return m_struct.toAddon.PositionStream(); -} - -int64_t CInputStream::LengthStream() -{ - return m_struct.toAddon.LengthStream(); -} - -void CInputStream::PauseStream(double time) -{ - m_struct.toAddon.PauseStream(time); -} - -bool CInputStream::IsRealTimeStream() -{ - return m_struct.toAddon.IsRealTimeStream(); -} - -void CInputStream::SetVideoResolution(int width, int height) -{ - m_struct.toAddon.SetVideoResolution(width, height); -} - -/*! - * Callbacks from add-on to kodi - */ -//@{ -DemuxPacket* CInputStream::cb_allocate_demux_packet(void* kodiInstance, int iDataSize) -{ - return CDVDDemuxUtils::AllocateDemuxPacket(iDataSize); -} - -void CInputStream::cb_free_demux_packet(void* kodiInstance, DemuxPacket* pPacket) -{ - CDVDDemuxUtils::FreeDemuxPacket(pPacket); -} -//@} - -} /*namespace ADDON*/ - diff --git a/xbmc/addons/InputStream.h b/xbmc/addons/InputStream.h deleted file mode 100644 index 3b85860c45..0000000000 --- a/xbmc/addons/InputStream.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2016 Team Kodi - * - * 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/>. - * - */ -#pragma once - -#include "addons/binary-addons/AddonDll.h" -#include "addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h" -#include "FileItem.h" -#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" -#include "threads/CriticalSection.h" -#include <vector> -#include <map> - -class CDemuxStream; - -namespace ADDON -{ - - class CInputStream : public CAddonDll - { - public: - - static std::unique_ptr<CInputStream> FromExtension(CAddonInfo addonInfo, const cp_extension_t* ext); - - explicit CInputStream(CAddonInfo addonInfo) - : CAddonDll(std::move(addonInfo)) - {}; - CInputStream(const CAddonInfo& addonInfo, - const std::string& name, - const std::string& listitemprops, - const std::string& extensions, - const std::string& protocols); - virtual ~CInputStream() {} - - virtual void SaveSettings() override; - - bool Create(); - - bool UseParent(); - bool Supports(const CFileItem &fileitem); - bool Open(CFileItem &fileitem); - void Close(); - - bool HasDemux() { return m_caps.m_supportsIDemux; }; - bool HasPosTime() { return m_caps.m_supportsIPosTime; }; - bool HasDisplayTime() { return m_caps.m_supportsIDisplayTime; }; - bool CanPause() { return m_caps.m_supportsPause; }; - bool CanSeek() { return m_caps.m_supportsSeek; }; - - // IDisplayTime - int GetTotalTime(); - int GetTime(); - - // IPosTime - bool PosTime(int ms); - - // demux - int GetNrOfStreams() const; - CDemuxStream* GetStream(int iStreamId); - std::vector<CDemuxStream*> GetStreams() const; - DemuxPacket* ReadDemux(); - bool SeekTime(double time, bool backward, double* startpts); - void AbortDemux(); - void FlushDemux(); - void SetSpeed(int iSpeed); - void EnableStream(int iStreamId, bool enable); - void SetVideoResolution(int width, int height); - - // stream - int ReadStream(uint8_t* buf, unsigned int size); - int64_t SeekStream(int64_t offset, int whence); - int64_t PositionStream(); - int64_t LengthStream(); - void PauseStream(double time); - bool IsRealTimeStream(); - - /*! - * @brief To get the interface table used between addon and kodi - * @todo This function becomes removed after old callback library system - * is removed. - */ - AddonInstance_InputStream* GetInstanceInterface() { return &m_struct; } - - protected: - void UpdateStreams(); - void DisposeStreams(); - void UpdateConfig(); - void CheckConfig(); - - std::vector<std::string> m_fileItemProps; - std::vector<std::string> m_extensionsList; - std::vector<std::string> m_protocolsList; - INPUTSTREAM_CAPABILITIES m_caps; - std::map<int, CDemuxStream*> m_streams; - - static CCriticalSection m_parentSection; - - struct Config - { - std::vector<std::string> m_pathList; - bool m_parentBusy; - bool m_ready; - }; - static std::map<std::string, Config> m_configMap; - - private: - /*! - * @brief Callback functions from addon to kodi - */ - //@{ - /*! - * @brief Allocate a demux packet. Free with FreeDemuxPacket - * @param kodiInstance A pointer to the add-on. - * @param iDataSize The size of the data that will go into the packet - * @return The allocated packet. - */ - static DemuxPacket* cb_allocate_demux_packet(void* kodiInstance, int iDataSize = 0); - - /*! - * @brief Free a packet that was allocated with AllocateDemuxPacket - * @param kodiInstance A pointer to the add-on. - * @param pPacket The packet to free. - */ - static void cb_free_demux_packet(void* kodiInstance, DemuxPacket* pPacket); - //@} - - AddonInstance_InputStream m_struct; - }; - -} /*namespace ADDON*/ diff --git a/xbmc/addons/interfaces/AddonInterfaces.cpp b/xbmc/addons/interfaces/AddonInterfaces.cpp index 5f664810da..1d52b2ecf2 100644 --- a/xbmc/addons/interfaces/AddonInterfaces.cpp +++ b/xbmc/addons/interfaces/AddonInterfaces.cpp @@ -22,7 +22,6 @@ #include "AddonInterfaces.h" #include "addons/Addon.h" -#include "addons/InputStream.h" #include "addons/PVRClient.h" #include "games/addons/GameClient.h" @@ -56,8 +55,6 @@ CAddonInterfaces::CAddonInterfaces(CAddon* addon) m_callbacks->GUILib_UnRegisterMe = CAddonInterfaces::GUILib_UnRegisterMe; m_callbacks->PVRLib_RegisterMe = CAddonInterfaces::PVRLib_RegisterMe; m_callbacks->PVRLib_UnRegisterMe = CAddonInterfaces::PVRLib_UnRegisterMe; - m_callbacks->INPUTSTREAMLib_RegisterMe = CAddonInterfaces::INPUTSTREAMLib_RegisterMe; - m_callbacks->INPUTSTREAMLib_UnRegisterMe = CAddonInterfaces::INPUTSTREAMLib_UnRegisterMe; m_callbacks->PeripheralLib_RegisterMe = CAddonInterfaces::PeripheralLib_RegisterMe; m_callbacks->PeripheralLib_UnRegisterMe = CAddonInterfaces::PeripheralLib_UnRegisterMe; m_callbacks->GameLib_RegisterMe = CAddonInterfaces::GameLib_RegisterMe; @@ -164,23 +161,6 @@ void CAddonInterfaces::GameLib_UnRegisterMe(void *addonData, void *cbTable) } /*\_____________________________________________________________________________ \*/ -void* CAddonInterfaces::INPUTSTREAMLib_RegisterMe(void *addonData) -{ - CAddonInterfaces* addon = static_cast<CAddonInterfaces*>(addonData); - if (addon == nullptr) - { - CLog::Log(LOGERROR, "CAddonInterfaces - %s - called with a null pointer", __FUNCTION__); - return nullptr; - } - - return dynamic_cast<ADDON::CInputStream*>(addon->m_addon)->GetInstanceInterface(); -} - -void CAddonInterfaces::INPUTSTREAMLib_UnRegisterMe(void *addonData, void* cbTable) -{ -} -/*\_____________________________________________________________________________ -\*/ void* CAddonInterfaces::PeripheralLib_RegisterMe(void *addonData) { CAddonInterfaces* addon = static_cast<CAddonInterfaces*>(addonData); diff --git a/xbmc/addons/interfaces/AddonInterfaces.h b/xbmc/addons/interfaces/AddonInterfaces.h index 63465141a9..b8db5dd678 100644 --- a/xbmc/addons/interfaces/AddonInterfaces.h +++ b/xbmc/addons/interfaces/AddonInterfaces.h @@ -62,10 +62,6 @@ namespace ADDON static void PVRLib_UnRegisterMe (void* addonData, void* cbTable); /*\_________________________________________________________________________ \*/ - static void* INPUTSTREAMLib_RegisterMe (void *addonData); - static void INPUTSTREAMLib_UnRegisterMe (void *addonData, void* cbTable); - /*\_________________________________________________________________________ - \*/ static void* PeripheralLib_RegisterMe (void *addonData); static void PeripheralLib_UnRegisterMe (void *addonData, void* cbTable); /*\_________________________________________________________________________ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h new file mode 100644 index 0000000000..bdb80bb742 --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h @@ -0,0 +1,585 @@ +#pragma once +/* + * Copyright (C) 2005-2017 Team Kodi + * http://kodi.tv + * + * 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 Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +/* + * Parts with a comment named "internal" are only used inside header and not + * used or accessed direct during add-on development! + */ + +#include "../AddonBase.h" + +#ifdef BUILD_KODI_ADDON +#include "../DVDDemuxPacket.h" +#else +#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxPacket.h" +#endif + +namespace kodi { namespace addon { class CInstanceInputStream; }} + +extern "C" { + + /*! + * @brief InputStream add-on capabilities. All capabilities are set to "false" as default. + */ + typedef struct INPUTSTREAM_CAPABILITIES + { + enum MASKTYPE: uint32_t + { + /// supports interface IDemux + SUPPORTS_IDEMUX = (1 << 0), + + /// supports interface IPosTime + SUPPORTS_IPOSTIME = (1 << 1), + + /// supports interface IDisplayTime + SUPPORTS_IDISPLAYTIME = (1 << 2), + + /// supports seek + SUPPORTS_SEEK = (1 << 3), + + /// supports pause + SUPPORTS_PAUSE = (1 << 4) + }; + + /// set of supported capabilities + uint32_t m_mask; + } INPUTSTREAM_CAPABILITIES; + + /*! + * @brief structure of key/value pairs passed to addon on Open() + */ + typedef struct INPUTSTREAM + { + static const unsigned int MAX_INFO_COUNT = 8; + + const char *m_strURL; + + unsigned int m_nCountInfoValues; + struct LISTITEMPROPERTY + { + const char *m_strKey; + const char *m_strValue; + } m_ListItemProperties[MAX_INFO_COUNT]; + + const char *m_libFolder; + const char *m_profileFolder; + } INPUTSTREAM; + + /*! + * @brief Array of stream IDs + */ + typedef struct INPUTSTREAM_IDS + { + static const unsigned int MAX_STREAM_COUNT = 32; + unsigned int m_streamCount; + unsigned int m_streamIds[MAX_STREAM_COUNT]; + } INPUTSTREAM_IDS; + + /*! + * @brief stream properties + */ + typedef struct INPUTSTREAM_INFO + { + enum STREAM_TYPE + { + TYPE_NONE, + TYPE_VIDEO, + TYPE_AUDIO, + TYPE_SUBTITLE, + TYPE_TELETEXT + } m_streamType; + + char m_codecName[32]; /*!< @brief (required) name of codec according to ffmpeg */ + char m_codecInternalName[32]; /*!< @brief (optional) internal name of codec (selectionstream info) */ + unsigned int m_pID; /*!< @brief (required) physical index */ + + const uint8_t *m_ExtraData; + unsigned int m_ExtraSize; + + char m_language[4]; /*!< @brief ISO 639 3-letter language code (empty string if undefined) */ + + unsigned int m_FpsScale; /*!< @brief Scale of 1000 and a rate of 29970 will result in 29.97 fps */ + unsigned int m_FpsRate; + unsigned int m_Height; /*!< @brief height of the stream reported by the demuxer */ + unsigned int m_Width; /*!< @brief width of the stream reported by the demuxer */ + float m_Aspect; /*!< @brief display aspect of stream */ + + unsigned int m_Channels; /*!< @brief (required) amount of channels */ + unsigned int m_SampleRate; /*!< @brief (required) sample rate */ + unsigned int m_BitRate; /*!< @brief (required) bit rate */ + unsigned int m_BitsPerSample; /*!< @brief (required) bits per sample */ + unsigned int m_BlockAlign; + } INPUTSTREAM_INFO; + + /*! + * @brief Structure to transfer the methods from xbmc_inputstream_dll.h to XBMC + */ + + // this are properties given to the addon on create + // at this time we have no parameters for the addon + typedef struct AddonProps_InputStream /* internal */ + { + int dummy; + } AddonProps_InputStream; + + typedef struct AddonToKodiFuncTable_InputStream /* internal */ + { + KODI_HANDLE kodiInstance; + DemuxPacket* (*allocate_demux_packet)(void* kodiInstance, int data_size); + void (*free_demux_packet)(void* kodiInstance, DemuxPacket* packet); + } AddonToKodiFuncTable_InputStream; + + struct AddonInstance_InputStream; + typedef struct KodiToAddonFuncTable_InputStream /* internal */ + { + kodi::addon::CInstanceInputStream* addonInstance; + + bool (__cdecl* open)(const AddonInstance_InputStream* instance, INPUTSTREAM* props); + void (__cdecl* close)(const AddonInstance_InputStream* instance); + const char* (__cdecl* get_path_list)(const AddonInstance_InputStream* instance); + void (__cdecl* get_capabilities)(const AddonInstance_InputStream* instance, INPUTSTREAM_CAPABILITIES* capabilities); + + // IDemux + struct INPUTSTREAM_IDS (__cdecl* get_stream_ids)(const AddonInstance_InputStream* instance); + struct INPUTSTREAM_INFO (__cdecl* get_stream)(const AddonInstance_InputStream* instance, int streamid); + void (__cdecl* enable_stream)(const AddonInstance_InputStream* instance, int streamid, bool enable); + void (__cdecl* demux_reset)(const AddonInstance_InputStream* instance); + void (__cdecl* demux_abort)(const AddonInstance_InputStream* instance); + void (__cdecl* demux_flush)(const AddonInstance_InputStream* instance); + DemuxPacket* (__cdecl* demux_read)(const AddonInstance_InputStream* instance); + bool (__cdecl* demux_seek_time)(const AddonInstance_InputStream* instance, double time, bool backwards, double* startpts); + void (__cdecl* demux_set_speed)(const AddonInstance_InputStream* instance, int speed); + void (__cdecl* set_video_resolution)(const AddonInstance_InputStream* instance, int width, int height); + + // IDisplayTime + int (__cdecl* get_total_time)(const AddonInstance_InputStream* instance); + int (__cdecl* get_time)(const AddonInstance_InputStream* instance); + + // IPosTime + bool (__cdecl* pos_time)(const AddonInstance_InputStream* instance, int ms); + + // Seekable (mandatory) + bool (__cdecl* can_pause_stream)(const AddonInstance_InputStream* instance); + bool (__cdecl* can_seek_stream)(const AddonInstance_InputStream* instance); + + int (__cdecl* read_stream)(const AddonInstance_InputStream* instance, uint8_t* buffer, unsigned int bufferSize); + int64_t(__cdecl* seek_stream)(const AddonInstance_InputStream* instance, int64_t position, int whence); + int64_t (__cdecl* position_stream)(const AddonInstance_InputStream* instance); + int64_t (__cdecl* length_stream)(const AddonInstance_InputStream* instance); + void (__cdecl* pause_stream)(const AddonInstance_InputStream* instance, double time); + bool (__cdecl* is_real_time_stream)(const AddonInstance_InputStream* instance); + } KodiToAddonFuncTable_InputStream; + + typedef struct AddonInstance_InputStream /* internal */ + { + AddonProps_InputStream props; + AddonToKodiFuncTable_InputStream toKodi; + KodiToAddonFuncTable_InputStream toAddon; + } AddonInstance_InputStream; + +} /* extern "C" */ + +namespace kodi +{ +namespace addon +{ + + class CInstanceInputStream : public IAddonInstance + { + public: + CInstanceInputStream(KODI_HANDLE instance) + : IAddonInstance(ADDON_INSTANCE_INPUTSTREAM) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceInputStream: Creation of multiple together with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + + virtual ~CInstanceInputStream() = default; + + /*! + * Open a stream. + * @param props + * @return True if the stream has been opened successfully, false otherwise. + * @remarks + */ + virtual bool Open(INPUTSTREAM& props) = 0; + + /*! + * Close an open stream. + * @remarks + */ + virtual void Close() = 0; + + /*! + * Get Capabilities of this addon. + * @param capabilities The add-on's capabilities. + * @remarks + */ + virtual void GetCapabilities(INPUTSTREAM_CAPABILITIES& capabilities) = 0; + + /*! + * Get IDs of available streams + * @remarks + */ + virtual INPUTSTREAM_IDS GetStreamIds() { return INPUTSTREAM_IDS(); } + + /*! + * Get stream properties of a stream. + * @param streamid unique id of stream + * @return struc of stream properties + * @remarks + */ + virtual INPUTSTREAM_INFO GetStream(int streamid) { return INPUTSTREAM_INFO(); } + + /*! + * Enable or disable a stream. + * A disabled stream does not send demux packets + * @param streamid unique id of stream + * @param enable true for enable, false for disable + * @remarks + */ + virtual void EnableStream(int streamid, bool enable) { } + + /*! + * Reset the demultiplexer in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxReset() { } + + /*! + * Abort the demultiplexer thread in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxAbort() { } + + /*! + * Flush all data that's currently in the demultiplexer buffer in the add-on. + * @remarks Required if bHandlesDemuxing is set to true. + */ + virtual void DemuxFlush() { } + + /*! + * Read the next packet from the demultiplexer, if there is one. + * @return The next packet. + * If there is no next packet, then the add-on should return the + * packet created by calling AllocateDemuxPacket(0) on the callback. + * If the stream changed and Kodi's player needs to be reinitialised, + * then, the add-on should call AllocateDemuxPacket(0) on the + * callback, and set the streamid to DMX_SPECIALID_STREAMCHANGE and + * return the value. + * The add-on should return NULL if an error occured. + * @remarks Return NULL if this add-on won't provide this function. + */ + virtual DemuxPacket* DemuxRead() { return nullptr; } + + /*! + * Notify the InputStream addon/demuxer that Kodi wishes to seek the stream by time + * Demuxer is required to set stream to an IDR frame + * @param time The absolute time since stream start + * @param backwards True to seek to keyframe BEFORE time, else AFTER + * @param startpts can be updated to point to where display should start + * @return True if the seek operation was possible + * @remarks Optional, and only used if addon has its own demuxer. + */ + virtual bool DemuxSeekTime(double time, bool backwards, double &startpts) { return false; } + + /*! + * Notify the InputStream addon/demuxer that Kodi wishes to change playback speed + * @param speed The requested playback speed + * @remarks Optional, and only used if addon has its own demuxer. + */ + virtual void DemuxSetSpeed(int speed) { } + + /*! + * Sets desired width / height + * @param width / hight + */ + virtual void SetVideoResolution(int width, int height) { } + + /*! + * Totel time in ms + * @remarks + */ + virtual int GetTotalTime() { return -1; } + + /*! + * Playing time in ms + * @remarks + */ + virtual int GetTime() { return -1; } + + /*! + * Positions inputstream to playing time given in ms + * @remarks + */ + virtual bool PosTime(int ms) { return false; } + + + /*! + * Check if the backend support pausing the currently playing stream + * This will enable/disable the pause button in Kodi based on the return value + * @return false if the InputStream addon/backend does not support pausing, true if possible + */ + virtual bool CanPauseStream() { return false; } + + /*! + * Check if the backend supports seeking for the currently playing stream + * This will enable/disable the rewind/forward buttons in Kodi based on the return value + * @return false if the InputStream addon/backend does not support seeking, true if possible + */ + virtual bool CanSeekStream() { return false; } + + /*! + * Read from an open stream. + * @param buffer The buffer to store the data in. + * @param bufferSize The amount of bytes to read. + * @return The amount of bytes that were actually read from the stream. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int ReadStream(uint8_t* buffer, unsigned int bufferSize) { return -1; } + + /*! + * Seek in a stream. + * @param position The position to seek to. + * @param whence ? + * @return The new position. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t SeekStream(int64_t position, int whence = SEEK_SET) { return -1; } + + /*! + * @return The position in the stream that's currently being read. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t PositionStream() { return -1; } + + /*! + * @return The total length of the stream that's currently being read. + * @remarks Return -1 if this add-on won't provide this function. + */ + virtual int64_t LengthStream() { return -1; } + + + /*! + * @brief Notify the InputStream addon that Kodi (un)paused the currently playing stream + */ + virtual void PauseStream(double time) { } + + + /*! + * Check for real-time streaming + * @return true if current stream is real-time + */ + virtual bool IsRealTimeStream() { return true; } + + /*! + * @brief Allocate a demux packet. Free with FreeDemuxPacket + * @param dataSize The size of the data that will go into the packet + * @return The allocated packet + */ + DemuxPacket* AllocateDemuxPacket(int dataSize) + { + return m_instanceData->toKodi.allocate_demux_packet(m_instanceData->toKodi.kodiInstance, dataSize); + } + + /*! + * @brief Free a packet that was allocated with AllocateDemuxPacket + * @param packet The packet to free + */ + void FreeDemuxPacket(DemuxPacket* packet) + { + return m_instanceData->toKodi.free_demux_packet(m_instanceData->toKodi.kodiInstance, packet); + } + + private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceInputStream: Creation with empty addon structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast<AddonInstance_InputStream*>(instance); + m_instanceData->toAddon.addonInstance = this; + m_instanceData->toAddon.open = ADDON_Open; + m_instanceData->toAddon.close = ADDON_Close; + m_instanceData->toAddon.get_capabilities = ADDON_GetCapabilities; + + m_instanceData->toAddon.get_stream_ids = ADDON_GetStreamIds; + m_instanceData->toAddon.get_stream = ADDON_GetStream; + m_instanceData->toAddon.enable_stream = ADDON_EnableStream; + m_instanceData->toAddon.demux_reset = ADDON_DemuxReset; + m_instanceData->toAddon.demux_abort = ADDON_DemuxAbort; + m_instanceData->toAddon.demux_flush = ADDON_DemuxFlush; + m_instanceData->toAddon.demux_read = ADDON_DemuxRead; + m_instanceData->toAddon.demux_seek_time = ADDON_DemuxSeekTime; + m_instanceData->toAddon.demux_set_speed = ADDON_DemuxSetSpeed; + m_instanceData->toAddon.set_video_resolution = ADDON_SetVideoResolution; + + m_instanceData->toAddon.get_total_time = ADDON_GetTotalTime; + m_instanceData->toAddon.get_time = ADDON_GetTime; + + m_instanceData->toAddon.pos_time = ADDON_PosTime; + + m_instanceData->toAddon.can_pause_stream = ADDON_CanPauseStream; + m_instanceData->toAddon.can_seek_stream = ADDON_CanSeekStream; + + m_instanceData->toAddon.read_stream = ADDON_ReadStream; + m_instanceData->toAddon.seek_stream = ADDON_SeekStream; + m_instanceData->toAddon.position_stream = ADDON_PositionStream; + m_instanceData->toAddon.length_stream = ADDON_LengthStream; + m_instanceData->toAddon.pause_stream = ADDON_PauseStream; + m_instanceData->toAddon.is_real_time_stream = ADDON_IsRealTimeStream; + } + + inline static bool ADDON_Open(const AddonInstance_InputStream* instance, INPUTSTREAM* props) + { + return instance->toAddon.addonInstance->Open(*props); + } + + inline static void ADDON_Close(const AddonInstance_InputStream* instance) + { + instance->toAddon.addonInstance->Close(); + } + + inline static void ADDON_GetCapabilities(const AddonInstance_InputStream* instance, INPUTSTREAM_CAPABILITIES* capabilities) + { + instance->toAddon.addonInstance->GetCapabilities(*capabilities); + } + + + // IDemux + inline static struct INPUTSTREAM_IDS ADDON_GetStreamIds(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->GetStreamIds(); + } + + inline static struct INPUTSTREAM_INFO ADDON_GetStream(const AddonInstance_InputStream* instance, int streamid) + { + return instance->toAddon.addonInstance->GetStream(streamid); + } + + inline static void ADDON_EnableStream(const AddonInstance_InputStream* instance, int streamid, bool enable) + { + instance->toAddon.addonInstance->EnableStream(streamid, enable); + } + + inline static void ADDON_DemuxReset(const AddonInstance_InputStream* instance) + { + instance->toAddon.addonInstance->DemuxReset(); + } + + inline static void ADDON_DemuxAbort(const AddonInstance_InputStream* instance) + { + instance->toAddon.addonInstance->DemuxAbort(); + } + + inline static void ADDON_DemuxFlush(const AddonInstance_InputStream* instance) + { + instance->toAddon.addonInstance->DemuxFlush(); + } + + inline static DemuxPacket* ADDON_DemuxRead(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->DemuxRead(); + } + + inline static bool ADDON_DemuxSeekTime(const AddonInstance_InputStream* instance, double time, bool backwards, double *startpts) + { + return instance->toAddon.addonInstance->DemuxSeekTime(time, backwards, *startpts); + } + + inline static void ADDON_DemuxSetSpeed(const AddonInstance_InputStream* instance, int speed) + { + instance->toAddon.addonInstance->DemuxSetSpeed(speed); + } + + inline static void ADDON_SetVideoResolution(const AddonInstance_InputStream* instance, int width, int height) + { + instance->toAddon.addonInstance->SetVideoResolution(width, height); + } + + + // IDisplayTime + inline static int ADDON_GetTotalTime(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->GetTotalTime(); + } + + inline static int ADDON_GetTime(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->GetTime(); + } + + + // IPosTime + inline static bool ADDON_PosTime(const AddonInstance_InputStream* instance, int ms) + { + return instance->toAddon.addonInstance->PosTime(ms); + } + + // Seekable (mandatory) + inline static bool ADDON_CanPauseStream(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->CanPauseStream(); + } + + inline static bool ADDON_CanSeekStream(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->CanSeekStream(); + } + + + inline static int ADDON_ReadStream(const AddonInstance_InputStream* instance, uint8_t* buffer, unsigned int bufferSize) + { + return instance->toAddon.addonInstance->ReadStream(buffer, bufferSize); + } + + inline static int64_t ADDON_SeekStream(const AddonInstance_InputStream* instance, int64_t position, int whence) + { + return instance->toAddon.addonInstance->SeekStream(position, whence); + } + + inline static int64_t ADDON_PositionStream(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->PositionStream(); + } + + inline static int64_t ADDON_LengthStream(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->LengthStream(); + } + + inline static void ADDON_PauseStream(const AddonInstance_InputStream* instance, double time) + { + instance->toAddon.addonInstance->PauseStream(time); + } + + inline static bool ADDON_IsRealTimeStream(const AddonInstance_InputStream* instance) + { + return instance->toAddon.addonInstance->IsRealTimeStream(); + } + + AddonInstance_InputStream* m_instanceData; + }; + +} /* namespace addon */ +} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_dll.h deleted file mode 100644 index ab8475d9bb..0000000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_dll.h +++ /dev/null @@ -1,256 +0,0 @@ -#pragma once - -/* -* Copyright (C) 2005-2016 Team Kodi -* http://kodi.tv -* -* 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 Kodi; see the file COPYING. If not, see -* <http://www.gnu.org/licenses/>. -* -*/ - -#include "kodi_inputstream_types.h" -#include "xbmc_addon_dll.h" - -/*! -* Functions that the InputStream client add-on must implement, but some can be empty. -* -* The 'remarks' field indicates which methods should be implemented, and which ones are optional. -*/ - -extern "C" -{ - /*! - * Open a stream. - * @param props - * @return True if the stream has been opened successfully, false otherwise. - * @remarks - */ - bool Open(INPUTSTREAM& props); - - /*! - * Close an open stream. - * @remarks - */ - void Close(void); - - /*! - * Get path/url for this addon. - * @remarks - */ - const char* GetPathList(void); - - /*! - * Get Capabilities of this addon. - * @remarks - */ - struct INPUTSTREAM_CAPABILITIES GetCapabilities(); - - - /*! - * Get IDs of available streams - * @remarks - */ - INPUTSTREAM_IDS GetStreamIds(); - - /*! - * Get stream properties of a stream. - * @param streamId unique id of stream - * @return struc of stream properties - * @remarks - */ - INPUTSTREAM_INFO GetStream(int streamid); - - /*! - * Enable or disable a stream. - * A disabled stream does not send demux packets - * @param streamId unique id of stream - * @param enable true for enable, false for disable - * @remarks - */ - void EnableStream(int streamid, bool enable); - - /*! - * Reset the demultiplexer in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - void DemuxReset(void); - - /*! - * Abort the demultiplexer thread in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - void DemuxAbort(void); - - /*! - * Flush all data that's currently in the demultiplexer buffer in the add-on. - * @remarks Required if bHandlesDemuxing is set to true. - */ - void DemuxFlush(void); - - /*! - * Read the next packet from the demultiplexer, if there is one. - * @return The next packet. - * If there is no next packet, then the add-on should return the - * packet created by calling AllocateDemuxPacket(0) on the callback. - * If the stream changed and XBMC's player needs to be reinitialised, - * then, the add-on should call AllocateDemuxPacket(0) on the - * callback, and set the streamid to DMX_SPECIALID_STREAMCHANGE and - * return the value. - * The add-on should return NULL if an error occured. - * @remarks Return NULL if this add-on won't provide this function. - */ - DemuxPacket* DemuxRead(void); - - /*! - * Notify the InputStream addon/demuxer that XBMC wishes to seek the stream by time - * Demuxer is required to set stream to an IDR frame - * @param time The absolute time since stream start - * @param backwards True to seek to keyframe BEFORE time, else AFTER - * @param startpts can be updated to point to where display should start - * @return True if the seek operation was possible - * @remarks Optional, and only used if addon has its own demuxer. - */ - bool DemuxSeekTime(double time, bool backwards, double *startpts); - - /*! - * Notify the InputStream addon/demuxer that XBMC wishes to change playback speed - * @param speed The requested playback speed - * @remarks Optional, and only used if addon has its own demuxer. - */ - void DemuxSetSpeed(int speed); - - /*! - * Sets desired width / height - * @param width / hight - */ - void SetVideoResolution(int width, int height); - - /*! - * Totel time in ms - * @remarks - */ - int GetTotalTime(); - - /*! - * Playing time in ms - * @remarks - */ - int GetTime(); - - /*! - * Positions inputstream to playing time given in ms - * @remarks - */ - bool PosTime(int ms); - - - /*! - * Check if the backend support pausing the currently playing stream - * This will enable/disable the pause button in XBMC based on the return value - * @return false if the InputStream addon/backend does not support pausing, true if possible - */ - bool CanPauseStream(); - - /*! - * Check if the backend supports seeking for the currently playing stream - * This will enable/disable the rewind/forward buttons in XBMC based on the return value - * @return false if the InputStream addon/backend does not support seeking, true if possible - */ - bool CanSeekStream(); - - - /*! - * Read from an open stream. - * @param pBuffer The buffer to store the data in. - * @param iBufferSize The amount of bytes to read. - * @return The amount of bytes that were actually read from the stream. - * @remarks Return -1 if this add-on won't provide this function. - */ - int ReadStream(uint8_t* pBuffer, unsigned int iBufferSize); - - /*! - * Seek in a stream. - * @param iPosition The position to seek to. - * @param iWhence ? - * @return The new position. - * @remarks Return -1 if this add-on won't provide this function. - */ - int64_t SeekStream(int64_t iPosition, int iWhence = SEEK_SET); - - /*! - * @return The position in the stream that's currently being read. - * @remarks Return -1 if this add-on won't provide this function. - */ - int64_t PositionStream(void); - - /*! - * @return The total length of the stream that's currently being read. - * @remarks Return -1 if this add-on won't provide this function. - */ - int64_t LengthStream(void); - - - /*! - * @brief Notify the InputStream addon that XBMC (un)paused the currently playing stream - */ - void PauseStream(double time); - - - /*! - * Check for real-time streaming - * @return true if current stream is real-time - */ - bool IsRealTimeStream(); - - /*! - * Called by XBMC to assign the function pointers of this add-on to pClient. - * @param pClient The struct to assign the function pointers to. - */ - void __declspec(dllexport) get_addon(void* ptr) - { - AddonInstance_InputStream* pClient = static_cast<AddonInstance_InputStream*>(ptr); - - pClient->toAddon.Open = Open; - pClient->toAddon.Close = Close; - pClient->toAddon.GetPathList = GetPathList; - pClient->toAddon.GetCapabilities = GetCapabilities; - - pClient->toAddon.GetStreamIds = GetStreamIds; - pClient->toAddon.GetStream = GetStream; - pClient->toAddon.EnableStream = EnableStream; - pClient->toAddon.DemuxReset = DemuxReset; - pClient->toAddon.DemuxAbort = DemuxAbort; - pClient->toAddon.DemuxFlush = DemuxFlush; - pClient->toAddon.DemuxRead = DemuxRead; - pClient->toAddon.DemuxSeekTime = DemuxSeekTime; - pClient->toAddon.DemuxSetSpeed = DemuxSetSpeed; - pClient->toAddon.SetVideoResolution = SetVideoResolution; - - pClient->toAddon.GetTotalTime = GetTotalTime; - pClient->toAddon.GetTime = GetTime; - - pClient->toAddon.PosTime = PosTime; - - pClient->toAddon.CanPauseStream = CanPauseStream; - pClient->toAddon.CanSeekStream = CanSeekStream; - - pClient->toAddon.ReadStream = ReadStream; - pClient->toAddon.SeekStream = SeekStream; - pClient->toAddon.PositionStream = PositionStream; - pClient->toAddon.LengthStream = LengthStream; - pClient->toAddon.PauseStream = PauseStream; - pClient->toAddon.IsRealTimeStream = IsRealTimeStream; - }; -}; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h deleted file mode 100644 index 9597e8a5fc..0000000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_inputstream_types.h +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2005-2016 Team Kodi - * http://kodi.tv - * - * 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 Kodi; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#ifndef TARGET_WINDOWS -#ifndef __cdecl -#define __cdecl -#endif -#ifndef __declspec -#define __declspec(X) -#endif -#endif - -#include "xbmc_addon_types.h" - -#ifdef BUILD_KODI_ADDON -#include "DVDDemuxPacket.h" -#else -#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxPacket.h" -#endif - -extern "C" { - - /*! - * @brief InputStream add-on capabilities. All capabilities are set to "false" as default. - */ - typedef struct INPUTSTREAM_CAPABILITIES - { - bool m_supportsIDemux; /*!< @brief supports interface IDemux */ - bool m_supportsIPosTime; /*!< @brief supports interface IPosTime */ - bool m_supportsIDisplayTime; /*!< @brief supports interface IDisplayTime */ - bool m_supportsSeek; /*!< @brief supports seek */ - bool m_supportsPause; /*!< @brief supports pause */ - } INPUTSTREAM_CAPABILITIES; - - /*! - * @brief structure of key/value pairs passed to addon on Open() - */ - typedef struct INPUTSTREAM - { - static const unsigned int MAX_INFO_COUNT = 8; - - const char *m_strURL; - - unsigned int m_nCountInfoValues; - struct LISTITEMPROPERTY - { - const char *m_strKey; - const char *m_strValue; - } m_ListItemProperties[MAX_INFO_COUNT]; - - const char *m_libFolder; - const char *m_profileFolder; - } INPUTSTREAM; - - /*! - * @brief Array of stream IDs - */ - typedef struct INPUTSTREAM_IDS - { - static const unsigned int MAX_STREAM_COUNT = 32; - unsigned int m_streamCount; - unsigned int m_streamIds[MAX_STREAM_COUNT]; - } INPUTSTREAM_IDS; - - /*! - * @brief stream properties - */ - typedef struct INPUTSTREAM_INFO - { - enum STREAM_TYPE - { - TYPE_NONE, - TYPE_VIDEO, - TYPE_AUDIO, - TYPE_SUBTITLE, - TYPE_TELETEXT - } m_streamType; - - char m_codecName[32]; /*!< @brief (required) name of codec according to ffmpeg */ - char m_codecInternalName[32]; /*!< @brief (optional) internal name of codec (selectionstream info) */ - unsigned int m_pID; /*!< @brief (required) physical index */ - - const uint8_t *m_ExtraData; - unsigned int m_ExtraSize; - - char m_language[4]; /*!< @brief ISO 639 3-letter language code (empty string if undefined) */ - - unsigned int m_FpsScale; /*!< @brief Scale of 1000 and a rate of 29970 will result in 29.97 fps */ - unsigned int m_FpsRate; - unsigned int m_Height; /*!< @brief height of the stream reported by the demuxer */ - unsigned int m_Width; /*!< @brief width of the stream reported by the demuxer */ - float m_Aspect; /*!< @brief display aspect of stream */ - - unsigned int m_Channels; /*!< @brief (required) amount of channels */ - unsigned int m_SampleRate; /*!< @brief (required) sample rate */ - unsigned int m_BitRate; /*!< @brief (required) bit rate */ - unsigned int m_BitsPerSample; /*!< @brief (required) bits per sample */ - unsigned int m_BlockAlign; - } INPUTSTREAM_INFO; - - /*! - * @brief Structure to transfer the methods from xbmc_inputstream_dll.h to XBMC - */ - - // this are properties given to the addon on create - // at this time we have no parameters for the addon - typedef struct AddonProps_InputStream - { - int dummy; - } AddonProps_InputStream; - - typedef AddonProps_InputStream INPUTSTREAM_PROPS; - - typedef struct AddonToKodiFuncTable_InputStream - { - KODI_HANDLE kodiInstance; - DemuxPacket* (*AllocateDemuxPacket)(void* kodiInstance, int iDataSize); - void (*FreeDemuxPacket)(void* kodiInstance, DemuxPacket* pPacket); - } AddonToKodiFuncTable_InputStream; - - typedef struct KodiToAddonFuncTable_InputStream - { - bool (__cdecl* Open)(INPUTSTREAM&); - void (__cdecl* Close)(void); - const char* (__cdecl* GetPathList)(void); - struct INPUTSTREAM_CAPABILITIES (__cdecl* GetCapabilities)(void); - - // IDemux - struct INPUTSTREAM_IDS (__cdecl* GetStreamIds)(); - struct INPUTSTREAM_INFO (__cdecl* GetStream)(int); - void (__cdecl* EnableStream)(int, bool); - void (__cdecl* DemuxReset)(void); - void (__cdecl* DemuxAbort)(void); - void (__cdecl* DemuxFlush)(void); - DemuxPacket* (__cdecl* DemuxRead)(void); - bool (__cdecl* DemuxSeekTime)(double, bool, double*); - void (__cdecl* DemuxSetSpeed)(int); - void (__cdecl* SetVideoResolution)(int, int); - - // IDisplayTime - int (__cdecl* GetTotalTime)(void); - int (__cdecl* GetTime)(void); - - // IPosTime - bool (__cdecl* PosTime)(int); - - // Seekable (mandatory) - bool (__cdecl* CanPauseStream)(void); - bool (__cdecl* CanSeekStream)(void); - - int (__cdecl* ReadStream)(uint8_t*, unsigned int); - int64_t(__cdecl* SeekStream)(int64_t, int); - int64_t (__cdecl* PositionStream)(void); - int64_t (__cdecl* LengthStream)(void); - void (__cdecl* PauseStream)(double); - bool (__cdecl* IsRealTimeStream)(void); - } KodiToAddonFuncTable_InputStream; - - typedef struct AddonInstance_InputStream - { - AddonProps_InputStream props; - AddonToKodiFuncTable_InputStream toKodi; - KodiToAddonFuncTable_InputStream toAddon; - } AddonInstance_InputStream; - -} - - diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_inputstream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_inputstream.h deleted file mode 100644 index d37d24ef6f..0000000000 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_inputstream.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2005-2016 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/>. - * - */ - -#pragma once - -#include <string> -#include <vector> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include "kodi_inputstream_types.h" -#include "versions.h" - -#ifdef BUILD_KODI_ADDON -#include "DVDDemuxPacket.h" -#else -#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxPacket.h" -#endif - -class CHelper_libKODI_inputstream -{ -public: - CHelper_libKODI_inputstream(void) - { - m_Handle = nullptr; - m_Callbacks = nullptr; - } - - ~CHelper_libKODI_inputstream(void) - { - } - - /*! - * @brief Resolve all callback methods - * @param handle Pointer to the add-on - * @return True when all methods were resolved, false otherwise. - */ - bool RegisterMe(void* handle) - { - m_Handle = static_cast<AddonCB*>(handle); - if (m_Handle) - m_Callbacks = (AddonInstance_InputStream*)m_Handle->INPUTSTREAMLib_RegisterMe(m_Handle->addonData); - if (!m_Callbacks) - fprintf(stderr, "libKODI_inputstream-ERROR: InputStream_RegisterMe can't get callback table from Kodi !!!\n"); - - return m_Callbacks != nullptr; - } - - /*! - * @brief Allocate a demux packet. Free with FreeDemuxPacket - * @param iDataSize The size of the data that will go into the packet - * @return The allocated packet - */ - DemuxPacket* AllocateDemuxPacket(int iDataSize) - { - return m_Callbacks->toKodi.AllocateDemuxPacket(m_Callbacks->toKodi.kodiInstance, iDataSize); - } - - /*! - * @brief Free a packet that was allocated with AllocateDemuxPacket - * @param pPacket The packet to free - */ - void FreeDemuxPacket(DemuxPacket* pPacket) - { - return m_Callbacks->toKodi.FreeDemuxPacket(m_Callbacks->toKodi.kodiInstance, pPacket); - } - -private: - AddonCB* m_Handle; - AddonInstance_InputStream* m_Callbacks; -}; diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h index e3ffd1965e..34c2861a99 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h @@ -103,12 +103,10 @@ #define ADDON_INSTANCE_VERSION_IMAGEDECODER_XML_ID "kodi.binary.instance.imagedecoder" #define ADDON_INSTANCE_VERSION_IMAGEDECODER_DEPENDS "addon-instance/ImageDecoder.h" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM "1.0.8" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN "1.0.8" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM "2.0.0" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN "2.0.0" #define ADDON_INSTANCE_VERSION_INPUTSTREAM_XML_ID "kodi.binary.instance.inputstream" -#define ADDON_INSTANCE_VERSION_INPUTSTREAM_DEPENDS "libKODI_inputstream.h" \ - "kodi_inputstream_dll.h" \ - "kodi_inputstream_types.h" +#define ADDON_INSTANCE_VERSION_INPUTSTREAM_DEPENDS "addon-instance/Inputstream.h" #define ADDON_INSTANCE_VERSION_PERIPHERAL "1.3.3" #define ADDON_INSTANCE_VERSION_PERIPHERAL_MIN "1.3.3" diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp index 08da796bb1..17113b8e9a 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp @@ -40,13 +40,14 @@ #include "filesystem/File.h" #include "utils/URIUtils.h" #include "ServiceBroker.h" -#include "addons/InputStream.h" -#include "addons/BinaryAddonCache.h" +#include "addons/binary-addons/BinaryAddonManager.h" #include "Util.h" CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer, const CFileItem &fileitem, bool scanforextaudio) { + using namespace ADDON; + std::string file = fileitem.GetPath(); if (scanforextaudio) { @@ -61,28 +62,12 @@ CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer } } - ADDON::VECADDONS addons; - ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); - addonCache.GetAddons(addons, ADDON::ADDON_INPUTSTREAM); - for (size_t i=0; i<addons.size(); ++i) + BinaryAddonBaseList addonInfos; + CServiceBroker::GetBinaryAddonManager().GetAddonInfos(addonInfos, true /*enabled only*/, ADDON_INPUTSTREAM); + for (auto addonInfo : addonInfos) { - std::shared_ptr<ADDON::CInputStream> input(std::static_pointer_cast<ADDON::CInputStream>(addons[i])); - - if (input->Supports(fileitem)) - { - std::shared_ptr<ADDON::CInputStream> addon = input; - if (!input->UseParent()) - addon = std::shared_ptr<ADDON::CInputStream>(new ADDON::CInputStream(*input)); - - if (addon->Create()) - { - unsigned int videoWidth, videoHeight; - pPlayer->GetVideoResolution(videoWidth, videoHeight); - addon->SetVideoResolution(videoWidth, videoHeight); - - return new CInputStreamAddon(fileitem, addon); - } - } + if (CInputStreamAddon::Supports(addonInfo, fileitem)) + return new CInputStreamAddon(addonInfo, pPlayer, fileitem); } if (fileitem.IsDiscImage()) diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp index 420190341c..05066127a0 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp @@ -20,40 +20,138 @@ #include "InputStreamAddon.h" #include "TimingConstants.h" -#include "addons/InputStream.h" +#include "addons/binary-addons/AddonDll.h" +#include "addons/binary-addons/BinaryAddonBase.h" #include "cores/VideoPlayer/DVDClock.h" - -CInputStreamAddon::CInputStreamAddon(const CFileItem& fileitem, std::shared_ptr<ADDON::CInputStream> inputStream) -: CDVDInputStream(DVDSTREAM_TYPE_ADDON, fileitem), m_addon(inputStream) +#include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" +#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" +#include "filesystem/SpecialProtocol.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" + +using namespace ADDON; + +CInputStreamAddon::CInputStreamAddon(BinaryAddonBasePtr& addonBase, IVideoPlayer* player, const CFileItem& fileitem) + : IAddonInstanceHandler(ADDON_INSTANCE_INPUTSTREAM, addonBase), + CDVDInputStream(DVDSTREAM_TYPE_ADDON, fileitem), + m_player(player) { + std::string listitemprops = addonBase->Type(ADDON_INPUTSTREAM)->GetValue("@listitemprops").asString(); + std::string name(addonBase->ID()); + + m_fileItemProps = StringUtils::Tokenize(listitemprops, "|"); + for (auto &key : m_fileItemProps) + { + StringUtils::Trim(key); + key = name + "." + key; + } + + m_struct = {{ 0 }}; } CInputStreamAddon::~CInputStreamAddon() { Close(); - m_addon.reset(); +} + +bool CInputStreamAddon::Supports(BinaryAddonBasePtr& addonBase, const CFileItem &fileitem) +{ + // check if a specific inputstream addon is requested + CVariant addon = fileitem.GetProperty("inputstreamaddon"); + if (!addon.isNull()) + return (addon.asString() == addonBase->ID()); + + // check protocols + std::string protocol = fileitem.GetURL().GetProtocol(); + if (!protocol.empty()) + { + std::string protocols = addonBase->Type(ADDON_INPUTSTREAM)->GetValue("@protocols").asString(); + if (!protocols.empty()) + { + std::vector<std::string> protocolsList = StringUtils::Tokenize(protocols, "|"); + for (auto& value : protocolsList) + { + StringUtils::Trim(value); + if (value == protocol) + return true; + } + } + } + + std::string filetype = fileitem.GetURL().GetFileType(); + if (!filetype.empty()) + { + std::string extensions = addonBase->Type(ADDON_INPUTSTREAM)->GetValue("@extension").asString(); + if (!extensions.empty()) + { + std::vector<std::string> extensionsList = StringUtils::Tokenize(extensions, "|"); + for (auto& value : extensionsList) + { + StringUtils::Trim(value); + if (value == filetype) + return true; + } + } + } + + return false; } bool CInputStreamAddon::Open() { - bool ret = false; - if (m_addon) - ret = m_addon->Open(m_item); + m_struct.toKodi.kodiInstance = this; + m_struct.toKodi.free_demux_packet = cb_free_demux_packet; + m_struct.toKodi.allocate_demux_packet = cb_allocate_demux_packet; + if (!CreateInstance(&m_struct) || !m_struct.toAddon.open) + return false; + + INPUTSTREAM props; + std::map<std::string, std::string> propsMap; + for (auto &key : m_fileItemProps) + { + if (m_item.GetProperty(key).isNull()) + continue; + propsMap[key] = m_item.GetProperty(key).asString(); + } + + props.m_nCountInfoValues = 0; + for (auto &pair : propsMap) + { + props.m_ListItemProperties[props.m_nCountInfoValues].m_strKey = pair.first.c_str(); + props.m_ListItemProperties[props.m_nCountInfoValues].m_strValue = pair.second.c_str(); + props.m_nCountInfoValues++; + } + + props.m_strURL = m_item.GetPath().c_str(); + + std::string libFolder = URIUtils::GetDirectory(Addon()->Path()); + std::string profileFolder = CSpecialProtocol::TranslatePath(Addon()->Profile()); + props.m_libFolder = libFolder.c_str(); + props.m_profileFolder = profileFolder.c_str(); + + unsigned int videoWidth = 1280; + unsigned int videoHeight = 720; + if (m_player) + m_player->GetVideoResolution(videoWidth, videoHeight); + SetVideoResolution(videoWidth, videoHeight); + + bool ret = m_struct.toAddon.open(&m_struct, &props); if (ret) { - m_hasDemux = m_addon->HasDemux(); - m_hasDisplayTime = m_addon->HasDisplayTime(); - m_hasPosTime = m_addon->HasPosTime(); - m_canPause = m_addon->CanPause(); - m_canSeek = m_addon->CanSeek(); + memset(&m_caps, 0, sizeof(m_caps)); + m_struct.toAddon.get_capabilities(&m_struct, &m_caps); } + + UpdateStreams(); return ret; } void CInputStreamAddon::Close() { - if (m_addon) - return m_addon->Close(); + if (m_struct.toAddon.close) + m_struct.toAddon.close(&m_struct); + DestroyInstance(); + m_struct = {{ 0 }}; } bool CInputStreamAddon::IsEOF() @@ -63,53 +161,58 @@ bool CInputStreamAddon::IsEOF() int CInputStreamAddon::Read(uint8_t* buf, int buf_size) { - if (!m_addon) + if (!m_struct.toAddon.read_stream) return -1; - return m_addon->ReadStream(buf, buf_size); + return m_struct.toAddon.read_stream(&m_struct, buf, buf_size); } int64_t CInputStreamAddon::Seek(int64_t offset, int whence) { - if (!m_addon) + if (!m_struct.toAddon.seek_stream) return -1; - return m_addon->SeekStream(offset, whence); + return m_struct.toAddon.seek_stream(&m_struct, offset, whence); } +int64_t CInputStreamAddon::PositionStream() +{ + if (!m_struct.toAddon.position_stream) + return -1; + + return m_struct.toAddon.position_stream(&m_struct); +} int64_t CInputStreamAddon::GetLength() { - if (!m_addon) + if (!m_struct.toAddon.length_stream) return -1; - return m_addon->LengthStream(); + return m_struct.toAddon.length_stream(&m_struct); } -bool CInputStreamAddon::Pause(double dTime) +bool CInputStreamAddon::Pause(double time) { - if (!m_addon) + if (!m_struct.toAddon.pause_stream) return false; - m_addon->PauseStream(dTime); + m_struct.toAddon.pause_stream(&m_struct, time); return true; } bool CInputStreamAddon::CanSeek() { - return m_canSeek; + return (m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_SEEK) != 0; } bool CInputStreamAddon::CanPause() { - return m_canPause; + return (m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_PAUSE) != 0; } // IDisplayTime CDVDInputStream::IDisplayTime* CInputStreamAddon::GetIDisplayTime() { - if (!m_addon) - return nullptr; - if (!m_hasDisplayTime) + if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_IDISPLAYTIME) == 0) return nullptr; return this; @@ -117,26 +220,24 @@ CDVDInputStream::IDisplayTime* CInputStreamAddon::GetIDisplayTime() int CInputStreamAddon::GetTotalTime() { - if (!m_addon) + if (!m_struct.toAddon.get_total_time) return 0; - return m_addon->GetTotalTime(); + return m_struct.toAddon.get_total_time(&m_struct); } int CInputStreamAddon::GetTime() { - if (!m_addon) + if (!m_struct.toAddon.get_time) return 0; - return m_addon->GetTime(); + return m_struct.toAddon.get_time(&m_struct); } // IPosTime CDVDInputStream::IPosTime* CInputStreamAddon::GetIPosTime() { - if (!m_addon) - return nullptr; - if (!m_hasPosTime) + if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_IPOSTIME) == 0) return nullptr; return this; @@ -144,18 +245,16 @@ CDVDInputStream::IPosTime* CInputStreamAddon::GetIPosTime() bool CInputStreamAddon::PosTime(int ms) { - if (!m_addon) + if (!m_struct.toAddon.pos_time) return false; - return m_addon->PosTime(ms); + return m_struct.toAddon.pos_time(&m_struct, ms); } // IDemux CDVDInputStream::IDemux* CInputStreamAddon::GetIDemux() { - if (!m_addon) - return nullptr; - if (!m_hasDemux) + if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_IDEMUX) == 0) return nullptr; return this; @@ -163,7 +262,7 @@ CDVDInputStream::IDemux* CInputStreamAddon::GetIDemux() bool CInputStreamAddon::OpenDemux() { - if (m_hasDemux) + if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_IDEMUX) != 0) return true; else return false; @@ -171,61 +270,77 @@ bool CInputStreamAddon::OpenDemux() DemuxPacket* CInputStreamAddon::ReadDemux() { - if (!m_addon) + if (!m_struct.toAddon.demux_read) + return nullptr; + + DemuxPacket* pPacket = m_struct.toAddon.demux_read(&m_struct); + + if (!pPacket) + { return nullptr; + } + else if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO) + { + UpdateStreams(); + } + else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE) + { + UpdateStreams(); + } - return m_addon->ReadDemux(); + return pPacket; } std::vector<CDemuxStream*> CInputStreamAddon::GetStreams() const { std::vector<CDemuxStream*> streams; - if (!m_addon) - return streams; + for (auto stream : m_streams) + streams.push_back(stream.second); - return m_addon->GetStreams(); + return streams; } -CDemuxStream* CInputStreamAddon::GetStream(int iStreamId) const +CDemuxStream* CInputStreamAddon::GetStream(int streamId) const { - if (!m_addon) - return nullptr; + auto stream = m_streams.find(streamId); + if (stream != m_streams.end()) + return stream->second; - return m_addon->GetStream(iStreamId); + return nullptr; } -void CInputStreamAddon::EnableStream(int iStreamId, bool enable) +void CInputStreamAddon::EnableStream(int streamId, bool enable) { - if (!m_addon) + if (!m_struct.toAddon.enable_stream) return; - return m_addon->EnableStream(iStreamId, enable); + auto stream = m_streams.find(streamId); + if (stream == m_streams.end()) + return; + + m_struct.toAddon.enable_stream(&m_struct, stream->second->uniqueId, enable); } int CInputStreamAddon::GetNrOfStreams() const { - if (!m_addon) - return 0; - - int count = m_addon->GetNrOfStreams(); - return count; + return m_streams.size(); } -void CInputStreamAddon::SetSpeed(int iSpeed) +void CInputStreamAddon::SetSpeed(int speed) { - if (!m_addon) + if (!m_struct.toAddon.demux_set_speed) return; - m_addon->SetSpeed(iSpeed); + m_struct.toAddon.demux_set_speed(&m_struct, speed); } bool CInputStreamAddon::SeekTime(double time, bool backward, double* startpts) { - if (!m_addon) + if (!m_struct.toAddon.demux_seek_time) return false; - if (m_hasPosTime) + if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_IPOSTIME) != 0) { if (!PosTime(static_cast<int>(time))) return false; @@ -237,29 +352,129 @@ bool CInputStreamAddon::SeekTime(double time, bool backward, double* startpts) return true; } - return m_addon->SeekTime(time, backward, startpts); + return m_struct.toAddon.demux_seek_time(&m_struct, time, backward, startpts); } void CInputStreamAddon::AbortDemux() { - if (!m_addon) - return; - - m_addon->AbortDemux(); + if (m_struct.toAddon.demux_abort) + m_struct.toAddon.demux_abort(&m_struct); } void CInputStreamAddon::FlushDemux() { - if (!m_addon) - return; - - m_addon->FlushDemux(); + if (m_struct.toAddon.demux_flush) + m_struct.toAddon.demux_flush(&m_struct); } void CInputStreamAddon::SetVideoResolution(int width, int height) { - if (!m_addon) + if (m_struct.toAddon.set_video_resolution) + m_struct.toAddon.set_video_resolution(&m_struct, width, height); +} + +bool CInputStreamAddon::IsRealTimeStream() +{ + if (m_struct.toAddon.is_real_time_stream) + return m_struct.toAddon.is_real_time_stream(&m_struct); + return false; +} + +void CInputStreamAddon::UpdateStreams() +{ + DisposeStreams(); + + INPUTSTREAM_IDS streamIDs = m_struct.toAddon.get_stream_ids(&m_struct); + if (streamIDs.m_streamCount > INPUTSTREAM_IDS::MAX_STREAM_COUNT) + { + DisposeStreams(); return; + } + + for (unsigned int i = 0; i < streamIDs.m_streamCount; ++i) + { + INPUTSTREAM_INFO stream = m_struct.toAddon.get_stream(&m_struct, streamIDs.m_streamIds[i]); + if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_NONE) + continue; + + std::string codecName(stream.m_codecName); + StringUtils::ToLower(codecName); + AVCodec *codec = avcodec_find_decoder_by_name(codecName.c_str()); + if (!codec) + continue; + + CDemuxStream *demuxStream; + + if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_AUDIO) + { + CDemuxStreamAudio *audioStream = new CDemuxStreamAudio(); + + audioStream->iChannels = stream.m_Channels; + audioStream->iSampleRate = stream.m_SampleRate; + audioStream->iBlockAlign = stream.m_BlockAlign; + audioStream->iBitRate = stream.m_BitRate; + audioStream->iBitsPerSample = stream.m_BitsPerSample; + demuxStream = audioStream; + } + else if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_VIDEO) + { + CDemuxStreamVideo *videoStream = new CDemuxStreamVideo(); + + videoStream->iFpsScale = stream.m_FpsScale; + videoStream->iFpsRate = stream.m_FpsRate; + videoStream->iWidth = stream.m_Width; + videoStream->iHeight = stream.m_Height; + videoStream->fAspect = stream.m_Aspect; + videoStream->stereo_mode = "mono"; + videoStream->iBitRate = stream.m_BitRate; + demuxStream = videoStream; + } + else if (stream.m_streamType == INPUTSTREAM_INFO::TYPE_SUBTITLE) + { + CDemuxStreamSubtitle *subtitleStream = new CDemuxStreamSubtitle(); + demuxStream = subtitleStream; + } + else + continue; + + demuxStream->codec = codec->id; + demuxStream->codecName = stream.m_codecInternalName; + demuxStream->uniqueId = streamIDs.m_streamIds[i]; + demuxStream->language[0] = stream.m_language[0]; + demuxStream->language[1] = stream.m_language[1]; + demuxStream->language[2] = stream.m_language[2]; + demuxStream->language[3] = stream.m_language[3]; + + if (stream.m_ExtraData && stream.m_ExtraSize) + { + demuxStream->ExtraData = new uint8_t[stream.m_ExtraSize]; + demuxStream->ExtraSize = stream.m_ExtraSize; + for (unsigned int j = 0; j < stream.m_ExtraSize; ++j) + demuxStream->ExtraData[j] = stream.m_ExtraData[j]; + } + + m_streams[demuxStream->uniqueId] = demuxStream; + } +} - m_addon->SetVideoResolution(width, height); +void CInputStreamAddon::DisposeStreams() +{ + for (auto &stream : m_streams) + delete stream.second; + m_streams.clear(); +} + +/*! + * Callbacks from add-on to kodi + */ +//@{ +DemuxPacket* CInputStreamAddon::cb_allocate_demux_packet(void* kodiInstance, int data_size) +{ + return CDVDDemuxUtils::AllocateDemuxPacket(data_size); +} + +void CInputStreamAddon::cb_free_demux_packet(void* kodiInstance, DemuxPacket* packet) +{ + CDVDDemuxUtils::FreeDemuxPacket(packet); } +//@} diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h index 04c5b4c557..f893b5cc0d 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h @@ -24,45 +24,35 @@ #include <vector> #include "DVDInputStream.h" -#include "addons/InputStream.h" +#include "IVideoPlayer.h" +#include "addons/binary-addons/AddonInstanceHandler.h" +#include "addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h" //! \brief Input stream class -class CInputStreamAddon : - public CDVDInputStream, - public CDVDInputStream::IDisplayTime, - public CDVDInputStream::IPosTime, - public CDVDInputStream::IDemux +class CInputStreamAddon + : public ADDON::IAddonInstanceHandler, + public CDVDInputStream, + public CDVDInputStream::IDisplayTime, + public CDVDInputStream::IPosTime, + public CDVDInputStream::IDemux { public: - //! \brief constructor - CInputStreamAddon(const CFileItem& fileitem, std::shared_ptr<ADDON::CInputStream> inputStream); - - //! \brief Destructor. + CInputStreamAddon(ADDON::BinaryAddonBasePtr& addonBase, IVideoPlayer* player, const CFileItem& fileitem); virtual ~CInputStreamAddon(); - //! \brief Open a MPD file - virtual bool Open() override; + static bool Supports(ADDON::BinaryAddonBasePtr& addonBase, const CFileItem& fileitem); - //! \brief Close input stream + // CDVDInputStream + virtual bool Open() override; virtual void Close() override; - - //! \brief Read data from stream virtual int Read(uint8_t* buf, int buf_size) override; - - //! \brief Seek in stream virtual int64_t Seek(int64_t offset, int whence) override; - - //! \brief Pause stream virtual bool Pause(double dTime) override; - //! \brief Return true if we have reached EOF + virtual int64_t GetLength() override; virtual bool IsEOF() override; - virtual bool CanSeek() override; virtual bool CanPause() override; - //! \brief Get length of input data - virtual int64_t GetLength() override; - // IDisplayTime virtual CDVDInputStream::IDisplayTime* GetIDisplayTime() override; virtual int GetTotalTime() override; @@ -72,25 +62,52 @@ public: virtual CDVDInputStream::IPosTime* GetIPosTime() override; virtual bool PosTime(int ms) override; - //IDemux + // IDemux CDVDInputStream::IDemux* GetIDemux() override; virtual bool OpenDemux() override; virtual DemuxPacket* ReadDemux() override; - virtual CDemuxStream* GetStream(int iStreamId) const override; + virtual CDemuxStream* GetStream(int streamId) const override; virtual std::vector<CDemuxStream*> GetStreams() const override; - virtual void EnableStream(int iStreamId, bool enable) override; + virtual void EnableStream(int streamId, bool enable) override; virtual int GetNrOfStreams() const override; - virtual void SetSpeed(int iSpeed) override; - virtual bool SeekTime(double time, bool backward = false, double* startpts = NULL) override; + virtual void SetSpeed(int speed) override; + virtual bool SeekTime(double time, bool backward = false, double* startpts = nullptr) override; virtual void AbortDemux() override; virtual void FlushDemux() override; virtual void SetVideoResolution(int width, int height) override; + int64_t PositionStream(); + bool IsRealTimeStream(); protected: - std::shared_ptr<ADDON::CInputStream> m_addon; - bool m_hasDemux = false; - bool m_hasDisplayTime = false; - bool m_hasPosTime = false; - bool m_canPause = false; - bool m_canSeek = false; + void UpdateStreams(); + void DisposeStreams(); + + IVideoPlayer* m_player; + +private: + std::vector<std::string> m_fileItemProps; + INPUTSTREAM_CAPABILITIES m_caps; + std::map<int, CDemuxStream*> m_streams; + + AddonInstance_InputStream m_struct; + + /*! + * Callbacks from add-on to kodi + */ + //@{ + /*! + * @brief Allocate a demux packet. Free with FreeDemuxPacket + * @param kodiInstance A pointer to the add-on. + * @param iDataSize The size of the data that will go into the packet + * @return The allocated packet. + */ + static DemuxPacket* cb_allocate_demux_packet(void* kodiInstance, int iDataSize = 0); + + /*! + * @brief Free a packet that was allocated with AllocateDemuxPacket + * @param kodiInstance A pointer to the add-on. + * @param pPacket The packet to free. + */ + static void cb_free_demux_packet(void* kodiInstance, DemuxPacket* pPacket); + //@} }; |