#pragma once /* * Copyright (C) 2005-2013 Team XBMC * http://xbmc.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XBMC; see the file COPYING. If not, see * . * */ #include "xbmc_pvr_types.h" #include #include namespace ADDON { /** * Represents a single stream. It extends the PODS to provide some operators * overloads. */ class XbmcPvrStream : public PVR_STREAM_PROPERTIES::PVR_STREAM { public: XbmcPvrStream() { Clear(); } XbmcPvrStream(const XbmcPvrStream &other) { memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } XbmcPvrStream& operator=(const XbmcPvrStream &other) { 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; } /** * 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 { if (iCodecType == XBMC_CODEC_TYPE_VIDEO) return true; else if (other.iCodecType != XBMC_CODEC_TYPE_VIDEO) return iPhysicalId < other.iPhysicalId; else return false; } /** * Clears the stream */ void Clear() { memset(this, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); iCodecId = XBMC_INVALID_CODEC_ID; iCodecType = XBMC_CODEC_TYPE_UNKNOWN; } /** * Checks whether the stream has been cleared * @return */ inline bool IsCleared() const { return iCodecId == XBMC_INVALID_CODEC_ID && iCodecType == XBMC_CODEC_TYPE_UNKNOWN; } }; class XbmcStreamProperties { public: typedef std::vector stream_vector; XbmcStreamProperties(void) { // make sure the vector won't have to resize itself later m_streamVector = new stream_vector(); m_streamVector->reserve(PVR_STREAM_MAX_STREAMS); } virtual ~XbmcStreamProperties(void) { delete m_streamVector; } /** * Resets the streams */ void Clear(void) { m_streamVector->clear(); m_streamIndex.clear(); } /** * 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::const_iterator it = m_streamIndex.find(iPhysicalId); if (it != m_streamIndex.end()) return it->second; 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 { int position = GetStreamId(iPhysicalId); return position != -1 ? &m_streamVector->at(position) : NULL; } /** * 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) { XbmcPvrStream *foundStream = GetStreamById(iPhysicalId); if (foundStream) stream = foundStream; else { stream->iIdentifier = -1; stream->iPhysicalId = iPhysicalId; } } /** * 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) { memcpy(&props->stream[i], &(*it), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM)); } props->iStreamCount = m_streamVector->size(); return (props->iStreamCount > 0); } /** * 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) { 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 { *it = *newStreamPosition; newStreams.erase(newStreamPosition); } } // replace cleared streams with new streams for (stream_vector::iterator it = m_streamVector->begin(); it != m_streamVector->end() && !newStreams.empty(); ++it) { if (it->IsCleared()) { *it = newStreams.front(); newStreams.erase(newStreams.begin()); } } // 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(); } private: stream_vector *m_streamVector; std::map m_streamIndex; /** * Updates the stream index */ void UpdateIndex() { 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; } }; }