qt: add device preferences for mmdevice
[vlc.git] / modules / demux / adaptive / adaptive.cpp
blob05dea53c143cfc0e16770deede28890c0f9f6fb6
1 /*****************************************************************************
2 * adaptive.cpp: Adaptive streaming module
3 *****************************************************************************
4 * Copyright © 2015 - VideoLAN and VLC 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 *****************************************************************************/
21 /*****************************************************************************
22 * Preamble
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <stdint.h>
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
35 #include "http/AuthStorage.hpp"
36 #include "playlist/BasePeriod.h"
37 #include "xml/DOMParser.h"
39 #include "../dash/DASHManager.h"
40 #include "../dash/DASHStream.hpp"
41 #include "../dash/mpd/IsoffMainParser.h"
43 #include "../hls/HLSManager.hpp"
44 #include "../hls/HLSStreams.hpp"
45 #include "../hls/playlist/Parser.hpp"
46 #include "../hls/playlist/M3U8.hpp"
47 #include "../smooth/SmoothManager.hpp"
48 #include "../smooth/SmoothStream.hpp"
49 #include "../smooth/playlist/Parser.hpp"
51 using namespace adaptive::http;
52 using namespace adaptive::logic;
53 using namespace adaptive::playlist;
54 using namespace adaptive::xml;
55 using namespace dash::mpd;
56 using namespace dash;
57 using namespace hls;
58 using namespace hls::playlist;
59 using namespace smooth;
60 using namespace smooth::playlist;
62 /*****************************************************************************
63 * Module descriptor
64 *****************************************************************************/
65 static int Open (vlc_object_t *);
66 static void Close (vlc_object_t *);
68 #define ADAPT_WIDTH_TEXT N_("Maximum device width")
69 #define ADAPT_HEIGHT_TEXT N_("Maximum device height")
71 #define ADAPT_BW_TEXT N_("Fixed Bandwidth in KiB/s")
72 #define ADAPT_BW_LONGTEXT N_("Preferred bandwidth for non adaptive streams")
74 #define ADAPT_LOGIC_TEXT N_("Adaptive Logic")
76 #define ADAPT_ACCESS_TEXT N_("Use regular HTTP modules")
77 #define ADAPT_ACCESS_LONGTEXT N_("Connect using HTTP access instead of custom HTTP code")
79 static const AbstractAdaptationLogic::LogicType pi_logics[] = {
80 AbstractAdaptationLogic::Default,
81 AbstractAdaptationLogic::Predictive,
82 AbstractAdaptationLogic::NearOptimal,
83 AbstractAdaptationLogic::RateBased,
84 AbstractAdaptationLogic::FixedRate,
85 AbstractAdaptationLogic::AlwaysLowest,
86 AbstractAdaptationLogic::AlwaysBest};
88 static const char *const ppsz_logics_values[] = {
89 "",
90 "predictive",
91 "nearoptimal",
92 "rate",
93 "fixedrate",
94 "lowest",
95 "highest"};
97 static const char *const ppsz_logics[] = { N_("Default"),
98 N_("Predictive"),
99 N_("Near Optimal"),
100 N_("Bandwidth Adaptive"),
101 N_("Fixed Bandwidth"),
102 N_("Lowest Bandwidth/Quality"),
103 N_("Highest Bandwidth/Quality")};
105 static_assert( ARRAY_SIZE( pi_logics ) == ARRAY_SIZE( ppsz_logics ),
106 "pi_logics and ppsz_logics shall have the same number of elements" );
108 static_assert( ARRAY_SIZE( pi_logics ) == ARRAY_SIZE( ppsz_logics_values ),
109 "pi_logics and ppsz_logics_values shall have the same number of elements" );
111 vlc_module_begin ()
112 set_shortname( N_("Adaptive"))
113 set_description( N_("Unified adaptive streaming for DASH/HLS") )
114 set_capability( "demux", 12 )
115 set_category( CAT_INPUT )
116 set_subcategory( SUBCAT_INPUT_DEMUX )
117 add_string( "adaptive-logic", "", ADAPT_LOGIC_TEXT, NULL, false )
118 change_string_list( ppsz_logics_values, ppsz_logics )
119 add_integer( "adaptive-maxwidth", 0,
120 ADAPT_WIDTH_TEXT, ADAPT_WIDTH_TEXT, false )
121 add_integer( "adaptive-maxheight", 0,
122 ADAPT_HEIGHT_TEXT, ADAPT_HEIGHT_TEXT, false )
123 add_integer( "adaptive-bw", 250, ADAPT_BW_TEXT, ADAPT_BW_LONGTEXT, false )
124 add_bool ( "adaptive-use-access", false, ADAPT_ACCESS_TEXT, ADAPT_ACCESS_LONGTEXT, true );
125 set_callbacks( Open, Close )
126 vlc_module_end ()
128 /*****************************************************************************
129 * Local prototypes
130 *****************************************************************************/
131 static PlaylistManager * HandleDash(demux_t *, AuthStorage *auth, DOMParser &,
132 const std::string &, AbstractAdaptationLogic::LogicType);
133 static PlaylistManager * HandleSmooth(demux_t *, AuthStorage *auth, DOMParser &,
134 const std::string &, AbstractAdaptationLogic::LogicType);
136 /*****************************************************************************
137 * Open:
138 *****************************************************************************/
139 static int Open(vlc_object_t *p_obj)
141 demux_t *p_demux = (demux_t*) p_obj;
143 if(!p_demux->s->psz_url)
144 return VLC_EGENERIC;
146 std::string mimeType;
148 char *psz_mime = stream_ContentType(p_demux->s);
149 if(psz_mime)
151 mimeType = std::string(psz_mime);
152 free(psz_mime);
155 PlaylistManager *p_manager = NULL;
156 AuthStorage *authStorage = new AuthStorage(p_obj);
158 char *psz_logic = var_InheritString(p_obj, "adaptive-logic");
159 AbstractAdaptationLogic::LogicType logic = AbstractAdaptationLogic::Default;
160 if( psz_logic )
162 for(size_t i=0;i<ARRAY_SIZE(pi_logics); i++)
164 if(!strcmp(psz_logic, ppsz_logics_values[i]))
166 logic = pi_logics[i];
167 break;
170 free( psz_logic );
173 std::string playlisturl(p_demux->s->psz_url);
175 bool dashmime = DASHManager::mimeMatched(mimeType);
176 bool smoothmime = SmoothManager::mimeMatched(mimeType);
178 if(!dashmime && !smoothmime && HLSManager::isHTTPLiveStreaming(p_demux->s))
180 M3U8Parser parser(authStorage);
181 M3U8 *p_playlist = parser.parse(VLC_OBJECT(p_demux),p_demux->s, playlisturl);
182 if(!p_playlist)
184 msg_Err( p_demux, "Could not parse playlist" );
185 delete authStorage;
186 return VLC_EGENERIC;
189 p_manager = new (std::nothrow) HLSManager(p_demux, authStorage, p_playlist,
190 new (std::nothrow) HLSStreamFactory, logic);
192 else
194 /* Handle XML Based ones */
195 DOMParser xmlParser; /* Share that xml reader */
196 if(dashmime)
198 p_manager = HandleDash(p_demux, authStorage, xmlParser, playlisturl, logic);
200 else if(smoothmime)
202 p_manager = HandleSmooth(p_demux, authStorage, xmlParser, playlisturl, logic);
204 else
206 /* We need to probe content */
207 const uint8_t *p_peek;
208 const ssize_t i_peek = vlc_stream_Peek(p_demux->s, &p_peek, 2048);
209 if(i_peek > 0)
211 stream_t *peekstream = vlc_stream_MemoryNew(p_demux, const_cast<uint8_t *>(p_peek), (size_t)i_peek, true);
212 if(peekstream)
214 if(xmlParser.reset(peekstream) && xmlParser.parse(false))
216 if(DASHManager::isDASH(xmlParser.getRootNode()))
218 p_manager = HandleDash(p_demux, authStorage, xmlParser, playlisturl, logic);
220 else if(SmoothManager::isSmoothStreaming(xmlParser.getRootNode()))
222 p_manager = HandleSmooth(p_demux, authStorage, xmlParser, playlisturl, logic);
225 vlc_stream_Delete(peekstream);
231 if(!p_manager)
233 delete authStorage;
234 return VLC_EGENERIC;
236 else if(!p_manager->start())
238 delete p_manager;
239 return VLC_EGENERIC;
242 p_demux->p_sys = reinterpret_cast<demux_sys_t *>(p_manager);
243 p_demux->pf_demux = p_manager->demux_callback;
244 p_demux->pf_control = p_manager->control_callback;
246 msg_Dbg(p_obj,"opening playlist file (%s)", p_demux->psz_location);
248 return VLC_SUCCESS;
251 /*****************************************************************************
252 * Close:
253 *****************************************************************************/
254 static void Close(vlc_object_t *p_obj)
256 demux_t *p_demux = (demux_t*) p_obj;
257 PlaylistManager *p_manager = reinterpret_cast<PlaylistManager *>(p_demux->p_sys);
259 p_manager->stop();
260 delete p_manager;
263 /*****************************************************************************
265 *****************************************************************************/
266 static PlaylistManager * HandleDash(demux_t *p_demux,
267 AuthStorage *auth, DOMParser &xmlParser,
268 const std::string & playlisturl,
269 AbstractAdaptationLogic::LogicType logic)
271 if(!xmlParser.reset(p_demux->s) || !xmlParser.parse(true))
273 msg_Err(p_demux, "Cannot parse MPD");
274 return NULL;
276 IsoffMainParser mpdparser(xmlParser.getRootNode(), VLC_OBJECT(p_demux),
277 p_demux->s, playlisturl);
278 MPD *p_playlist = mpdparser.parse();
279 if(p_playlist == NULL)
281 msg_Err( p_demux, "Cannot create/unknown MPD for profile");
282 return NULL;
285 return new (std::nothrow) DASHManager( p_demux, auth, p_playlist,
286 new (std::nothrow) DASHStreamFactory,
287 logic );
290 static PlaylistManager * HandleSmooth(demux_t *p_demux,
291 AuthStorage *auth, DOMParser &xmlParser,
292 const std::string & playlisturl,
293 AbstractAdaptationLogic::LogicType logic)
295 if(!xmlParser.reset(p_demux->s) || !xmlParser.parse(true))
297 msg_Err(p_demux, "Cannot parse Manifest");
298 return NULL;
300 ManifestParser mparser(xmlParser.getRootNode(), VLC_OBJECT(p_demux),
301 p_demux->s, playlisturl);
302 Manifest *p_playlist = mparser.parse();
303 if(p_playlist == NULL)
305 msg_Err( p_demux, "Cannot create Manifest");
306 return NULL;
309 return new (std::nothrow) SmoothManager( p_demux, auth, p_playlist,
310 new (std::nothrow) SmoothStreamFactory,
311 logic );