Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (8)
Showing
with 475 additions and 97 deletions
......@@ -39,6 +39,11 @@ ID::ID(uint64_t id_)
id = ss.str();
}
bool ID::isValid() const
{
return !id.empty();
}
bool ID::operator==(const ID &other) const
{
return (!id.empty() && id == other.id);
......
......@@ -33,6 +33,7 @@ namespace adaptive
bool operator==(const ID &) const;
bool operator<(const ID &) const;
std::string str() const;
bool isValid() const;
private:
std::string id;
......
......@@ -161,6 +161,8 @@ bool PlaylistManager::init(bool b_preparsing)
playlist->playbackStart.Set(time(nullptr));
nextPlaylistupdate = playlist->playbackStart.Get();
if(b_preparsing)
preparsePlaylist();
updateControlsPosition();
return true;
......@@ -422,6 +424,11 @@ bool PlaylistManager::updatePlaylist()
return true;
}
void PlaylistManager::preparsePlaylist()
{
}
Times PlaylistManager::getTimes(bool b_first) const
{
vlc_mutex_locker locker(&demux.lock);
......
......@@ -66,6 +66,7 @@ namespace adaptive
virtual bool needsUpdate() const;
virtual bool updatePlaylist();
virtual void scheduleNextUpdate();
virtual void preparsePlaylist();
/* static callbacks */
static int control_callback(demux_t *, int, va_list);
......@@ -105,6 +106,7 @@ namespace adaptive
demux_t *p_demux;
std::vector<AbstractStream *> streams;
BasePeriod *currentPeriod;
bool b_preparsing;
enum class TimestampSynchronizationPoint
{
......@@ -151,7 +153,6 @@ namespace adaptive
bool b_buffering;
bool b_canceled;
mtime_t pause_start;
bool b_preparsing;
};
}
......
......@@ -596,18 +596,22 @@ bool SegmentTracker::bufferingAvailable() const
return true;
}
void SegmentTracker::updateSelected()
bool SegmentTracker::updateSelected()
{
bool b_updated;
if(current.rep && current.rep->needsUpdate(next.number))
{
bool b_updated = current.rep->runLocalUpdates(resources);
b_updated = current.rep->runLocalUpdates(resources);
current.rep->scheduleNextUpdate(current.number, b_updated);
if(b_updated)
notify(RepresentationUpdatedEvent(current.rep));
}
else b_updated = false;
if(current.rep && current.rep->canNoLongerUpdate())
notify(RepresentationUpdateFailedEvent(current.rep));
return b_updated;
}
void SegmentTracker::notify(const TrackerEvent &event) const
......
......@@ -235,7 +235,7 @@ namespace adaptive
void notifyBufferingState(bool) const;
void notifyBufferingLevel(mtime_t, mtime_t, mtime_t, mtime_t) const;
void registerListener(SegmentTrackerListenerInterface *);
void updateSelected();
bool updateSelected();
bool bufferingAvailable() const;
private:
......
......@@ -727,10 +727,15 @@ bool AbstractStream::getMediaAdvanceAmount(mtime_t *duration) const
return true;
}
void AbstractStream::runUpdates()
bool AbstractStream::runUpdates(bool)
{
if(valid && !disabled)
segmentTracker->updateSelected();
if(!valid)
return false;
if(!disabled)
return segmentTracker->updateSelected();
else
return false;
}
void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
......
......@@ -102,7 +102,7 @@ namespace adaptive
virtual bool setPosition(const StreamPosition &, bool);
bool getMediaPlaybackTimes(mtime_t *, mtime_t *, mtime_t *) const;
bool getMediaAdvanceAmount(mtime_t *) const;
void runUpdates();
bool runUpdates(bool = false);
/* Used by demuxers fake streams */
virtual block_t *readNextBlock() override;
......
......@@ -70,7 +70,7 @@ NearOptimalAdaptationLogic::getNextQualityIndex( BaseAdaptationSet *adaptSet, Re
{
BaseRepresentation *ret = nullptr;
BaseRepresentation *prev = nullptr;
float argmax;
float argmax = 0;
for(BaseRepresentation *rep = selector.lowest(adaptSet);
rep && rep != prev; rep = selector.higher(adaptSet, rep))
{
......
......@@ -93,6 +93,11 @@ void CodecDescription::setSampleRate(const Rate &r)
fmt.audio.i_rate = r.num();
}
void CodecDescription::setChannelsCount(unsigned c)
{
fmt.audio.i_channels = c;
}
CodecDescriptionList::CodecDescriptionList()
{
......
......@@ -44,6 +44,7 @@ namespace adaptive
void setAspectRatio(const AspectRatio &);
void setFrameRate(const Rate &);
void setSampleRate(const Rate &);
void setChannelsCount(unsigned);
protected:
es_format_t fmt;
......
......@@ -27,6 +27,7 @@
#include "../../playlist/BaseAdaptationSet.h"
#include "../../playlist/BaseRepresentation.h"
#include "../../logic/BufferingLogic.hpp"
#include "../../tools/FormatNamespace.hpp"
#include "../../SegmentTracker.hpp"
#include "../../../hls/playlist/Parser.hpp"
#include "../../../hls/playlist/M3U8.hpp"
......@@ -125,10 +126,10 @@ int M3U8MasterPlaylist_test()
{
Expect(m3u);
Expect(m3u->getPeriods().size() == 1);
Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 4);
Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);
BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("aac English"));
Expect(set);
Expect(set->getRepresentations().size() == 1);
Expect(set->getRepresentations().size() == 2);
Expect(set->getLang() == "en");
Expect(set->getRole().autoSelectable());
Expect(set->getRole().isDefault());
......@@ -140,6 +141,131 @@ int M3U8MasterPlaylist_test()
return 1;
}
/* Empty MEDIA URI property group propagation test */
{
const char srcmanifest[] =
"#EXTM3U\n"
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aach-64\",NAME=\"audio 64\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aacl-128\",NAME=\"audio 128\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=75000,AVERAGE-BANDWIDTH=70000,CODECS=\"mp4a.40.5\",AUDIO=\"aach-64\"\n"
"streaminf0.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=150000,AVERAGE-BANDWIDTH=125000,CODECS=\"mp4a.40.2\",AUDIO=\"aacl-128\"\n"
"streaminf1.m3u8\n"
;
m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
try
{
Expect(m3u);
Expect(m3u->getFirstPeriod());
Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 1);
BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSets().front();
Expect(set->getRole().autoSelectable());
Expect(set->getRole().isDefault());
auto reps = set->getRepresentations();
Expect(reps.size() == 2);
Expect(reps[0]->getBandwidth() == 70000);
Expect(reps[1]->getBandwidth() == 125000);
FormatNamespace fns("mp4a.40.5");
CodecDescriptionList codecsdesclist;
reps[0]->getCodecsDesc(&codecsdesclist);
Expect(codecsdesclist.size() == 1);
const es_format_t *fmt = codecsdesclist.front()->getFmt();
Expect(fmt != nullptr);
Expect(fmt->i_codec == fns.getFmt()->i_codec);
Expect(fmt->i_profile == fns.getFmt()->i_profile);
Expect(fmt->i_cat == AUDIO_ES);
Expect(fmt->audio.i_channels == 2);
delete m3u;
}
catch (...)
{
delete m3u;
return 1;
}
}
/* check codec assignment per group */
{
const char srcmanifest[] =
"#EXTM3U\n"
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"Audio\",NAME=\"en_aud\",DEFAULT=YES,AUTOSELECT=YES,"
" LANGUAGE=\"en\",CHANNELS=\"2\",URI=\"a0.m3u8\"\n"
"#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"Subtitles\",NAME=\"sub_fr\",DEFAULT=YES,FORCED=NO,LANGUAGE=\"fr\","
" URI=\"cc0.m3u8\"\n"
"#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"Closed Captions\",NAME=\"cc_en\",DEFAULT=YES,AUTOSELECT=YES,"
" LANGUAGE=\"en\",INSTREAM-ID=\"CC1\"\n"
"#EXT-X-STREAM-INF:BANDWIDTH=629758,AVERAGE-BANDWIDTH=572508,RESOLUTION=426x240,CODECS=\"avc1.42E015,mp4a.40.2,wvtt\","
" FRAME-RATE=25,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
"v0.m3u8\n"
"#EXT-X-STREAM-INF:BANDWIDTH=1069758,AVERAGE-BANDWIDTH=972508,RESOLUTION=640x360,CODECS=\"avc1.4D401E,mp4a.40.2,wvtt\","
" FRAME-RATE=29.970,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
"v1.m3u8\n"
;
m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
try
{
Expect(m3u);
Expect(m3u->getFirstPeriod());
Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);
{
auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Audio en_aud"));
Expect(set != nullptr);
auto reps = set->getRepresentations();
Expect(reps.size() == 1);
FormatNamespace fns("mp4a.40.2");
CodecDescriptionList codecsdesclist;
reps[0]->getCodecsDesc(&codecsdesclist);
Expect(codecsdesclist.size() == 1);
const es_format_t *fmt = codecsdesclist.front()->getFmt();
Expect(fmt != nullptr);
Expect(fmt->i_codec == fns.getFmt()->i_codec);
Expect(fmt->i_cat == AUDIO_ES);
Expect(fmt->audio.i_channels == 2);
}
{
auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Subtitles sub_fr"));
Expect(set != nullptr);
auto reps = set->getRepresentations();
Expect(reps.size() == 1);
FormatNamespace fns("wvtt");
CodecDescriptionList codecsdesclist;
reps[0]->getCodecsDesc(&codecsdesclist);
Expect(codecsdesclist.size() == 1);
const es_format_t *fmt = codecsdesclist.front()->getFmt();
Expect(fmt != nullptr);
Expect(fmt->i_codec == fns.getFmt()->i_codec);
Expect(fmt->i_cat == SPU_ES);
}
{
auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("default_id#0"));
Expect(set != nullptr);
auto reps = set->getRepresentations();
Expect(reps.size() == 2);
FormatNamespace fns("avc1.42E015");
CodecDescriptionList codecsdesclist;
reps[0]->getCodecsDesc(&codecsdesclist);
Expect(codecsdesclist.size() == 1);
const es_format_t *fmt = codecsdesclist.front()->getFmt();
Expect(fmt != nullptr);
Expect(fmt->i_codec == fns.getFmt()->i_codec);
Expect(fmt->i_cat == VIDEO_ES);
}
delete m3u;
}
catch (...)
{
delete m3u;
return 1;
}
}
return 0;
}
......@@ -420,6 +546,5 @@ int M3U8Playlist_test()
return 1;
}
return 0;
}
......@@ -48,6 +48,7 @@ HLSRepresentation::HLSRepresentation ( BaseAdaptationSet *set ) :
lastUpdateTime = 0;
targetDuration = 0;
streamFormat = StreamFormat::Type::Unknown;
channels = 0;
}
HLSRepresentation::~HLSRepresentation ()
......@@ -178,6 +179,21 @@ bool HLSRepresentation::canNoLongerUpdate() const
return updateFailureCount > MAX_UPDATE_FAILED_UPDATE_COUNT;
}
void HLSRepresentation::setChannelsCount(unsigned c)
{
channels = c;
}
CodecDescription * HLSRepresentation::makeCodecDescription(const std::string &s) const
{
CodecDescription *desc = BaseRepresentation::makeCodecDescription(s);
if(desc)
{
desc->setChannelsCount(channels);
}
return desc;
}
uint64_t HLSRepresentation::translateSegmentNumber(uint64_t num, const BaseRepresentation *from) const
{
if(targetDuration == static_cast<const HLSRepresentation *>(from)->targetDuration)
......
......@@ -54,6 +54,9 @@ namespace hls
virtual bool canNoLongerUpdate() const override;
virtual uint64_t translateSegmentNumber(uint64_t, const BaseRepresentation *) const override;
virtual CodecDescription * makeCodecDescription(const std::string &) const override;
void setChannelsCount(unsigned);
protected:
time_t targetDuration;
......@@ -66,6 +69,7 @@ namespace hls
bool b_loaded;
unsigned updateFailureCount;
mtime_t lastUpdateTime;
unsigned channels;
};
}
}
......
......@@ -32,6 +32,7 @@
#include "../../adaptive/tools/Retrieve.hpp"
#include "../../adaptive/tools/Helper.h"
#include "../../adaptive/tools/Conversions.hpp"
#include "../../adaptive/tools/FormatNamespace.hpp"
#include "M3U8.hpp"
#include "Tags.hpp"
......@@ -39,7 +40,8 @@
#include <vlc_stream.h>
#include <cstdio>
#include <sstream>
#include <map>
#include <array>
#include <unordered_map>
#include <cctype>
#include <algorithm>
#include <limits>
......@@ -91,7 +93,9 @@ static void releaseTagsList(std::list<Tag *> &list)
HLSRepresentation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag)
{
const Attribute *uriAttr = tag->getAttributeByName("URI");
const Attribute *bwAttr = tag->getAttributeByName("BANDWIDTH");
const Attribute *bwAttr = tag->getAttributeByName("AVERAGE-BANDWIDTH");
if(!bwAttr)
bwAttr = tag->getAttributeByName("BANDWIDTH");
const Attribute *resAttr = tag->getAttributeByName("RESOLUTION");
HLSRepresentation *rep = new (std::nothrow) HLSRepresentation(adaptSet);
......@@ -121,9 +125,6 @@ HLSRepresentation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet
if(bwAttr)
rep->setBandwidth(bwAttr->decimal());
if(tag->getAttributeByName("CODECS"))
rep->addCodecs(tag->getAttributeByName("CODECS")->quotedString());
if(resAttr)
{
std::pair<int, int> res = resAttr->getResolution();
......@@ -159,6 +160,68 @@ void M3U8Parser::createAndFillRepresentation(vlc_object_t *p_obj, BaseAdaptation
}
}
void M3U8Parser::fillRepresentationFromMediainfo(const AttributesTag *mediatag,
const std::string &type,
HLSRepresentation *rep)
{
if(type == "AUDIO")
{
const Attribute *channelsAttr = mediatag->getAttributeByName("CHANNELS");
if(channelsAttr)
rep->setChannelsCount(std::atoi(channelsAttr->quotedString().c_str()));
}
if(type != "AUDIO" && type != "VIDEO" && type != "SUBTITLES")
{
rep->streamFormat = StreamFormat(StreamFormat::Type::Unsupported);
}
}
void M3U8Parser::fillAdaptsetFromMediainfo(const AttributesTag *mediatag,
const std::string &type,
const std::string &group,
BaseAdaptationSet *altAdaptSet)
{
if(mediatag->getAttributeByName("DEFAULT"))
{
if(mediatag->getAttributeByName("DEFAULT")->value == "YES")
altAdaptSet->setRole(Role(Role::Value::Main));
else
altAdaptSet->setRole(Role(Role::Value::Alternate));
}
if(mediatag->getAttributeByName("AUTOSELECT"))
{
if(mediatag->getAttributeByName("AUTOSELECT")->value == "NO" &&
!mediatag->getAttributeByName("DEFAULT"))
altAdaptSet->setRole(Role(Role::Value::Supplementary));
}
/* Subtitles unsupported for now */
if(type == "SUBTITLES")
{
altAdaptSet->setRole(Role(Role::Value::Subtitle));
}
if(mediatag->getAttributeByName("LANGUAGE"))
altAdaptSet->setLang(mediatag->getAttributeByName("LANGUAGE")->quotedString());
std::string desc = group;
const Attribute *nameAttr = mediatag->getAttributeByName("NAME");
if(nameAttr)
{
if(!desc.empty())
desc += " ";
desc += nameAttr->quotedString();
}
if(!desc.empty())
{
altAdaptSet->description.Set(desc);
altAdaptSet->setID(ID(desc));
}
}
bool M3U8Parser::appendSegmentsFromPlaylistURI(vlc_object_t *p_obj, HLSRepresentation *rep)
{
block_t *p_block = Retrieve::HTTP(resources, ChunkType::Playlist, rep->getPlaylistUrl().toString());
......@@ -425,11 +488,12 @@ M3U8 * M3U8Parser::parse(vlc_object_t *p_object, stream_t *p_stream, const std::
return playlist;
std::list<Tag *> tagslist = parseEntries(p_stream);
bool b_masterplaylist = !getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF).empty();
std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
bool b_masterplaylist = !streaminfotags.empty();
if(b_masterplaylist)
{
std::list<Tag *>::const_iterator it;
std::map<std::string, AttributesTag *> groupsmap;
std::list<BaseAdaptationSet *> setstoadd;
/* Preload Session Key */
Tag *sessionKey = getTagFromList(tagslist, AttributesTag::EXTXSESSIONKEY);
......@@ -446,119 +510,255 @@ M3U8 * M3U8Parser::parse(vlc_object_t *p_object, stream_t *p_stream, const std::
/* We'll need to create an adaptation set for each media group / alternative rendering
* we create a list of playlist being and alternative/group */
struct typecat_s
{
const char *type;
es_format_category_e cat;
};
std::array<struct typecat_s, 3> const typescats =
{{
{ "AUDIO", AUDIO_ES },
{ "VIDEO", VIDEO_ES },
{ "SUBTITLES", SPU_ES },
}};
struct StreamCodec
{
std::string codec;
es_format_category_e cat;
};
struct StreamInfos
{
const AttributesTag *tag;
std::string uri;
HLSRepresentation *rep;
std::list<struct StreamCodec> codecs;
};
std::list<struct StreamInfos> streaminfolist;
struct MediaInfos
{
const AttributesTag *tag;
std::string uri;
std::string group;
};
using CodecStats = std::unordered_map<std::string, unsigned>;
std::unordered_map<std::string, CodecStats> groupsmap;
std::list<struct MediaInfos> mediainfos;
/* create group info */
std::list<Tag *> mediainfotags = getTagsFromList(tagslist, AttributesTag::EXTXMEDIA);
for(it = mediainfotags.begin(); it != mediainfotags.end(); ++it)
{
AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
if(tag && tag->getAttributeByName("URI"))
{
std::pair<std::string, AttributesTag *> pair(tag->getAttributeByName("URI")->quotedString(), tag);
groupsmap.insert(pair);
}
if(!tag)
continue;
const Attribute *groupid = tag->getAttributeByName("GROUP-ID");
if(!groupid) /* invalid */
continue;
const Attribute *uri = tag->getAttributeByName("URI");
MediaInfos entry;
entry.tag = tag;
entry.uri = uri ? uri->quotedString() : std::string();
entry.group = groupid->quotedString();
groupsmap.insert(std::pair<std::string, CodecStats>(entry.group, CodecStats()));
mediainfos.push_back(entry);
}
/* Then we parse all playlists uri and add them, except when alternative */
BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(adaptSet)
/* Gather info from EXT-X-STREAMINF */
for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
{
/* adaptSet->setSegmentAligned(true); FIXME: based on streamformat */
std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
if(!tag)
continue;
const Attribute *uri = tag->getAttributeByName("URI");
if(!uri)
continue;
StreamInfos entry;
entry.tag = tag;
entry.uri = uri->quotedString();
entry.rep = nullptr;
const Attribute *codecsAttr = tag->getAttributeByName("CODECS");
if(codecsAttr)
{
AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
if(tag && tag->getAttributeByName("URI"))
auto codecs = Helper::tokenize(codecsAttr->quotedString(), ',');
for(auto codec : codecs)
{
FormatNamespace fns(codec);
struct StreamCodec s;
s.cat = fns.getFmt()->i_cat;
s.codec = codec;
entry.codecs.push_front(s);
}
/* create codec reference count info per group */
std::list<std::string> mediasCodecs;
for(auto typecat : typescats)
{
if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end())
if(tag->getAttributeByName(typecat.type))
{
/* not a group, belong to default adaptation set */
HLSRepresentation *rep = createRepresentation(adaptSet, tag);
if(rep)
for(auto codec : entry.codecs)
{
adaptSet->addRepresentation(rep);
if(codec.cat == typecat.cat)
{
auto mit = groupsmap.find(tag->getAttributeByName(typecat.type)->quotedString());
if(mit != groupsmap.cend())
{
auto eit = (*mit).second.find(codec.codec);
if(eit != (*mit).second.end())
++(*eit).second;
else
(*mit).second.insert(std::pair<std::string, unsigned>(codec.codec, 0));
mediasCodecs.push_front(codec.codec);
}
break;
}
}
}
}
/* remove most frequent group codecs from streaminfo */
for(auto codec : mediasCodecs)
entry.codecs.remove_if([codec, entry](struct StreamCodec &v)
{ return v.codec == codec && entry.codecs.size() > 1; });
/* deduplicate codecs by category as variants can have different profile */
entry.codecs.sort([](const struct StreamCodec &a, const struct StreamCodec &b)
{ return a.cat < b.cat ; });
entry.codecs.unique([](const struct StreamCodec &a, const struct StreamCodec &b)
{ return a.cat == b.cat ; });
}
if(!adaptSet->getRepresentations().empty())
period->addAdaptationSet(adaptSet);
else
delete adaptSet;
streaminfolist.push_back(entry);
}
/* Finally add all groups */
unsigned set_id = 1;
std::map<std::string, AttributesTag *>::const_iterator groupsit;
for(groupsit = groupsmap.begin(); groupsit != groupsmap.end(); ++groupsit)
/* process all EXT-X-STREAMINF and add them */
BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(adaptSet)
{
std::pair<std::string, AttributesTag *> pair = *groupsit;
if(!pair.second->getAttributeByName("TYPE"))
continue;
BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(altAdaptSet)
/* adaptSet->setSegmentAligned(true); FIXME: based on streamformat */
for(auto &info : streaminfolist)
{
HLSRepresentation *rep = createRepresentation(altAdaptSet, pair.second);
if(rep)
{
altAdaptSet->addRepresentation(rep);
}
if(info.uri.empty())
continue;
std::string desc;
if(pair.second->getAttributeByName("GROUP-ID"))
desc = pair.second->getAttributeByName("GROUP-ID")->quotedString();
if(pair.second->getAttributeByName("NAME"))
{
if(!desc.empty())
desc += " ";
desc += pair.second->getAttributeByName("NAME")->quotedString();
}
HLSRepresentation *rep = createRepresentation(adaptSet, info.tag);
if(!rep)
continue;
if(pair.second->getAttributeByName("CODECS"))
rep->addCodecs(pair.second->getAttributeByName("CODECS")->quotedString());
for(auto codec: info.codecs)
rep->addCodecs(codec.codec);
if(!desc.empty())
if(adaptSet->description.Get().empty() &&
info.tag->getAttributeByName("NAME"))
{
altAdaptSet->description.Set(desc);
altAdaptSet->setID(ID(desc));
adaptSet->description.Set(info.tag->getAttributeByName("NAME")->quotedString());
}
else altAdaptSet->setID(ID(set_id++));
if(pair.second->getAttributeByName("DEFAULT"))
{
if(pair.second->getAttributeByName("DEFAULT")->value == "YES")
altAdaptSet->setRole(Role(Role::Value::Main));
else
altAdaptSet->setRole(Role(Role::Value::Alternate));
}
adaptSet->addRepresentation(rep);
info.rep = rep;
}
if(pair.second->getAttributeByName("AUTOSELECT"))
{
if(pair.second->getAttributeByName("AUTOSELECT")->value == "NO" &&
!pair.second->getAttributeByName("DEFAULT"))
altAdaptSet->setRole(Role(Role::Value::Supplementary));
}
if(adaptSet->getRepresentations().empty())
{
delete adaptSet;
adaptSet = nullptr;
}
else setstoadd.push_front(adaptSet);
}
/* Finally add all EXT-X-MEDIA or propagate their attributes */
for(auto mediainfo : mediainfos)
{
const Attribute *typeattr = mediainfo.tag->getAttributeByName("TYPE");
if(!typeattr)
continue;
const std::string &mediatype = typeattr->value;
/* Subtitles unsupported for now */
const Attribute *typeattr = pair.second->getAttributeByName("TYPE");
if(typeattr->value == "SUBTITLES")
const StreamInfos *matchedstreaminf = nullptr;
if(!mediainfo.uri.empty())
{
auto sit = std::find_if(streaminfolist.begin(), streaminfolist.end(),
[mediainfo] (StreamInfos &si)
{ return si.uri == mediainfo.uri; });
if(sit != streaminfolist.end())
matchedstreaminf = & (*sit);
};
if(mediainfo.uri.empty() || matchedstreaminf) /* Attributes do apply to group STREAMINF members */
{
if(mediatype == "AUDIO" || mediatype == "VIDEO")
for(StreamInfos &si : streaminfolist)
{
altAdaptSet->setRole(Role(Role::Value::Subtitle));
if(matchedstreaminf && matchedstreaminf != &si)
continue;
const Attribute *groupattr = si.tag->getAttributeByName(mediatype.c_str());
if(groupattr && groupattr->quotedString() == mediainfo.group)
{
if(si.rep)
{
fillAdaptsetFromMediainfo(mediainfo.tag, typeattr->value,
mediainfo.group, si.rep->getAdaptationSet());
if(!matchedstreaminf || matchedstreaminf == &si)
fillRepresentationFromMediainfo(mediainfo.tag, typeattr->value, si.rep);
}
}
}
else if(typeattr->value != "AUDIO" && typeattr->value != "VIDEO")
}
else /* This is an alternative in the group */
{
BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(altAdaptSet)
{
rep->streamFormat = StreamFormat(StreamFormat::Type::Unsupported);
}
fillAdaptsetFromMediainfo(mediainfo.tag, typeattr->value, mediainfo.group, altAdaptSet);
if(pair.second->getAttributeByName("LANGUAGE"))
altAdaptSet->setLang(pair.second->getAttributeByName("LANGUAGE")->quotedString());
HLSRepresentation *rep = createRepresentation(altAdaptSet, mediainfo.tag);
if(!rep)
{
delete altAdaptSet;
continue;
}
if(!altAdaptSet->getRepresentations().empty())
period->addAdaptationSet(altAdaptSet);
else
delete altAdaptSet;
fillRepresentationFromMediainfo(mediainfo.tag, typeattr->value, rep);
/* assign group codecs to adaptset */
auto groupmapit = groupsmap.find(mediainfo.group);
if(groupmapit != groupsmap.end())
{
for(auto p : (*groupmapit).second)
{
FormatNamespace fns(p.first);
for(auto typecat : typescats)
{
if((fns.getFmt()->i_cat == typecat.cat && typeattr->value == typecat.type))
{
rep->addCodecs(p.first);
break;
}
}
}
}
altAdaptSet->addRepresentation(rep);
setstoadd.push_front(altAdaptSet);
}
}
}
/* late add to keep it ordered */
unsigned set_id = 1;
for(auto set : setstoadd)
{
if(!set->getID().isValid())
set->setID(ID(set_id++));
period->addAdaptationSet(set);
}
}
else /* Non master playlist (opened directly subplaylist or HLS v1) */
{
......
......@@ -65,6 +65,10 @@ namespace hls
HLSRepresentation * createRepresentation(BaseAdaptationSet *, const AttributesTag *);
void createAndFillRepresentation(vlc_object_t *, BaseAdaptationSet *,
const AttributesTag *, const std::list<Tag *>&);
void fillRepresentationFromMediainfo(const AttributesTag *, const std::string &,
HLSRepresentation *);
void fillAdaptsetFromMediainfo(const AttributesTag *, const std::string &,
const std::string &, BaseAdaptationSet *);
void parseSegments(vlc_object_t *, HLSRepresentation *, const std::list<Tag *>&);
std::list<Tag *> parseEntries(stream_t *);
adaptive::SharedResources *resources;
......