3 *****************************************************************************
4 * Copyright (C) 2014 - VideoLAN authors
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
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 Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
20 #define __STDC_CONSTANT_MACROS
21 #include "Streams.hpp"
22 #include "adaptationlogic/AbstractAdaptationLogic.h"
23 #include "adaptationlogic/AdaptationLogicFactory.h"
24 #include "SegmentTracker.hpp"
25 #include <vlc_stream.h>
26 #include <vlc_demux.h>
28 using namespace dash::Streams;
29 using namespace dash::http;
30 using namespace dash::logic;
32 Stream::Stream(const std::string &mime)
34 init(mimeToType(mime), mimeToFormat(mime));
37 Stream::Stream(const Type type, const Format format)
42 void Stream::init(const Type type_, const Format format_)
47 adaptationLogic = NULL;
50 segmentTracker = NULL;
56 delete adaptationLogic;
58 delete segmentTracker;
61 Type Stream::mimeToType(const std::string &mime)
64 if (!mime.compare(0, 6, "video/"))
65 mimetype = Streams::VIDEO;
66 else if (!mime.compare(0, 6, "audio/"))
67 mimetype = Streams::AUDIO;
68 else if (!mime.compare(0, 12, "application/"))
69 mimetype = Streams::APPLICATION;
70 else /* unknown of unsupported */
71 mimetype = Streams::UNKNOWN;
75 Format Stream::mimeToFormat(const std::string &mime)
77 Format format = Streams::UNSUPPORTED;
78 std::string::size_type pos = mime.find("/");
79 if(pos != std::string::npos)
81 std::string tail = mime.substr(pos + 1);
83 format = Streams::MP4;
84 else if (tail == "mp2t")
85 format = Streams::MPEG2TS;
90 void Stream::create(demux_t *demux, AbstractAdaptationLogic *logic, SegmentTracker *tracker)
95 output = new MP4StreamOutput(demux);
97 case Streams::MPEG2TS:
98 output = new MPEG2TSStreamOutput(demux);
104 adaptationLogic = logic;
105 segmentTracker = tracker;
108 bool Stream::isEOF() const
113 mtime_t Stream::getPCR() const
115 return output->getPCR();
118 int Stream::getGroup() const
120 return output->getGroup();
123 int Stream::esCount() const
125 return output->esCount();
128 bool Stream::operator ==(const Stream &stream) const
130 return stream.type == type;
133 Chunk * Stream::getChunk()
135 if (currentChunk == NULL)
137 currentChunk = segmentTracker->getNextChunk(type);
138 if (currentChunk == NULL)
144 bool Stream::seekAble() const
146 return (output && output->seekAble());
149 size_t Stream::read(HTTPConnectionManager *connManager)
151 Chunk *chunk = getChunk();
155 if(!chunk->getConnection())
157 if(!connManager->connectChunk(chunk))
163 /* Because we don't know Chunk size at start, we need to get size
164 from content length */
165 if(chunk->getBytesRead() == 0)
167 if(chunk->getConnection()->query(chunk->getPath()) == false)
168 readsize = 32768; /* we don't handle retry here :/ */
170 readsize = chunk->getBytesToRead();
174 readsize = chunk->getBytesToRead();
177 if (readsize > 128000)
180 block_t *block = block_Alloc(readsize);
184 mtime_t time = mdate();
185 ssize_t ret = chunk->getConnection()->read(block->p_buffer, readsize);
186 time = mdate() - time;
190 block_Release(block);
191 chunk->getConnection()->releaseChunk();
198 block->i_buffer = (size_t)ret;
200 adaptationLogic->updateDownloadRate(block->i_buffer, time);
202 if (chunk->getBytesToRead() == 0)
204 chunk->onDownload(block->p_buffer, block->i_buffer);
205 chunk->getConnection()->releaseChunk();
211 readsize = block->i_buffer;
213 output->pushBlock(block);
218 bool Stream::setPosition(mtime_t time, bool tryonly)
220 bool ret = segmentTracker->setPosition(time, tryonly);
222 output->setPosition(time);
226 mtime_t Stream::getPosition() const
228 return segmentTracker->getSegmentStart();
231 AbstractStreamOutput::AbstractStreamOutput(demux_t *demux)
240 fakeesout = new es_out_t;
244 fakeesout->pf_add = esOutAdd;
245 fakeesout->pf_control = esOutControl;
246 fakeesout->pf_del = esOutDel;
247 fakeesout->pf_destroy = esOutDestroy;
248 fakeesout->pf_send = esOutSend;
249 fakeesout->p_sys = (es_out_sys_t*) this;
252 AbstractStreamOutput::~AbstractStreamOutput()
255 stream_Delete(demuxstream);
259 mtime_t AbstractStreamOutput::getPCR() const
264 int AbstractStreamOutput::getGroup() const
269 int AbstractStreamOutput::esCount() const
274 void AbstractStreamOutput::pushBlock(block_t *block)
276 stream_DemuxSend(demuxstream, block);
279 bool AbstractStreamOutput::seekAble() const
281 return (demuxstream && seekable);
284 void AbstractStreamOutput::setPosition(mtime_t nztime)
286 es_out_Control(realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
290 /* Static callbacks */
291 es_out_id_t * AbstractStreamOutput::esOutAdd(es_out_t *fakees, const es_format_t *p_fmt)
293 AbstractStreamOutput *me = (AbstractStreamOutput *) fakees->p_sys;
295 return me->realdemux->out->pf_add(me->realdemux->out, p_fmt);
298 int AbstractStreamOutput::esOutSend(es_out_t *fakees, es_out_id_t *p_es, block_t *p_block)
300 AbstractStreamOutput *me = (AbstractStreamOutput *) fakees->p_sys;
301 return me->realdemux->out->pf_send(me->realdemux->out, p_es, p_block);
304 void AbstractStreamOutput::esOutDel(es_out_t *fakees, es_out_id_t *p_es)
306 AbstractStreamOutput *me = (AbstractStreamOutput *) fakees->p_sys;
308 me->realdemux->out->pf_del(me->realdemux->out, p_es);
311 int AbstractStreamOutput::esOutControl(es_out_t *fakees, int i_query, va_list args)
313 AbstractStreamOutput *me = (AbstractStreamOutput *) fakees->p_sys;
314 if (i_query == ES_OUT_SET_PCR )
316 me->pcr = (int64_t)va_arg( args, int64_t );
319 else if( i_query == ES_OUT_SET_GROUP_PCR )
321 me->group = (int) va_arg( args, int );
322 me->pcr = (int64_t)va_arg( args, int64_t );
326 return me->realdemux->out->pf_control(me->realdemux->out, i_query, args);
329 void AbstractStreamOutput::esOutDestroy(es_out_t *fakees)
331 AbstractStreamOutput *me = (AbstractStreamOutput *) fakees->p_sys;
332 me->realdemux->out->pf_destroy(me->realdemux->out);
334 /* !Static callbacks */
336 MP4StreamOutput::MP4StreamOutput(demux_t *demux) :
337 AbstractStreamOutput(demux)
339 demuxstream = stream_DemuxNew(demux, "mp4", fakeesout);
344 MPEG2TSStreamOutput::MPEG2TSStreamOutput(demux_t *demux) :
345 AbstractStreamOutput(demux)
347 demuxstream = stream_DemuxNew(demux, "ts", fakeesout);