[vlc-commits] demux: hls: probe content
Francois Cartegnie
git at videolan.org
Tue Jul 23 20:36:18 CEST 2019
vlc/vlc-3.0 | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Tue Apr 23 14:34:37 2019 +0200| [72ab7359fdf4fa533ea6a2bea3c2232538b01aa1] | committer: Francois Cartegnie
demux: hls: probe content
Solves issues when the server does not sends proper MIME
and the file does not match known extension.
(cherry picked from commit dfe4aca1f22265115e07c501a77c870cfea4cd52)
> http://git.videolan.org/gitweb.cgi/vlc/vlc-3.0.git/?a=commit;h=72ab7359fdf4fa533ea6a2bea3c2232538b01aa1
---
modules/demux/adaptive/SegmentTracker.cpp | 6 +++---
modules/demux/adaptive/StreamFormat.cpp | 24 +++++++++++++++++++++-
modules/demux/adaptive/StreamFormat.hpp | 2 ++
modules/demux/adaptive/Streams.cpp | 2 +-
modules/demux/adaptive/plumbing/Demuxer.cpp | 15 ++++++++++++--
modules/demux/hls/HLSStreams.cpp | 4 ++--
modules/demux/hls/playlist/Parser.cpp | 32 -----------------------------
modules/demux/hls/playlist/Parser.hpp | 1 -
8 files changed, 44 insertions(+), 42 deletions(-)
diff --git a/modules/demux/adaptive/SegmentTracker.cpp b/modules/demux/adaptive/SegmentTracker.cpp
index ce5db8874f..23835117cb 100644
--- a/modules/demux/adaptive/SegmentTracker.cpp
+++ b/modules/demux/adaptive/SegmentTracker.cpp
@@ -86,7 +86,7 @@ SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSe
curRepresentation = NULL;
setAdaptationLogic(logic_);
adaptationSet = adaptSet;
- format = StreamFormat::UNSUPPORTED;
+ format = StreamFormat::UNKNOWN;
}
SegmentTracker::~SegmentTracker()
@@ -132,7 +132,7 @@ void SegmentTracker::reset()
init_sent = false;
index_sent = false;
initializing = true;
- format = StreamFormat::UNSUPPORTED;
+ format = StreamFormat::UNKNOWN;
}
SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed,
@@ -199,7 +199,7 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed,
if(rep->getStreamFormat() != format)
{
/* Initial format ? */
- if(format == StreamFormat(StreamFormat::UNSUPPORTED))
+ if(format == StreamFormat(StreamFormat::UNKNOWN))
{
format = rep->getStreamFormat();
}
diff --git a/modules/demux/adaptive/StreamFormat.cpp b/modules/demux/adaptive/StreamFormat.cpp
index 11cee69dac..d31cc1800c 100644
--- a/modules/demux/adaptive/StreamFormat.cpp
+++ b/modules/demux/adaptive/StreamFormat.cpp
@@ -23,6 +23,8 @@
#endif
#include "StreamFormat.hpp"
+
+#include <vlc_common.h>
#include <algorithm>
using namespace adaptive;
@@ -64,7 +66,7 @@ StreamFormat::StreamFormat( const std::string &mimetype )
std::string mime = mimetype;
std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
std::string::size_type pos = mime.find("/");
- formatid = UNSUPPORTED;
+ formatid = UNKNOWN;
if(pos != std::string::npos)
{
std::string tail = mime.substr(pos + 1);
@@ -79,6 +81,26 @@ StreamFormat::StreamFormat( const std::string &mimetype )
}
}
+StreamFormat::StreamFormat(const void *data_, size_t sz)
+{
+ const uint8_t *data = reinterpret_cast<const uint8_t *>(data_);
+ formatid = UNKNOWN;
+ const char moov[] = "ftypmoovmoof";
+
+ if(sz > 188 && data[0] == 0x47 && data[188] == 0x47)
+ formatid = StreamFormat::MPEG2TS;
+ else if(sz > 8 && (!memcmp(&moov, &data[4], 4) ||
+ !memcmp(&moov[4], &data[4], 4) ||
+ !memcmp(&moov[8], &data[4], 4)))
+ formatid = StreamFormat::MP4;
+ else if(sz > 7 && !memcmp("WEBVTT", data, 6) &&
+ std::isspace(static_cast<unsigned char>(data[7])))
+ formatid = StreamFormat::WEBVTT;
+ else if(sz > 3 && (!memcmp("\xFF\xF1", data, 2)||
+ !memcmp("\xFF\xF9", data, 2)))
+ formatid = StreamFormat::PACKEDAAC;
+}
+
StreamFormat::~StreamFormat()
{
diff --git a/modules/demux/adaptive/StreamFormat.hpp b/modules/demux/adaptive/StreamFormat.hpp
index 7b3d49e1b4..738e04574b 100644
--- a/modules/demux/adaptive/StreamFormat.hpp
+++ b/modules/demux/adaptive/StreamFormat.hpp
@@ -35,9 +35,11 @@ namespace adaptive
static const unsigned TTML = 4;
static const unsigned PACKEDAAC = 5;
static const unsigned UNKNOWN = 0xFF; /* will probe */
+ static const unsigned PEEK_SIZE = 189;
StreamFormat( unsigned = UNSUPPORTED );
explicit StreamFormat( const std::string &mime );
+ StreamFormat( const void *, size_t );
~StreamFormat();
operator unsigned() const;
std::string str() const;
diff --git a/modules/demux/adaptive/Streams.cpp b/modules/demux/adaptive/Streams.cpp
index 4bded1ba70..fe36b8df6f 100644
--- a/modules/demux/adaptive/Streams.cpp
+++ b/modules/demux/adaptive/Streams.cpp
@@ -41,7 +41,7 @@ using namespace adaptive::http;
AbstractStream::AbstractStream(demux_t * demux_)
{
p_realdemux = demux_;
- format = StreamFormat::UNSUPPORTED;
+ format = StreamFormat::UNKNOWN;
currentChunk = NULL;
eof = false;
dead = false;
diff --git a/modules/demux/adaptive/plumbing/Demuxer.cpp b/modules/demux/adaptive/plumbing/Demuxer.cpp
index caf78c5667..6c6ca8cd2f 100644
--- a/modules/demux/adaptive/plumbing/Demuxer.cpp
+++ b/modules/demux/adaptive/plumbing/Demuxer.cpp
@@ -100,13 +100,24 @@ bool MimeDemuxer::create()
if(!p_newstream)
return false;
+ StreamFormat format(StreamFormat::UNKNOWN);
char *type = stream_ContentType(p_newstream);
if(type)
{
- demuxer = factory->newDemux( p_realdemux, StreamFormat(std::string(type)),
- p_es_out, sourcestream );
+ format = StreamFormat(std::string(type));
free(type);
}
+ /* Try to probe */
+ if(format == StreamFormat(StreamFormat::UNKNOWN))
+ {
+ const uint8_t *p_peek;
+ size_t i_peek = sourcestream->Peek(&p_peek, StreamFormat::PEEK_SIZE);
+ format = StreamFormat(reinterpret_cast<const void *>(p_peek), i_peek);
+ }
+
+ if(format != StreamFormat(StreamFormat::UNKNOWN))
+ demuxer = factory->newDemux(p_realdemux, format, p_es_out, sourcestream);
+
vlc_stream_Delete(p_newstream);
if(!demuxer || !demuxer->create())
diff --git a/modules/demux/hls/HLSStreams.cpp b/modules/demux/hls/HLSStreams.cpp
index 30cb2640bf..b4434d7a4c 100644
--- a/modules/demux/hls/HLSStreams.cpp
+++ b/modules/demux/hls/HLSStreams.cpp
@@ -161,11 +161,11 @@ AbstractDemuxer *HLSStream::newDemux(demux_t *p_realdemux, const StreamFormat &f
return ret;
}
-AbstractStream * HLSStreamFactory::create(demux_t *realdemux, const StreamFormat &,
+AbstractStream * HLSStreamFactory::create(demux_t *realdemux, const StreamFormat &format,
SegmentTracker *tracker, AbstractConnectionManager *manager) const
{
HLSStream *stream = new (std::nothrow) HLSStream(realdemux);
- if(stream && !stream->init(StreamFormat(StreamFormat::UNKNOWN), tracker, manager))
+ if(stream && !stream->init(format, tracker, manager))
{
delete stream;
return NULL;
diff --git a/modules/demux/hls/playlist/Parser.cpp b/modules/demux/hls/playlist/Parser.cpp
index d5b65cd15e..54e18d8819 100644
--- a/modules/demux/hls/playlist/Parser.cpp
+++ b/modules/demux/hls/playlist/Parser.cpp
@@ -74,36 +74,6 @@ static void releaseTagsList(std::list<Tag *> &list)
list.clear();
}
-void M3U8Parser::setFormatFromExtension(Representation *rep, const std::string &filename)
-{
- std::size_t pos = filename.find_last_of('.');
- if(pos != std::string::npos)
- {
- std::string extension = Helper::getFileExtension(filename);
- transform(extension.begin(), extension.end(), extension.begin(), (int (*)(int))std::tolower);
- if(extension == "aac")
- {
- rep->streamFormat = StreamFormat(StreamFormat::PACKEDAAC);
- }
- else if(extension == "ts" || extension == "mp2t" || extension == "mpeg" || extension == "m2ts")
- {
- rep->streamFormat = StreamFormat(StreamFormat::MPEG2TS);
- }
- else if(extension == "mp4" || extension == "m4s" || extension == "mov" || extension == "m4v")
- {
- rep->streamFormat = StreamFormat(StreamFormat::MP4);
- }
- else if(extension == "vtt" || extension == "wvtt" || extension == "webvtt")
- {
- rep->streamFormat = StreamFormat(StreamFormat::WEBVTT);
- }
- else
- {
- rep->streamFormat = StreamFormat(StreamFormat::UNSUPPORTED);
- }
- }
-}
-
Representation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag)
{
const Attribute *uriAttr = tag->getAttributeByName("URI");
@@ -241,8 +211,6 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
break;
segment->setSourceUrl(uritag->getValue().value);
- if((unsigned)rep->getStreamFormat() == StreamFormat::UNKNOWN)
- setFormatFromExtension(rep, uritag->getValue().value);
/* Need to use EXTXTARGETDURATION as default as some can't properly set segment one */
double duration = rep->targetDuration;
diff --git a/modules/demux/hls/playlist/Parser.hpp b/modules/demux/hls/playlist/Parser.hpp
index e46ae15b30..dc2c148e78 100644
--- a/modules/demux/hls/playlist/Parser.hpp
+++ b/modules/demux/hls/playlist/Parser.hpp
@@ -68,7 +68,6 @@ namespace hls
void createAndFillRepresentation(vlc_object_t *, BaseAdaptationSet *,
const AttributesTag *, const std::list<Tag *>&);
void parseSegments(vlc_object_t *, Representation *, const std::list<Tag *>&);
- void setFormatFromExtension(Representation *rep, const std::string &);
std::list<Tag *> parseEntries(stream_t *);
AuthStorage *auth;
};
More information about the vlc-commits
mailing list