demux: adaptive: merge toChunk/getChunk
[vlc.git] / modules / demux / adaptive / playlist / Segment.cpp
1 /*
2  * Segment.cpp
3  *****************************************************************************
4  * Copyright (C) 2010 - 2011 Klagenfurt University
5  *
6  * Created on: Aug 10, 2010
7  * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
8  *          Christian Timmerer  <christian.timmerer@itec.uni-klu.ac.at>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published
12  * by the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include "Segment.h"
30 #include "BaseRepresentation.h"
31 #include "AbstractPlaylist.hpp"
32 #include "SegmentChunk.hpp"
33 #include "../http/BytesRange.hpp"
34 #include "../http/HTTPConnectionManager.h"
35 #include "../http/Downloader.hpp"
36 #include <cassert>
37
38 using namespace adaptive::http;
39 using namespace adaptive::playlist;
40
41 const int ISegment::SEQUENCE_INVALID = 0;
42 const int ISegment::SEQUENCE_FIRST   = 1;
43
44 ISegment::ISegment(const ICanonicalUrl *parent):
45     ICanonicalUrl( parent ),
46     startByte  (0),
47     endByte    (0)
48 {
49     debugName = "Segment";
50     classId = CLASSID_ISEGMENT;
51     startTime.Set(0);
52     duration.Set(0);
53     chunksuse.Set(0);
54     sequence = SEQUENCE_INVALID;
55     templated = false;
56     discontinuity = false;
57 }
58
59 ISegment::~ISegment()
60 {
61     assert(chunksuse.Get() == 0);
62 }
63
64 void ISegment::onChunkDownload(block_t **, SegmentChunk *, BaseRepresentation *)
65 {
66
67 }
68
69 SegmentChunk* ISegment::toChunk(size_t index, BaseRepresentation *rep, HTTPConnectionManager *connManager)
70 {
71     const std::string url = getUrlSegment().toString(index, rep);
72     HTTPChunkBufferedSource *source = new (std::nothrow) HTTPChunkBufferedSource(url, connManager);
73     if( source )
74     {
75         if(startByte != endByte)
76             source->setBytesRange(BytesRange(startByte, endByte));
77
78         SegmentChunk *chunk = new (std::nothrow) SegmentChunk(this, source, rep);
79         if( chunk )
80         {
81             connManager->downloader->schedule(source);
82             return chunk;
83         }
84         else
85         {
86             delete source;
87         }
88     }
89     return NULL;
90 }
91
92 bool ISegment::isTemplate() const
93 {
94     return templated;
95 }
96
97 void ISegment::setByteRange(size_t start, size_t end)
98 {
99     startByte = start;
100     endByte   = end;
101 }
102
103 void ISegment::setSequenceNumber(uint64_t seq)
104 {
105     sequence = SEQUENCE_FIRST + seq;
106 }
107
108 uint64_t ISegment::getSequenceNumber() const
109 {
110     return sequence;
111 }
112
113 size_t ISegment::getOffset() const
114 {
115     return startByte;
116 }
117
118 void ISegment::debug(vlc_object_t *obj, int indent) const
119 {
120     std::stringstream ss;
121     ss.imbue(std::locale("C"));
122     ss << std::string(indent, ' ') << debugName << " #" << getSequenceNumber();
123     ss << " url=" << getUrlSegment().toString();
124     if(startByte!=endByte)
125         ss << " @" << startByte << ".." << endByte;
126     if(startTime.Get() > 0)
127          ss << " stime " << startTime.Get();
128     ss << " duration " << duration.Get();
129     msg_Dbg(obj, "%s", ss.str().c_str());
130 }
131
132 bool ISegment::contains(size_t byte) const
133 {
134     if (startByte == endByte)
135         return false;
136     return (byte >= startByte &&
137             (!endByte || byte <= endByte) );
138 }
139
140 int ISegment::compare(ISegment *other) const
141 {
142     if(duration.Get())
143     {
144         stime_t diff = startTime.Get() - other->startTime.Get();
145         if(diff)
146             return diff / diff;
147     }
148
149     size_t diff = startByte - other->startByte;
150     if(diff)
151         return diff / diff;
152
153     diff = endByte - other->endByte;
154     if(diff)
155         return diff / diff;
156
157     return 0;
158 }
159
160 int ISegment::getClassId() const
161 {
162     return classId;
163 }
164
165 Segment::Segment(ICanonicalUrl *parent) :
166         ISegment(parent)
167 {
168     size = -1;
169     classId = CLASSID_SEGMENT;
170 }
171
172 void Segment::addSubSegment(SubSegment *subsegment)
173 {
174     if(!subsegments.empty())
175     {
176         /* Use our own sequence number, and since it it now
177            uneffective, also for next subsegments numbering */
178         subsegment->setSequenceNumber(getSequenceNumber());
179         setSequenceNumber(getSequenceNumber());
180     }
181     subsegments.push_back(subsegment);
182 }
183
184 Segment::~Segment()
185 {
186     std::vector<SubSegment*>::iterator it;
187     for(it=subsegments.begin();it!=subsegments.end();++it)
188         delete *it;
189 }
190
191 void                    Segment::setSourceUrl   ( const std::string &url )
192 {
193     if ( url.empty() == false )
194         this->sourceUrl = Url(url);
195 }
196
197 void Segment::debug(vlc_object_t *obj, int indent) const
198 {
199     if (subsegments.empty())
200     {
201         ISegment::debug(obj, indent);
202     }
203     else
204     {
205         std::string text(indent, ' ');
206         text.append("Segment");
207         msg_Dbg(obj, "%s", text.c_str());
208         std::vector<SubSegment *>::const_iterator l;
209         for(l = subsegments.begin(); l != subsegments.end(); ++l)
210             (*l)->debug(obj, indent + 1);
211     }
212 }
213
214 Url Segment::getUrlSegment() const
215 {
216     if(sourceUrl.hasScheme())
217     {
218         return sourceUrl;
219     }
220     else
221     {
222         Url ret = getParentUrlSegment();
223         if (!sourceUrl.empty())
224             ret.append(sourceUrl);
225         return ret;
226     }
227 }
228
229 std::vector<ISegment*> Segment::subSegments()
230 {
231     std::vector<ISegment*> list;
232     if(!subsegments.empty())
233     {
234         std::vector<SubSegment*>::iterator it;
235         for(it=subsegments.begin();it!=subsegments.end();++it)
236             list.push_back(*it);
237     }
238     else
239     {
240         list.push_back(this);
241     }
242     return list;
243 }
244
245 InitSegment::InitSegment(ICanonicalUrl *parent) :
246     Segment(parent)
247 {
248     debugName = "InitSegment";
249     classId = CLASSID_INITSEGMENT;
250 }
251
252 IndexSegment::IndexSegment(ICanonicalUrl *parent) :
253     Segment(parent)
254 {
255     debugName = "IndexSegment";
256     classId = CLASSID_INDEXSEGMENT;
257 }
258
259 SubSegment::SubSegment(ISegment *main, size_t start, size_t end) :
260     ISegment(main), parent(main)
261 {
262     setByteRange(start, end);
263     debugName = "SubSegment";
264     classId = CLASSID_SUBSEGMENT;
265 }
266
267 Url SubSegment::getUrlSegment() const
268 {
269     return getParentUrlSegment();
270 }
271
272 std::vector<ISegment*> SubSegment::subSegments()
273 {
274     std::vector<ISegment*> list;
275     list.push_back(this);
276     return list;
277 }
278
279 void SubSegment::addSubSegment(SubSegment *)
280 {
281
282 }