Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / xbmc / addons / include / xbmc_stream_utils.hpp
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 }