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 ()
/*****************************************************************************
* 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:
......@@ -108,80 +112,73 @@ static int Open(vlc_object_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);
if(psz_mime)
{
b_mimematched = !strcmp(psz_mime, "application/dash+xml");
mimeType = std::string(psz_mime);
free(psz_mime);
}
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);
playlisturl.append("://");
playlisturl.append(p_demux->psz_location);
if(b_mimematched || DASHManager::isDASH(p_demux->s))
{
//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);
MPD *p_playlist = mpdparser.parse();
if(p_playlist == NULL)
{
msg_Err( p_demux, "Cannot create/unknown MPD for profile");
return VLC_EGENERIC;
}
bool dashmime = DASHManager::mimeMatched(mimeType);
bool smoothmime = SmoothManager::mimeMatched(mimeType);
p_manager = new DASHManager( p_demux, p_playlist,
new (std::nothrow) DASHStreamFactory,
static_cast<AbstractAdaptationLogic::LogicType>(logic) );
}
else if(HLSManager::isHTTPLiveStreaming(p_demux->s))
if(!dashmime && !smoothmime && HLSManager::isHTTPLiveStreaming(p_demux->s))
{
M3U8Parser parser;
M3U8 *p_playlist = parser.parse(p_demux->s, playlisturl);
if(!p_playlist)
{
msg_Err( p_demux, "Could not parse MPD" );
msg_Err( p_demux, "Could not parse playlist" );
return VLC_EGENERIC;
}
p_manager =
new (std::nothrow) HLSManager(p_demux, p_playlist,
new (std::nothrow) HLSStreamFactory,
static_cast<AbstractAdaptationLogic::LogicType>(logic));
p_manager = new (std::nothrow) HLSManager(p_demux, p_playlist,
new (std::nothrow) HLSStreamFactory, logic);
}
else if(SmoothManager::isSmoothStreaming(p_demux->s))
else
{
//Build a XML tree
DOMParser parser(p_demux->s);
if( !parser.parse() )
/* Handle XML Based ones */
DOMParser xmlParser; /* Share that xml reader */
if(dashmime)
{
msg_Err( p_demux, "Could not parse Manifest" );
return VLC_EGENERIC;
p_manager = HandleDash(p_demux, xmlParser, playlisturl, logic);
}
ManifestParser *mparser = new ManifestParser(parser.getRootNode(), p_demux->s, playlisturl);
smooth::playlist::Manifest *p_playlist = mparser->parse();
delete mparser;
if(p_playlist == NULL)
else if(smoothmime)
{
msg_Err( p_demux, "Cannot create Manifest");
return VLC_EGENERIC;
p_manager = HandleSmooth(p_demux, xmlParser, playlisturl, logic);
}
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())
......@@ -198,6 +195,7 @@ static int Open(vlc_object_t *p_obj)
return VLC_SUCCESS;
}
/*****************************************************************************
* Close:
*****************************************************************************/
......@@ -208,3 +206,50 @@ static void Close(vlc_object_t *p_obj)
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 @@
using namespace adaptative::xml;
DOMParser::DOMParser() :
root( NULL ),
stream( NULL ),
vlc_reader( NULL )
{
}
DOMParser::DOMParser (stream_t *stream) :
root( NULL ),
stream( stream ),
......@@ -51,14 +58,15 @@ Node* DOMParser::getRootNode ()
{
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;
root = processNode();
root = processNode(b);
if ( root == NULL )
return false;
......@@ -67,14 +75,16 @@ bool DOMParser::parse ()
bool DOMParser::reset(stream_t *s)
{
stream = s;
if(!vlc_reader)
return true;
delete root;
root = NULL;
stream = s;
vlc_reader = xml_ReaderReset(vlc_reader, s);
return !!vlc_reader;
}
Node* DOMParser::processNode()
Node* DOMParser::processNode(bool b_strict)
{
const char *data;
int type;
......@@ -129,10 +139,15 @@ Node* DOMParser::processNode()
while( lifo.size() > 1 )
lifo.pop();
if(!lifo.empty())
delete lifo.top();
Node *node = (!lifo.empty()) ? lifo.top() : NULL;
if(b_strict && node)
{
delete node;
return NULL;
}
return NULL;
return node;
}
void DOMParser::addAttributesToNode (Node *node)
......
......@@ -41,10 +41,11 @@ namespace adaptative
class DOMParser
{
public:
DOMParser ();
DOMParser (stream_t *stream);
virtual ~DOMParser ();
bool parse ();
bool parse (bool);
bool reset (stream_t *);
Node* getRootNode ();
void print ();
......@@ -55,7 +56,7 @@ namespace adaptative
xml_reader_t *vlc_reader;
Node* processNode ();
Node* processNode (bool);
void addAttributesToNode (Node *node);
void print (Node *node, int offset);
};
......
......@@ -32,6 +32,7 @@
#include "mpd/ProgramInformation.h"
#include "mpd/IsoffMainParser.h"
#include "xml/DOMParser.h"
#include "xml/Node.h"
#include "../adaptative/tools/Helper.h"
#include "../adaptative/http/HTTPConnectionManager.h"
#include <vlc_stream.h>
......@@ -87,7 +88,7 @@ bool DASHManager::updatePlaylist()
}
xml::DOMParser parser(mpdstream);
if(!parser.parse())
if(!parser.parse(true))
{
stream_Delete(mpdstream);
block_Release(p_block);
......@@ -176,27 +177,30 @@ int DASHManager::doControl(int i_query, va_list args)
return PlaylistManager::doControl(i_query, args);
}
bool DASHManager::isDASH(stream_t *stream)
bool DASHManager::isDASH(xml::Node *root)
{
const std::string namespaces[] = {
"xmlns=\"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011\"",
"xmlns=\"urn:mpeg:schema:dash:mpd:2011\"",
"xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"",
"xmlns='urn:mpeg:mpegB:schema:DASH:MPD:DIS2011'",
"xmlns='urn:mpeg:schema:dash:mpd:2011'",
"xmlns='urn:mpeg:DASH:schema:MPD:2011'",
"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"urn:mpeg:schema:dash:mpd:2011",
"urn:mpeg:DASH:schema:MPD:2011",
"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"urn:mpeg:schema:dash:mpd:2011",
"urn:mpeg:DASH:schema:MPD:2011",
};
const uint8_t *peek;
int peek_size = stream_Peek(stream, &peek, 1024);
if (peek_size < (int)namespaces[0].length())
if(root->getName() != "MPD")
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++ )
{
if ( adaptative::Helper::ifind(header, namespaces[i]) )
if ( adaptative::Helper::ifind(ns, namespaces[i]) )
return true;
}
return false;
}
bool DASHManager::mimeMatched(const std::string &mime)
{
return (mime == "application/dash+xml");
}
......@@ -29,6 +29,14 @@
#include "../adaptative/logic/AbstractAdaptationLogic.h"
#include "mpd/MPD.h"
namespace adaptative
{
namespace xml
{
class Node;
}
}
namespace dash
{
using namespace adaptative;
......@@ -42,7 +50,8 @@ namespace dash
virtual ~DASHManager ();
virtual bool updatePlaylist(); //reimpl
static bool isDASH(stream_t *);
static bool isDASH(xml::Node *);
static bool mimeMatched(const std::string &);
protected:
virtual int doControl(int, va_list); /* reimpl */
......
......@@ -50,7 +50,7 @@ using namespace dash::mpd;
using namespace adaptative::xml;
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_;
p_stream = stream;
......
......@@ -63,7 +63,7 @@ namespace dash
class IsoffMainParser
{
public:
IsoffMainParser (xml::Node *root, stream_t *p_stream, std::string &);
IsoffMainParser (xml::Node *root, stream_t *p_stream, const std::string &);
virtual ~IsoffMainParser ();
MPD * parse();
......
......@@ -65,7 +65,7 @@ Manifest * SmoothManager::fetchManifest()
}
xml::DOMParser parser(memorystream);
if(!parser.parse())
if(!parser.parse(true))
{
stream_Delete(memorystream);
block_Release(p_block);
......@@ -148,39 +148,12 @@ bool SmoothManager::updatePlaylist()
return true;
}
bool SmoothManager::isSmoothStreaming(stream_t *stream)
bool SmoothManager::isSmoothStreaming(xml::Node *root)
{
const uint8_t *peek;
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;
return root->getName() == "SmoothStreamingMedia";
}
bool ret = strstr( str, "<SmoothStreamingMedia" ) != NULL;
free( str );
return ret;
bool SmoothManager::mimeMatched(const std::string &mime)
{
return (mime == "application/vnd.ms-sstr+xml");
}
......@@ -24,6 +24,14 @@
#include "../adaptative/logic/AbstractAdaptationLogic.h"
#include "playlist/Manifest.hpp"
namespace adaptative
{
namespace xml
{
class Node;
}
}
namespace smooth
{
using namespace adaptative;
......@@ -37,7 +45,8 @@ namespace smooth
virtual ~SmoothManager();
virtual bool updatePlaylist(); //reimpl
static bool isSmoothStreaming(stream_t *);
static bool isSmoothStreaming(xml::Node *);
static bool mimeMatched(const std::string &);
private:
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