diff options
Diffstat (limited to 'xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_stream_utils.hpp')
| -rw-r--r-- | xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_stream_utils.hpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_stream_utils.hpp b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_stream_utils.hpp new file mode 100644 index 0000000..099776a --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_stream_utils.hpp | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | #pragma once | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2005-2013 Team XBMC | ||
| 4 | * http://xbmc.org | ||
| 5 | * | ||
| 6 | * This Program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This Program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with XBMC; see the file COPYING. If not, see | ||
| 18 | * <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "xbmc_pvr_types.h" | ||
| 23 | #include <algorithm> | ||
| 24 | #include <map> | ||
| 25 | |||
| 26 | namespace ADDON | ||
| 27 | { | ||
| 28 | /** | ||
| 29 | * Represents a single stream. It extends the PODS to provide some operators | ||
| 30 | * overloads. | ||
| 31 | */ | ||
| 32 | class XbmcPvrStream : public PVR_STREAM_PROPERTIES::PVR_STREAM | ||
| 33 | { | ||
| 34 | public: | ||
| 35 | XbmcPvrStream() | ||
| 36 | { | ||
| 37 | Clear(); | ||
| 38 | } | ||
| 39 | |||
| 40 | XbmcPvrStream(const XbmcPvrStream &other) | ||
| 41 | { | ||
| 42 | memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); | ||
| 43 | } | ||
| 44 | |||
| 45 | XbmcPvrStream& operator=(const XbmcPvrStream &other) | ||
| 46 | { | ||
| 47 | memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); | ||
| 48 | return *this; | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Compares this stream based on another stream | ||
| 53 | * @param other | ||
| 54 | * @return | ||
| 55 | */ | ||
| 56 | inline bool operator==(const XbmcPvrStream &other) const | ||
| 57 | { | ||
| 58 | return iPhysicalId == other.iPhysicalId && iCodecId == other.iCodecId; | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Compares this stream with another one so that video streams are sorted | ||
| 63 | * before any other streams and the others are sorted by the physical ID | ||
| 64 | * @param other | ||
| 65 | * @return | ||
| 66 | */ | ||
| 67 | bool operator<(const XbmcPvrStream &other) const | ||
| 68 | { | ||
| 69 | if (iCodecType == XBMC_CODEC_TYPE_VIDEO) | ||
| 70 | return true; | ||
| 71 | else if (other.iCodecType != XBMC_CODEC_TYPE_VIDEO) | ||
| 72 | return iPhysicalId < other.iPhysicalId; | ||
| 73 | else | ||
| 74 | return false; | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Clears the stream | ||
| 79 | */ | ||
| 80 | void Clear() | ||
| 81 | { | ||
| 82 | memset(this, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); | ||
| 83 | iCodecId = XBMC_INVALID_CODEC_ID; | ||
| 84 | iCodecType = XBMC_CODEC_TYPE_UNKNOWN; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Checks whether the stream has been cleared | ||
| 89 | * @return | ||
| 90 | */ | ||
| 91 | inline bool IsCleared() const | ||
| 92 | { | ||
| 93 | return iCodecId == XBMC_INVALID_CODEC_ID && | ||
| 94 | iCodecType == XBMC_CODEC_TYPE_UNKNOWN; | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | |||
| 98 | class XbmcStreamProperties | ||
| 99 | { | ||
| 100 | public: | ||
| 101 | typedef std::vector<XbmcPvrStream> stream_vector; | ||
| 102 | |||
| 103 | XbmcStreamProperties(void) | ||
| 104 | { | ||
| 105 | // make sure the vector won't have to resize itself later | ||
| 106 | m_streamVector = new stream_vector(); | ||
| 107 | m_streamVector->reserve(PVR_STREAM_MAX_STREAMS); | ||
| 108 | } | ||
| 109 | |||
| 110 | virtual ~XbmcStreamProperties(void) | ||
| 111 | { | ||
| 112 | delete m_streamVector; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Resets the streams | ||
| 117 | */ | ||
| 118 | void Clear(void) | ||
| 119 | { | ||
| 120 | m_streamVector->clear(); | ||
| 121 | m_streamIndex.clear(); | ||
| 122 | } | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Returns the index of the stream with the specified physical ID, or -1 if | ||
| 126 | * there no stream is found. This method is called very often which is why | ||
| 127 | * we keep a separate map for this. | ||
| 128 | * @param iPhysicalId | ||
| 129 | * @return | ||
| 130 | */ | ||
| 131 | int GetStreamId(unsigned int iPhysicalId) const | ||
| 132 | { | ||
| 133 | std::map<unsigned int, int>::const_iterator it = m_streamIndex.find(iPhysicalId); | ||
| 134 | if (it != m_streamIndex.end()) | ||
| 135 | return it->second; | ||
| 136 | |||
| 137 | return -1; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Returns the stream with the specified physical ID, or null if no such | ||
| 142 | * stream exists | ||
| 143 | * @param iPhysicalId | ||
| 144 | * @return | ||
| 145 | */ | ||
| 146 | XbmcPvrStream* GetStreamById(unsigned int iPhysicalId) const | ||
| 147 | { | ||
| 148 | int position = GetStreamId(iPhysicalId); | ||
| 149 | return position != -1 ? &m_streamVector->at(position) : NULL; | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Populates the specified stream with the stream having the specified | ||
| 154 | * physical ID. If the stream is not found only target stream's physical ID | ||
| 155 | * will be populated. | ||
| 156 | * @param iPhysicalId | ||
| 157 | * @param stream | ||
| 158 | */ | ||
| 159 | void GetStreamData(unsigned int iPhysicalId, XbmcPvrStream* stream) | ||
| 160 | { | ||
| 161 | XbmcPvrStream *foundStream = GetStreamById(iPhysicalId); | ||
| 162 | if (foundStream) | ||
| 163 | *stream = *foundStream; | ||
| 164 | else | ||
| 165 | { | ||
| 166 | stream->iIdentifier = -1; | ||
| 167 | stream->iPhysicalId = iPhysicalId; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * Populates props with the current streams and returns whether there are | ||
| 173 | * any streams at the moment or not. | ||
| 174 | * @param props | ||
| 175 | * @return | ||
| 176 | */ | ||
| 177 | bool GetProperties(PVR_STREAM_PROPERTIES* props) | ||
| 178 | { | ||
| 179 | unsigned int i = 0; | ||
| 180 | for (stream_vector::const_iterator it = m_streamVector->begin(); | ||
| 181 | it != m_streamVector->end(); ++it, ++i) | ||
| 182 | { | ||
| 183 | memcpy(&props->stream[i], &(*it), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); | ||
| 184 | } | ||
| 185 | |||
| 186 | props->iStreamCount = m_streamVector->size(); | ||
| 187 | return (props->iStreamCount > 0); | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * Merges new streams into the current list of streams. Identical streams | ||
| 192 | * will retain their respective indexes and new streams will replace unused | ||
| 193 | * indexes or be appended. | ||
| 194 | * @param newStreams | ||
| 195 | */ | ||
| 196 | void UpdateStreams(stream_vector &newStreams) | ||
| 197 | { | ||
| 198 | // sort the new streams | ||
| 199 | std::sort(newStreams.begin(), newStreams.end()); | ||
| 200 | |||
| 201 | // ensure we never have more than PVR_STREAMS_MAX_STREAMS streams | ||
| 202 | if (newStreams.size() > PVR_STREAM_MAX_STREAMS) | ||
| 203 | { | ||
| 204 | while (newStreams.size() > PVR_STREAM_MAX_STREAMS) | ||
| 205 | newStreams.pop_back(); | ||
| 206 | |||
| 207 | XBMC->Log(LOG_ERROR, "%s - max amount of streams reached", __FUNCTION__); | ||
| 208 | } | ||
| 209 | |||
| 210 | stream_vector::iterator newStreamPosition; | ||
| 211 | for (stream_vector::iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it) | ||
| 212 | { | ||
| 213 | newStreamPosition = std::find(newStreams.begin(), newStreams.end(), *it); | ||
| 214 | |||
| 215 | // if the current stream no longer exists we clear it, otherwise we | ||
| 216 | // copy it and remove it from newStreams | ||
| 217 | if (newStreamPosition == newStreams.end()) | ||
| 218 | it->Clear(); | ||
| 219 | else | ||
| 220 | { | ||
| 221 | *it = *newStreamPosition; | ||
| 222 | newStreams.erase(newStreamPosition); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | // replace cleared streams with new streams | ||
| 227 | for (stream_vector::iterator it = m_streamVector->begin(); | ||
| 228 | it != m_streamVector->end() && !newStreams.empty(); ++it) | ||
| 229 | { | ||
| 230 | if (it->IsCleared()) | ||
| 231 | { | ||
| 232 | *it = newStreams.front(); | ||
| 233 | newStreams.erase(newStreams.begin()); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | // append any remaining new streams | ||
| 238 | m_streamVector->insert(m_streamVector->end(), newStreams.begin(), newStreams.end()); | ||
| 239 | |||
| 240 | // remove trailing cleared streams | ||
| 241 | while (m_streamVector->back().IsCleared()) | ||
| 242 | m_streamVector->pop_back(); | ||
| 243 | |||
| 244 | // update the index | ||
| 245 | UpdateIndex(); | ||
| 246 | } | ||
| 247 | |||
| 248 | private: | ||
| 249 | stream_vector *m_streamVector; | ||
| 250 | std::map<unsigned int, int> m_streamIndex; | ||
| 251 | |||
| 252 | /** | ||
| 253 | * Updates the stream index | ||
| 254 | */ | ||
| 255 | void UpdateIndex() | ||
| 256 | { | ||
| 257 | m_streamIndex.clear(); | ||
| 258 | |||
| 259 | int i = 0; | ||
| 260 | for (stream_vector::const_iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it, ++i) | ||
| 261 | m_streamIndex[it->iPhysicalId] = i; | ||
| 262 | } | ||
| 263 | }; | ||
| 264 | } | ||
