diff options
author | Lars Op den Kamp <lars@opdenkamp.eu> | 2014-01-04 02:13:35 +0100 |
---|---|---|
committer | Lars Op den Kamp <lars@opdenkamp.eu> | 2014-01-04 02:13:46 +0100 |
commit | afff71d9dfea10604287a88f2e2f9f658d6f8c69 (patch) | |
tree | b1e946b065f7e3c52a8221086fee808d7cfb92f1 | |
parent | a101ca5098a4af7dc2ba5c06e1663f1a74ae75f8 (diff) |
[PVR] sync xbmc_stream_utils.hpp
-rw-r--r-- | xbmc/addons/include/xbmc_stream_utils.hpp | 321 |
1 files changed, 187 insertions, 134 deletions
diff --git a/xbmc/addons/include/xbmc_stream_utils.hpp b/xbmc/addons/include/xbmc_stream_utils.hpp index 5de81ced5f..927fe335d8 100644 --- a/xbmc/addons/include/xbmc_stream_utils.hpp +++ b/xbmc/addons/include/xbmc_stream_utils.hpp @@ -20,192 +20,245 @@ */ #include "xbmc_pvr_types.h" +#include <algorithm> #include <map> namespace ADDON { - class XbmcStreamProperties + /** + * Represents a single stream. It extends the PODS to provide some operators + * overloads. + */ + class XbmcPvrStream : public PVR_STREAM_PROPERTIES::PVR_STREAM { public: - XbmcStreamProperties(void) + XbmcPvrStream() { Clear(); } - - virtual ~XbmcStreamProperties(void) + + XbmcPvrStream(const XbmcPvrStream &other) { + memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } - - int GetStreamId(unsigned int iPhysicalId) + + XbmcPvrStream& operator=(const XbmcPvrStream &other) { - std::map<unsigned int, unsigned int>::iterator it = m_streamIndex.find(iPhysicalId); - if (it != m_streamIndex.end()) - return it->second; - return -1; + memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); + return *this; + } + + /** + * Compares this stream based on another stream + * @param other + * @return + */ + inline bool operator==(const XbmcPvrStream &other) const + { + return iPhysicalId == other.iPhysicalId && iCodecId == other.iCodecId; } - void GetStreamData(unsigned int iPhysicalId, PVR_STREAM_PROPERTIES::PVR_STREAM* stream) + /** + * Compares this stream with another one so that video streams are sorted + * before any other streams and the others are sorted by the physical ID + * @param other + * @return + */ + bool operator<(const XbmcPvrStream &other) const { - std::map<unsigned int, unsigned int>::iterator it = m_streamIndex.find(iPhysicalId); - if (it != m_streamIndex.end()) - { - memcpy(stream, &m_streams.stream[it->second], sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - } + if (iCodecType == XBMC_CODEC_TYPE_VIDEO) + return true; + else if (other.iCodecType != XBMC_CODEC_TYPE_VIDEO) + return iPhysicalId < other.iPhysicalId; else - { - memset(stream, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - stream->iIdentifier = -1; - stream->iPhysicalId = iPhysicalId; - } + return false; } - - PVR_STREAM_PROPERTIES::PVR_STREAM* GetStreamById(unsigned int iPhysicalId) + + /** + * Clears the stream + */ + void Clear() { - std::map<unsigned int, unsigned int>::iterator it = m_streamIndex.find(iPhysicalId); - if (it != m_streamIndex.end()) - return &m_streams.stream[it->second]; - return NULL; + memset(this, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); + iCodecId = XBMC_INVALID_CODEC_ID; + iCodecType = XBMC_CODEC_TYPE_UNKNOWN; } - - bool GetProperties(PVR_STREAM_PROPERTIES* props) const + + /** + * Checks whether the stream has been cleared + * @return + */ + inline bool IsCleared() const { - props->iStreamCount = m_streams.iStreamCount; - for (unsigned int i = 0; i < m_streams.iStreamCount; i++) - { - props->stream[i].iPhysicalId = m_streams.stream[i].iPhysicalId; - props->stream[i].iCodecType = m_streams.stream[i].iCodecType; - props->stream[i].iCodecId = m_streams.stream[i].iCodecId; - props->stream[i].strLanguage[0] = m_streams.stream[i].strLanguage[0]; - props->stream[i].strLanguage[1] = m_streams.stream[i].strLanguage[1]; - props->stream[i].strLanguage[2] = m_streams.stream[i].strLanguage[2]; - props->stream[i].strLanguage[3] = m_streams.stream[i].strLanguage[3]; - props->stream[i].iIdentifier = m_streams.stream[i].iIdentifier; - props->stream[i].iFPSScale = m_streams.stream[i].iFPSScale; - props->stream[i].iFPSRate = m_streams.stream[i].iFPSRate; - props->stream[i].iHeight = m_streams.stream[i].iHeight; - props->stream[i].iWidth = m_streams.stream[i].iWidth; - props->stream[i].fAspect = m_streams.stream[i].fAspect; - props->stream[i].iChannels = m_streams.stream[i].iChannels; - props->stream[i].iSampleRate = m_streams.stream[i].iSampleRate; - props->stream[i].iBlockAlign = m_streams.stream[i].iBlockAlign; - props->stream[i].iBitRate = m_streams.stream[i].iBitRate; - props->stream[i].iBitsPerSample = m_streams.stream[i].iBitsPerSample; - } - - return (props->iStreamCount > 0); + return iCodecId == XBMC_INVALID_CODEC_ID && + iCodecType == XBMC_CODEC_TYPE_UNKNOWN; } - - void Clear(void) + }; + + class XbmcStreamProperties + { + public: + typedef std::vector<XbmcPvrStream> stream_vector; + + XbmcStreamProperties(void) { - memset(&m_streams, 0, sizeof(PVR_STREAM_PROPERTIES)); - for (unsigned int i = 0; i < PVR_STREAM_MAX_STREAMS; i++) - m_streams.stream[i].iCodecType = XBMC_CODEC_TYPE_UNKNOWN; + // make sure the vector won't have to resize itself later + m_streamVector = new stream_vector(); + m_streamVector->reserve(PVR_STREAM_MAX_STREAMS); } - unsigned int NextFreeIndex(void) + virtual ~XbmcStreamProperties(void) { - unsigned int i; - for (i = 0; i < PVR_STREAM_MAX_STREAMS; i++) - { - if (m_streams.stream[i].iCodecType == XBMC_CODEC_TYPE_UNKNOWN) - break; - } - return i; + delete m_streamVector; } - - static std::map<unsigned int, unsigned int> CreateIndex(PVR_STREAM_PROPERTIES streams) + + /** + * Resets the streams + */ + void Clear(void) { - std::map<unsigned int, unsigned int> retval; - for (unsigned int i = 0; i < PVR_STREAM_MAX_STREAMS && i < streams.iStreamCount; i++) - retval.insert(std::make_pair(streams.stream[i].iPhysicalId, i)); - return retval; + m_streamVector->clear(); + m_streamIndex.clear(); } - static std::map<unsigned int, unsigned int> CreateIndex(const std::vector<PVR_STREAM_PROPERTIES::PVR_STREAM>& streams) + /** + * Returns the index of the stream with the specified physical ID, or -1 if + * there no stream is found. This method is called very often which is why + * we keep a separate map for this. + * @param iPhysicalId + * @return + */ + int GetStreamId(unsigned int iPhysicalId) const { - std::map<unsigned int, unsigned int> retval; - for (unsigned int i = 0; i < PVR_STREAM_MAX_STREAMS && i < streams.size(); i++) - retval.insert(std::make_pair(streams.at(i).iPhysicalId, i)); - return retval; - } + std::map<unsigned int, int>::const_iterator it = m_streamIndex.find(iPhysicalId); + if (it != m_streamIndex.end()) + return it->second; - static void ClearStream(PVR_STREAM_PROPERTIES::PVR_STREAM* stream) + return -1; + } + + /** + * Returns the stream with the specified physical ID, or null if no such + * stream exists + * @param iPhysicalId + * @return + */ + XbmcPvrStream* GetStreamById(unsigned int iPhysicalId) const { - memset(stream, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - stream->iCodecType = XBMC_CODEC_TYPE_UNKNOWN; - stream->iCodecId = XBMC_INVALID_CODEC_ID; + int position = GetStreamId(iPhysicalId); + return position != -1 ? &m_streamVector->at(position) : NULL; } - void UpdateStreams(const std::vector<PVR_STREAM_PROPERTIES::PVR_STREAM>& newStreams) + /** + * Populates the specified stream with the stream having the specified + * physical ID. If the stream is not found only target stream's physical ID + * will be populated. + * @param iPhysicalId + * @param stream + */ + void GetStreamData(unsigned int iPhysicalId, XbmcPvrStream* stream) { - std::map<unsigned int, unsigned int> newIndex = CreateIndex(newStreams); - - // delete streams we don't have in newStreams - std::map<unsigned int, unsigned int>::iterator ito = m_streamIndex.begin(); - std::map<unsigned int, unsigned int>::iterator itn; - while (ito != m_streamIndex.end()) + XbmcPvrStream *foundStream = GetStreamById(iPhysicalId); + if (foundStream) + stream = foundStream; + else { - itn = newIndex.find(ito->first); - if (itn == newIndex.end()) - { - memset(&m_streams.stream[ito->second], 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - m_streams.stream[ito->second].iCodecType = XBMC_CODEC_TYPE_UNKNOWN; - m_streams.stream[ito->second].iCodecId = XBMC_INVALID_CODEC_ID; - m_streamIndex.erase(ito); - ito = m_streamIndex.begin(); - } - else - ++ito; + stream->iIdentifier = -1; + stream->iPhysicalId = iPhysicalId; } + } - // copy known streams - for (ito = m_streamIndex.begin(); ito != m_streamIndex.end(); ++ito) + /** + * Populates props with the current streams and returns whether there are + * any streams at the moment or not. + * @param props + * @return + */ + bool GetProperties(PVR_STREAM_PROPERTIES* props) + { + unsigned int i = 0; + for (stream_vector::const_iterator it = m_streamVector->begin(); + it != m_streamVector->end(); ++it, ++i) { - itn = newIndex.find(ito->first); - memcpy(&m_streams.stream[ito->second], &newStreams.at(itn->second), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - newIndex.erase(itn); + memcpy(&props->stream[i], &(*it), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } + + props->iStreamCount = m_streamVector->size(); + return (props->iStreamCount > 0); + } - // place video stream at pos 0 - for (itn = newIndex.begin(); itn != newIndex.end(); ++itn) + /** + * Merges new streams into the current list of streams. Identical streams + * will retain their respective indexes and new streams will replace unused + * indexes or be appended. + * @param newStreams + */ + void UpdateStreams(stream_vector &newStreams) + { + // sort the new streams + std::sort(newStreams.begin(), newStreams.end()); + + // ensure we never have more than PVR_STREAMS_MAX_STREAMS streams + if (newStreams.size() > PVR_STREAM_MAX_STREAMS) + { + while (newStreams.size() > PVR_STREAM_MAX_STREAMS) + newStreams.pop_back(); + + XBMC->Log(LOG_ERROR, "%s - max amount of streams reached", __FUNCTION__); + } + + stream_vector::iterator newStreamPosition; + for (stream_vector::iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it) { - if (newStreams.at(itn->second).iCodecType == XBMC_CODEC_TYPE_VIDEO) + newStreamPosition = std::find(newStreams.begin(), newStreams.end(), *it); + + // if the current stream no longer exists we clear it, otherwise we + // copy it and remove it from newStreams + if (newStreamPosition == newStreams.end()) + it->Clear(); + else { - m_streamIndex[itn->first] = 0; - memcpy(&m_streams.stream[0], &newStreams.at(itn->second), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - newIndex.erase(itn); - break; + *it = *newStreamPosition; + newStreams.erase(newStreamPosition); } } - // fill the gaps or append after highest index - while (!newIndex.empty()) + // replace cleared streams with new streams + for (stream_vector::iterator it = m_streamVector->begin(); + it != m_streamVector->end() && !newStreams.empty(); ++it) { - // find first unused index - unsigned int i = NextFreeIndex(); - itn = newIndex.begin(); - m_streamIndex[itn->first] = i; - memcpy(&m_streams.stream[i], &newStreams.at(itn->second), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); - newIndex.erase(itn); + if (it->IsCleared()) + { + *it = newStreams.front(); + newStreams.erase(newStreams.begin()); + } } - // set streamCount - m_streams.iStreamCount = 0; - for (ito = m_streamIndex.begin(); ito != m_streamIndex.end(); ++ito) - { - if (ito->second > m_streams.iStreamCount) - m_streams.iStreamCount = ito->second; - } - if (!m_streamIndex.empty()) - m_streams.iStreamCount++; + // append any remaining new streams + m_streamVector->insert(m_streamVector->end(), newStreams.begin(), newStreams.end()); + + // remove trailing cleared streams + while (m_streamVector->back().IsCleared()) + m_streamVector->pop_back(); + + // update the index + UpdateIndex(); } - size_t Size(void) const + private: + stream_vector *m_streamVector; + std::map<unsigned int, int> m_streamIndex; + + /** + * Updates the stream index + */ + void UpdateIndex() { - return m_streamIndex.size(); + m_streamIndex.clear(); + + int i = 0; + for (stream_vector::const_iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it, ++i) + m_streamIndex[it->iPhysicalId] = i; } - - std::map<unsigned int, unsigned int> m_streamIndex; - PVR_STREAM_PROPERTIES m_streams; }; } |