Commit df703b2a authored by Francois Cartegnie's avatar Francois Cartegnie

demux: adaptative: reorder and optimize probing

uses xml reader for encoding proofness
now reuses and shares xml reader
parent f84a3af2
...@@ -100,6 +100,10 @@ vlc_module_end () ...@@ -100,6 +100,10 @@ vlc_module_end ()
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static PlaylistManager * HandleDash(demux_t *, DOMParser &,
const std::string &, AbstractAdaptationLogic::LogicType);
static PlaylistManager * HandleSmooth(demux_t *, DOMParser &,
const std::string &, AbstractAdaptationLogic::LogicType);
/***************************************************************************** /*****************************************************************************
* Open: * Open:
...@@ -108,80 +112,73 @@ static int Open(vlc_object_t *p_obj) ...@@ -108,80 +112,73 @@ static int Open(vlc_object_t *p_obj)
{ {
demux_t *p_demux = (demux_t*) p_obj; demux_t *p_demux = (demux_t*) p_obj;
bool b_mimematched = false; std::string mimeType;
char *psz_mime = stream_ContentType(p_demux->s); char *psz_mime = stream_ContentType(p_demux->s);
if(psz_mime) if(psz_mime)
{ {
b_mimematched = !strcmp(psz_mime, "application/dash+xml"); mimeType = std::string(psz_mime);
free(psz_mime); free(psz_mime);
} }
PlaylistManager *p_manager = NULL; PlaylistManager *p_manager = NULL;
int logic = var_InheritInteger(p_obj, "adaptative-logic"); AbstractAdaptationLogic::LogicType logic =
static_cast<AbstractAdaptationLogic::LogicType>(var_InheritInteger(p_obj, "adaptative-logic"));
std::string playlisturl(p_demux->psz_access); std::string playlisturl(p_demux->psz_access);
playlisturl.append("://"); playlisturl.append("://");
playlisturl.append(p_demux->psz_location); playlisturl.append(p_demux->psz_location);
if(b_mimematched || DASHManager::isDASH(p_demux->s)) bool dashmime = DASHManager::mimeMatched(mimeType);
{ bool smoothmime = SmoothManager::mimeMatched(mimeType);
//Build a XML tree
DOMParser parser(p_demux->s);
if( !parser.parse() )
{
msg_Err( p_demux, "Could not parse MPD" );
return VLC_EGENERIC;
}
IsoffMainParser mpdparser(parser.getRootNode(), p_demux->s, playlisturl); if(!dashmime && !smoothmime && HLSManager::isHTTPLiveStreaming(p_demux->s))
MPD *p_playlist = mpdparser.parse();
if(p_playlist == NULL)
{
msg_Err( p_demux, "Cannot create/unknown MPD for profile");
return VLC_EGENERIC;
}
p_manager = new DASHManager( p_demux, p_playlist,
new (std::nothrow) DASHStreamFactory,
static_cast<AbstractAdaptationLogic::LogicType>(logic) );
}
else if(HLSManager::isHTTPLiveStreaming(p_demux->s))
{ {
M3U8Parser parser; M3U8Parser parser;
M3U8 *p_playlist = parser.parse(p_demux->s, playlisturl); M3U8 *p_playlist = parser.parse(p_demux->s, playlisturl);
if(!p_playlist) if(!p_playlist)
{ {
msg_Err( p_demux, "Could not parse MPD" ); msg_Err( p_demux, "Could not parse playlist" );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
p_manager = p_manager = new (std::nothrow) HLSManager(p_demux, p_playlist,
new (std::nothrow) HLSManager(p_demux, p_playlist, new (std::nothrow) HLSStreamFactory, logic);
new (std::nothrow) HLSStreamFactory,
static_cast<AbstractAdaptationLogic::LogicType>(logic));
} }
else if(SmoothManager::isSmoothStreaming(p_demux->s)) else
{ {
//Build a XML tree /* Handle XML Based ones */
DOMParser parser(p_demux->s); DOMParser xmlParser; /* Share that xml reader */
if( !parser.parse() ) if(dashmime)
{ {
msg_Err( p_demux, "Could not parse Manifest" ); p_manager = HandleDash(p_demux, xmlParser, playlisturl, logic);
return VLC_EGENERIC;
} }
else if(smoothmime)
ManifestParser *mparser = new ManifestParser(parser.getRootNode(), p_demux->s, playlisturl);
smooth::playlist::Manifest *p_playlist = mparser->parse();
delete mparser;
if(p_playlist == NULL)
{ {
msg_Err( p_demux, "Cannot create Manifest"); p_manager = HandleSmooth(p_demux, xmlParser, playlisturl, logic);
return VLC_EGENERIC; }
else
{
/* We need to probe content */
const uint8_t *p_peek;
const size_t i_peek = stream_Peek(p_demux->s, &p_peek, 2048);
stream_t *peekstream = stream_MemoryNew(p_demux, const_cast<uint8_t *>(p_peek), i_peek, true);
if(peekstream)
{
if(xmlParser.reset(peekstream) && xmlParser.parse(false))
{
if(DASHManager::isDASH(xmlParser.getRootNode()))
{
p_manager = HandleDash(p_demux, xmlParser, playlisturl, logic);
}
else if(SmoothManager::isSmoothStreaming(xmlParser.getRootNode()))
{
p_manager = HandleSmooth(p_demux, xmlParser, playlisturl, logic);
}
}
stream_Delete(peekstream);
}
} }
p_manager = new SmoothManager( p_demux, p_playlist,
new (std::nothrow) SmoothStreamFactory,
static_cast<AbstractAdaptationLogic::LogicType>(logic) );
} }
if(!p_manager || !p_manager->start()) if(!p_manager || !p_manager->start())
...@@ -198,6 +195,7 @@ static int Open(vlc_object_t *p_obj) ...@@ -198,6 +195,7 @@ static int Open(vlc_object_t *p_obj)
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/***************************************************************************** /*****************************************************************************
* Close: * Close:
*****************************************************************************/ *****************************************************************************/
...@@ -208,3 +206,50 @@ static void Close(vlc_object_t *p_obj) ...@@ -208,3 +206,50 @@ static void Close(vlc_object_t *p_obj)
delete p_manager; delete p_manager;
} }
/*****************************************************************************
*
*****************************************************************************/
static PlaylistManager * HandleDash(demux_t *p_demux, DOMParser &xmlParser,
const std::string & playlisturl,
AbstractAdaptationLogic::LogicType logic)
{
if(!xmlParser.reset(p_demux->s) || !xmlParser.parse(true))
{
msg_Err(p_demux, "Cannot parse MPD");
return NULL;
}
IsoffMainParser mpdparser(xmlParser.getRootNode(), p_demux->s, playlisturl);
MPD *p_playlist = mpdparser.parse();
if(p_playlist == NULL)
{
msg_Err( p_demux, "Cannot create/unknown MPD for profile");
return NULL;
}
return new (std::nothrow) DASHManager( p_demux, p_playlist,
new (std::nothrow) DASHStreamFactory,
logic );
}
static PlaylistManager * HandleSmooth(demux_t *p_demux, DOMParser &xmlParser,
const std::string & playlisturl,
AbstractAdaptationLogic::LogicType logic)
{
if(!xmlParser.reset(p_demux->s) || !xmlParser.parse(true))
{
msg_Err(p_demux, "Cannot parse Manifest");
return NULL;
}
ManifestParser mparser(xmlParser.getRootNode(), p_demux->s, playlisturl);
Manifest *p_playlist = mparser.parse();
if(p_playlist == NULL)
{
msg_Err( p_demux, "Cannot create Manifest");
return NULL;
}
return new (std::nothrow) SmoothManager( p_demux, p_playlist,
new (std::nothrow) SmoothStreamFactory,
logic );
}
...@@ -33,6 +33,13 @@ ...@@ -33,6 +33,13 @@
using namespace adaptative::xml; using namespace adaptative::xml;
DOMParser::DOMParser() :
root( NULL ),
stream( NULL ),
vlc_reader( NULL )
{
}
DOMParser::DOMParser (stream_t *stream) : DOMParser::DOMParser (stream_t *stream) :
root( NULL ), root( NULL ),
stream( stream ), stream( stream ),
...@@ -51,14 +58,15 @@ Node* DOMParser::getRootNode () ...@@ -51,14 +58,15 @@ Node* DOMParser::getRootNode ()
{ {
return this->root; return this->root;
} }
bool DOMParser::parse () bool DOMParser::parse (bool b)
{ {
this->vlc_reader = xml_ReaderCreate(this->stream, this->stream); if(!stream)
return false;
if(!this->vlc_reader) if(!vlc_reader && !(vlc_reader = xml_ReaderCreate(stream, stream)))
return false; return false;
root = processNode(); root = processNode(b);
if ( root == NULL ) if ( root == NULL )
return false; return false;
...@@ -67,14 +75,16 @@ bool DOMParser::parse () ...@@ -67,14 +75,16 @@ bool DOMParser::parse ()
bool DOMParser::reset(stream_t *s) bool DOMParser::reset(stream_t *s)
{ {
stream = s;
if(!vlc_reader)
return true;
delete root; delete root;
root = NULL; root = NULL;
stream = s;
vlc_reader = xml_ReaderReset(vlc_reader, s); vlc_reader = xml_ReaderReset(vlc_reader, s);
return !!vlc_reader; return !!vlc_reader;
} }
Node* DOMParser::processNode() Node* DOMParser::processNode(bool b_strict)
{ {
const char *data; const char *data;
int type; int type;
...@@ -129,10 +139,15 @@ Node* DOMParser::processNode() ...@@ -129,10 +139,15 @@ Node* DOMParser::processNode()
while( lifo.size() > 1 ) while( lifo.size() > 1 )
lifo.pop(); lifo.pop();
if(!lifo.empty()) Node *node = (!lifo.empty()) ? lifo.top() : NULL;
delete lifo.top();
if(b_strict && node)
{
delete node;
return NULL; return NULL;
}
return node;
} }
void DOMParser::addAttributesToNode (Node *node) void DOMParser::addAttributesToNode (Node *node)
......
...@@ -41,10 +41,11 @@ namespace adaptative ...@@ -41,10 +41,11 @@ namespace adaptative
class DOMParser class DOMParser
{ {
public: public:
DOMParser ();
DOMParser (stream_t *stream); DOMParser (stream_t *stream);
virtual ~DOMParser (); virtual ~DOMParser ();
bool parse (); bool parse (bool);
bool reset (stream_t *); bool reset (stream_t *);
Node* getRootNode (); Node* getRootNode ();
void print (); void print ();
...@@ -55,7 +56,7 @@ namespace adaptative ...@@ -55,7 +56,7 @@ namespace adaptative
xml_reader_t *vlc_reader; xml_reader_t *vlc_reader;
Node* processNode (); Node* processNode (bool);
void addAttributesToNode (Node *node); void addAttributesToNode (Node *node);
void print (Node *node, int offset); void print (Node *node, int offset);
}; };
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "mpd/ProgramInformation.h" #include "mpd/ProgramInformation.h"
#include "mpd/IsoffMainParser.h" #include "mpd/IsoffMainParser.h"
#include "xml/DOMParser.h" #include "xml/DOMParser.h"
#include "xml/Node.h"
#include "../adaptative/tools/Helper.h" #include "../adaptative/tools/Helper.h"
#include "../adaptative/http/HTTPConnectionManager.h" #include "../adaptative/http/HTTPConnectionManager.h"
#include <vlc_stream.h> #include <vlc_stream.h>
...@@ -87,7 +88,7 @@ bool DASHManager::updatePlaylist() ...@@ -87,7 +88,7 @@ bool DASHManager::updatePlaylist()
} }
xml::DOMParser parser(mpdstream); xml::DOMParser parser(mpdstream);
if(!parser.parse()) if(!parser.parse(true))
{ {
stream_Delete(mpdstream); stream_Delete(mpdstream);
block_Release(p_block); block_Release(p_block);
...@@ -176,27 +177,30 @@ int DASHManager::doControl(int i_query, va_list args) ...@@ -176,27 +177,30 @@ int DASHManager::doControl(int i_query, va_list args)
return PlaylistManager::doControl(i_query, args); return PlaylistManager::doControl(i_query, args);
} }
bool DASHManager::isDASH(stream_t *stream) bool DASHManager::isDASH(xml::Node *root)
{ {
const std::string namespaces[] = { const std::string namespaces[] = {
"xmlns=\"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011\"", "urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"xmlns=\"urn:mpeg:schema:dash:mpd:2011\"", "urn:mpeg:schema:dash:mpd:2011",
"xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"", "urn:mpeg:DASH:schema:MPD:2011",
"xmlns='urn:mpeg:mpegB:schema:DASH:MPD:DIS2011'", "urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"xmlns='urn:mpeg:schema:dash:mpd:2011'", "urn:mpeg:schema:dash:mpd:2011",
"xmlns='urn:mpeg:DASH:schema:MPD:2011'", "urn:mpeg:DASH:schema:MPD:2011",
}; };
const uint8_t *peek; if(root->getName() != "MPD")
int peek_size = stream_Peek(stream, &peek, 1024);
if (peek_size < (int)namespaces[0].length())
return false; return false;
std::string header((const char*)peek, peek_size); std::string ns = root->getAttributeValue("xmlns");
for( size_t i=0; i<ARRAY_SIZE(namespaces); i++ ) for( size_t i=0; i<ARRAY_SIZE(namespaces); i++ )
{ {
if ( adaptative::Helper::ifind(header, namespaces[i]) ) if ( adaptative::Helper::ifind(ns, namespaces[i]) )
return true; return true;
} }
return false; return false;
} }
bool DASHManager::mimeMatched(const std::string &mime)
{
return (mime == "application/dash+xml");
}
...@@ -29,6 +29,14 @@ ...@@ -29,6 +29,14 @@
#include "../adaptative/logic/AbstractAdaptationLogic.h" #include "../adaptative/logic/AbstractAdaptationLogic.h"
#include "mpd/MPD.h" #include "mpd/MPD.h"
namespace adaptative
{
namespace xml
{
class Node;
}
}
namespace dash namespace dash
{ {
using namespace adaptative; using namespace adaptative;
...@@ -42,7 +50,8 @@ namespace dash ...@@ -42,7 +50,8 @@ namespace dash
virtual ~DASHManager (); virtual ~DASHManager ();
virtual bool updatePlaylist(); //reimpl virtual bool updatePlaylist(); //reimpl
static bool isDASH(stream_t *); static bool isDASH(xml::Node *);
static bool mimeMatched(const std::string &);
protected: protected:
virtual int doControl(int, va_list); /* reimpl */ virtual int doControl(int, va_list); /* reimpl */
......
...@@ -50,7 +50,7 @@ using namespace dash::mpd; ...@@ -50,7 +50,7 @@ using namespace dash::mpd;
using namespace adaptative::xml; using namespace adaptative::xml;
using namespace adaptative::playlist; using namespace adaptative::playlist;
IsoffMainParser::IsoffMainParser (Node *root_, stream_t *stream, std::string & streambaseurl_) IsoffMainParser::IsoffMainParser (Node *root_, stream_t *stream, const std::string & streambaseurl_)
{ {
root = root_; root = root_;
p_stream = stream; p_stream = stream;
......
...@@ -63,7 +63,7 @@ namespace dash ...@@ -63,7 +63,7 @@ namespace dash
class IsoffMainParser class IsoffMainParser
{ {
public: public:
IsoffMainParser (xml::Node *root, stream_t *p_stream, std::string &); IsoffMainParser (xml::Node *root, stream_t *p_stream, const std::string &);
virtual ~IsoffMainParser (); virtual ~IsoffMainParser ();
MPD * parse(); MPD * parse();
......
...@@ -65,7 +65,7 @@ Manifest * SmoothManager::fetchManifest() ...@@ -65,7 +65,7 @@ Manifest * SmoothManager::fetchManifest()
} }
xml::DOMParser parser(memorystream); xml::DOMParser parser(memorystream);
if(!parser.parse()) if(!parser.parse(true))
{ {
stream_Delete(memorystream); stream_Delete(memorystream);
block_Release(p_block); block_Release(p_block);
...@@ -148,39 +148,12 @@ bool SmoothManager::updatePlaylist() ...@@ -148,39 +148,12 @@ bool SmoothManager::updatePlaylist()
return true; return true;
} }
bool SmoothManager::isSmoothStreaming(stream_t *stream) bool SmoothManager::isSmoothStreaming(xml::Node *root)
{ {
const uint8_t *peek; return root->getName() == "SmoothStreamingMedia";
int i_size = stream_Peek( stream, &peek, 512 ); }
if( i_size < 512 )
return false;
char *peeked = (char*) malloc( 512 );
if( unlikely( peeked == NULL ) )
return false;
memcpy( peeked, peek, 512 );
peeked[511] = peeked[510] = '\0';
char *str;
if( !memcmp( peeked, "\xFF\xFE", 2 ) )
{
str = FromCharset( "UTF-16LE", peeked, 512 );
free( peeked );
}
else if( !memcmp( peeked, "\xFE\xFF", 2 ) )
{
str = FromCharset( "UTF-16BE", peeked, 512 );
free( peeked );
}
else
str = peeked;
if( str == NULL )
return false;
bool ret = strstr( str, "<SmoothStreamingMedia" ) != NULL; bool SmoothManager::mimeMatched(const std::string &mime)
free( str ); {
return ret; return (mime == "application/vnd.ms-sstr+xml");
} }
...@@ -24,6 +24,14 @@ ...@@ -24,6 +24,14 @@
#include "../adaptative/logic/AbstractAdaptationLogic.h" #include "../adaptative/logic/AbstractAdaptationLogic.h"
#include "playlist/Manifest.hpp" #include "playlist/Manifest.hpp"
namespace adaptative
{
namespace xml
{
class Node;
}
}
namespace smooth namespace smooth
{ {
using namespace adaptative; using namespace adaptative;
...@@ -37,7 +45,8 @@ namespace smooth ...@@ -37,7 +45,8 @@ namespace smooth
virtual ~SmoothManager(); virtual ~SmoothManager();
virtual bool updatePlaylist(); //reimpl virtual bool updatePlaylist(); //reimpl
static bool isSmoothStreaming(stream_t *); static bool isSmoothStreaming(xml::Node *);
static bool mimeMatched(const std::string &);
private: private:
playlist::Manifest * fetchManifest(); playlist::Manifest * fetchManifest();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment