diff --git a/XBMC.files b/XBMC.files
index d8a0ab4f42..37f1e0b501 100644
--- a/XBMC.files
+++ b/XBMC.files
@@ -9845,25 +9845,6 @@ xbmc/interfaces/builtins/WeatherBuiltins.h
tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCProperties.java.in
xbmc/android/jni/AudioDeviceInfo.cpp
xbmc/android/jni/AudioDeviceInfo.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentObserver.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.h
-xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.h
-xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.cpp
-xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.h
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNULL.h
xbmc/cores/dvdplayer/Makefile.in
xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
@@ -9974,3 +9955,28 @@ xbmc/android/jni/PlaybackState.h
xbmc/android/jni/PlaybackState.cpp
xbmc/android/jni/BitmapFactory.h
xbmc/android/jni/BitmapFactory.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/dash/SmoothTree.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/dash/SmoothTree.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentObserver.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.h
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.h
+xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.cpp
+xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.h
diff --git a/XBMC.includes b/XBMC.includes
index 51a0589ea6..552fee1ee3 100644
--- a/XBMC.includes
+++ b/XBMC.includes
@@ -2866,7 +2866,6 @@ xbmc/video/jobs
xbmc/video/videosync
tools/android/packaging/xbmc/src/org/xbmc/kodi
system/shaders
-xbmc/cores/dvdplayer/DVDInputStreams/dash
tools/android/packaging/xbmc/res/layout
tools/android/packaging/xbmc/res/values
.
@@ -2882,3 +2881,6 @@ lib/libUPnP
xbmc/network/android
xbmc/listproviders
tools/android/packaging/xbmc/src/org/xbmc/kodi/interfaces
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers
+xbmc/cores/dvdplayer/DVDDemuxers/adaptive
diff --git a/tools/depends/target/bento4/Makefile b/tools/depends/target/bento4/Makefile
index 2d481e4b6f..9a437dc233 100644
--- a/tools/depends/target/bento4/Makefile
+++ b/tools/depends/target/bento4/Makefile
@@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile
# lib name, version
LIBNAME=Bento4
-VERSION=HEAD
+VERSION=inputstream
SOURCE=archive
ARCHIVE=$(VERSION).tar.gz
GIT_BASE_URL=https://github.com/koying
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.cpp
new file mode 100644
index 0000000000..15eee239e6
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2016 Christian Browet
+ * Copyright (C) 2016-2016 peak3d
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * .
+ *
+ */
+
+#include "DVDDemuxAdaptive.h"
+
+#include "DVDDemuxPacket.h"
+#include "DVDDemuxUtils.h"
+#include "DVDInputStreams/DVDInputStream.h"
+
+#include "adaptive/DASHByteStream.h"
+
+#ifdef TARGET_ANDROID
+#include "android/jni/SystemProperties.h"
+#endif
+#ifdef TARGET_WINDOWS
+#pragma comment(lib, "libexpat.lib")
+#pragma comment(lib, "ap4.lib")
+#endif
+
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+CDVDDemuxAdaptive::CDVDDemuxAdaptive()
+ : CDVDDemux()
+{
+ CLog::Log(LOGDEBUG, "CDVDDemuxAdaptive::%s", __FUNCTION__);
+}
+
+CDVDDemuxAdaptive::~CDVDDemuxAdaptive()
+{
+ CLog::Log(LOGDEBUG, "CDVDDemuxAdaptive::%s", __FUNCTION__);
+}
+
+bool CDVDDemuxAdaptive::Open(CDVDInputStream* pInput, uint32_t maxWidth, uint32_t maxHeight)
+{
+ CLog::Log(LOGINFO, "CDVDDemuxAdaptive - matching against %d x %d", maxWidth, maxHeight);
+
+ CDASHSession::MANIFEST_TYPE type = CDASHSession::MANIFEST_TYPE_UNKNOWN;
+
+ if (pInput->GetFileItem().GetMimeType() == "video/vnd.mpeg.dash.mpd" || pInput->GetFileItem().IsType(".mpd")) //MPD
+ type = CDASHSession::MANIFEST_TYPE_MPD;
+ else if (pInput->GetFileItem().GetMimeType() == "application/vnd.ms-sstr+xml" || pInput->GetFileItem().IsType(".ismc") || pInput->GetFileItem().IsType(".ism")) //ISM
+ type = CDASHSession::MANIFEST_TYPE_ISM;
+
+ if (type == CDASHSession::MANIFEST_TYPE_UNKNOWN)
+ return false;
+
+ m_session.reset(new CDASHSession(type, pInput->GetFileName(), maxWidth, maxHeight, "", "", "special://profile/"));
+
+ if (!m_session->initialize())
+ {
+ m_session = nullptr;
+ return false;
+ }
+ return true;
+}
+
+void CDVDDemuxAdaptive::Dispose()
+{
+}
+
+void CDVDDemuxAdaptive::Reset()
+{
+}
+
+void CDVDDemuxAdaptive::Abort()
+{
+}
+
+void CDVDDemuxAdaptive::Flush()
+{
+}
+
+DemuxPacket*CDVDDemuxAdaptive::Read()
+{
+ if (!m_session)
+ return NULL;
+
+ CDASHFragmentedSampleReader *sr(m_session->GetNextSample());
+
+ if (m_session->CheckChange())
+ {
+ DemuxPacket *p = CDVDDemuxUtils::AllocateDemuxPacket(0);
+ p->iStreamId = DMX_SPECIALID_STREAMCHANGE;
+ CLog::Log(LOGDEBUG, "DMX_SPECIALID_STREAMCHANGE");
+ return p;
+ }
+
+ if (sr)
+ {
+ DemuxPacket *p = CDVDDemuxUtils::AllocateDemuxPacket(sr->GetSampleDataSize());
+ p->dts = sr->DTS() * 1000000;
+ p->pts = sr->PTS() * 1000000;
+ p->duration = sr->GetDuration() * 1000000;
+ p->iStreamId = sr->GetStreamId();
+ p->iGroupId = 0;
+ p->iSize = sr->GetSampleDataSize();
+ memcpy(p->pData, sr->GetSampleData(), p->iSize);
+
+ CLog::Log(LOGDEBUG, "DTS: %0.4f, PTS:%0.4f, ID: %u SZ: %d", p->dts, p->pts, p->iStreamId, p->iSize);
+
+ sr->ReadSample();
+ return p;
+ }
+ return NULL;
+}
+
+bool CDVDDemuxAdaptive::SeekTime(int time, bool backwards, double* startpts)
+{
+ if (!m_session)
+ return false;
+
+ return m_session->SeekTime(static_cast(time)*0.001f, 0, !backwards);
+}
+
+void CDVDDemuxAdaptive::SetSpeed(int speed)
+{
+}
+
+int CDVDDemuxAdaptive::GetNrOfStreams()
+{
+ int n = 0;
+ if (m_session)
+ n = m_session->GetStreamCount();
+
+ return n;
+}
+
+CDemuxStream* CDVDDemuxAdaptive::GetStream(int streamid)
+{
+ CDASHSession::STREAM *stream(m_session->GetStream(streamid));
+ if (!stream)
+ {
+ CLog::Log(LOGERROR, "CDVDDemuxAdaptive::GetStream(%d): error getting stream", streamid);
+ return nullptr;
+ }
+
+ return stream->dmuxstrm;
+}
+
+void CDVDDemuxAdaptive::EnableStream(int streamid, bool enable)
+{
+ CLog::Log(LOGDEBUG, "EnableStream(%d: %s)", streamid, enable?"true":"false");
+
+ if (!m_session)
+ return;
+
+ CDASHSession::STREAM *stream(m_session->GetStream(streamid));
+ if (!stream)
+ return;
+
+ if (enable)
+ {
+ if (stream->enabled)
+ return;
+
+ stream->enabled = true;
+
+ stream->stream_.start_stream(~0, m_session->GetWidth(), m_session->GetHeight());
+ const adaptive::AdaptiveTree::Representation *rep(stream->stream_.getRepresentation());
+ CLog::Log(LOGDEBUG, "Selecting stream with conditions: w: %u, h: %u, bw: %u",
+ stream->stream_.getWidth(), stream->stream_.getHeight(), stream->stream_.getBandwidth());
+
+ if (!stream->stream_.select_stream(true, false, stream->dmuxstrm->iPhysicalId >> 16))
+ {
+ CLog::Log(LOGERROR, "Unable to select stream!");
+ return stream->disable();
+ }
+
+ if(rep != stream->stream_.getRepresentation())
+ {
+ m_session->UpdateStream(*stream);
+ m_session->CheckChange(true);
+ }
+
+ stream->input_ = new CDASHByteStream(&stream->stream_);
+ static const AP4_Track::Type TIDC[adaptive::AdaptiveTree::STREAM_TYPE_COUNT] = {
+ AP4_Track::TYPE_UNKNOWN,
+ AP4_Track::TYPE_VIDEO,
+ AP4_Track::TYPE_AUDIO,
+ AP4_Track::TYPE_TEXT };
+
+ AP4_Movie* movie = nullptr;
+ if (m_session->GetManifestType() == CDASHSession::MANIFEST_TYPE_ISM && stream->stream_.getRepresentation()->get_initialization() == nullptr)
+ {
+ //We'll create a Movie out of the things we got from manifest file
+ //note: movie will be deleted in destructor of stream->input_file_
+ movie = new AP4_Movie();
+
+ AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable();
+ AP4_SampleDescription *sample_descryption = new AP4_SampleDescription(AP4_SampleDescription::TYPE_UNKNOWN, 0, 0);
+ if (stream->stream_.getAdaptationSet()->encrypted)
+ {
+ static const AP4_UI08 default_key[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ AP4_ContainerAtom schi(AP4_ATOM_TYPE_SCHI);
+ schi.AddChild(new AP4_TencAtom(AP4_CENC_ALGORITHM_ID_CTR, 8, default_key));
+ sample_descryption = new AP4_ProtectedSampleDescription(0, sample_descryption, 0, AP4_PROTECTION_SCHEME_TYPE_PIFF, 0, "", &schi);
+ }
+ sample_table->AddSampleDescription(sample_descryption);
+
+ movie->AddTrack(new AP4_Track(TIDC[stream->stream_.get_type()], sample_table, ~0, stream->stream_.getRepresentation()->timescale_, 0, stream->stream_.getRepresentation()->timescale_, 0, "", 0, 0));
+ //Create a dumy MOOV Atom to tell Bento4 its a fragmented stream
+ AP4_MoovAtom *moov = new AP4_MoovAtom();
+ moov->AddChild(new AP4_ContainerAtom(AP4_ATOM_TYPE_MVEX));
+ movie->SetMoovAtom(moov);
+ }
+
+ stream->input_file_ = new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance_, true, movie);
+ movie = stream->input_file_->GetMovie();
+ if (movie == NULL)
+ {
+ CLog::Log(LOGERROR, "No MOOV in stream!");
+ return stream->disable();
+ }
+
+ AP4_Track *track = movie->GetTrack(TIDC[stream->stream_.get_type()]);
+ if (!track)
+ {
+ CLog::Log(LOGERROR, "No suitable track found in stream");
+ return stream->disable();
+ }
+
+ stream->reader_ = new CDASHFragmentedSampleReader(stream->input_, movie, track, streamid, m_session->GetSingleSampleDecryptor(), m_session->GetPresentationTimeOffset());
+ stream->reader_->SetObserver(dynamic_cast(m_session.get()));
+
+ if (!stream->dmuxstrm->ExtraSize && stream->reader_->GetExtraDataSize())
+ {
+ // ExtraData is now available......
+ stream->dmuxstrm->ExtraSize = stream->reader_->GetExtraDataSize();
+ stream->dmuxstrm->ExtraData = (uint8_t*)malloc(stream->dmuxstrm->ExtraSize);
+ memcpy((void*)stream->dmuxstrm->ExtraData, stream->reader_->GetExtraData(), stream->dmuxstrm->ExtraSize);
+ // Set the session Changed to force new GetStreamInfo call from kodi -> addon
+ m_session->CheckChange(true);
+ }
+ return;
+ }
+ CLog::Log(LOGDEBUG, ">>>> ERROR");
+ return stream->disable();
+}
+
+int CDVDDemuxAdaptive::GetStreamLength()
+{
+ if (!m_session)
+ return 0;
+
+ return static_cast(m_session->GetTotalTime()*1000);
+}
+
+std::string CDVDDemuxAdaptive::GetFileName()
+{
+ if (!m_session)
+ return "";
+
+ return m_session->GetUrl();
+}
+
+void CDVDDemuxAdaptive::GetStreamCodecName(int iStreamId, std::string& strName)
+{
+ strName = "";
+
+ CDASHSession::STREAM *stream(m_session->GetStream(iStreamId));
+ if (stream)
+ strName = stream->codecName;
+}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.h
similarity index 88%
rename from xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.h
index 0cb7396cba..0c61dcd5da 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxAdaptive.h
@@ -25,13 +25,13 @@
#include
-#include "dash/DASHSession.h"
+#include "adaptive/DASHSession.h"
-class CDVDDemuxMPD : public CDVDDemux
+class CDVDDemuxAdaptive : public CDVDDemux
{
public:
- CDVDDemuxMPD();
- virtual ~CDVDDemuxMPD();
+ CDVDDemuxAdaptive();
+ virtual ~CDVDDemuxAdaptive();
bool Open(CDVDInputStream* pInput, uint32_t maxWidth, uint32_t maxHeight);
void Dispose();
@@ -50,5 +50,5 @@ class CDVDDemuxMPD : public CDVDDemux
virtual void GetStreamCodecName(int iStreamId, std::string &strName);
protected:
- std::shared_ptr m_MPDsession;
+ std::shared_ptr m_session;
};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.cpp
deleted file mode 100644
index 0adb01cec7..0000000000
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxMPD.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2016 Christian Browet
- * Copyright (C) 2016-2016 peak3d
- * http://xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
- *
- */
-
-#include "DVDDemuxMPD.h"
-
-#include "DVDDemuxPacket.h"
-#include "DVDDemuxUtils.h"
-#include "DVDInputStreams/DVDInputStream.h"
-
-#include "dash/DASHByteStream.h"
-
-#ifdef TARGET_ANDROID
-#include "android/jni/SystemProperties.h"
-#endif
-#ifdef TARGET_WINDOWS
-#pragma comment(lib, "libexpat.lib")
-#pragma comment(lib, "ap4.lib")
-#endif
-
-#include "utils/StringUtils.h"
-#include "utils/log.h"
-
-CDVDDemuxMPD::CDVDDemuxMPD()
- : CDVDDemux()
-{
- CLog::Log(LOGDEBUG, "CDVDDemuxMPD::%s", __FUNCTION__);
-}
-
-CDVDDemuxMPD::~CDVDDemuxMPD()
-{
- CLog::Log(LOGDEBUG, "CDVDDemuxMPD::%s", __FUNCTION__);
-}
-
-bool CDVDDemuxMPD::Open(CDVDInputStream* pInput, uint32_t maxWidth, uint32_t maxHeight)
-{
- CLog::Log(LOGINFO, "CDVDInputStreamMPD - matching against %d x %d", maxWidth, maxHeight);
- m_MPDsession.reset(new CDASHSession(pInput->GetFileName(), maxWidth, maxHeight, "", "", "special://profile/"));
-
- if (!m_MPDsession->initialize())
- {
- m_MPDsession = nullptr;
- return false;
- }
- return true;
-}
-
-void CDVDDemuxMPD::Dispose()
-{
-}
-
-void CDVDDemuxMPD::Reset()
-{
-}
-
-void CDVDDemuxMPD::Abort()
-{
-}
-
-void CDVDDemuxMPD::Flush()
-{
-}
-
-DemuxPacket*CDVDDemuxMPD::Read()
-{
- if (!m_MPDsession)
- return NULL;
-
- CDASHFragmentedSampleReader *sr(m_MPDsession->GetNextSample());
-
- if (m_MPDsession->CheckChange())
- {
- DemuxPacket *p = CDVDDemuxUtils::AllocateDemuxPacket(0);
- p->iStreamId = DMX_SPECIALID_STREAMCHANGE;
- CLog::Log(LOGDEBUG, "DMX_SPECIALID_STREAMCHANGE");
- return p;
- }
-
- if (sr)
- {
- DemuxPacket *p = CDVDDemuxUtils::AllocateDemuxPacket(sr->GetSampleDataSize());
- p->dts = sr->DTS() * 1000000;
- p->pts = sr->PTS() * 1000000;
- p->duration = sr->GetDuration() * 1000000;
- p->iStreamId = sr->GetStreamId();
- p->iGroupId = 0;
- p->iSize = sr->GetSampleDataSize();
- memcpy(p->pData, sr->GetSampleData(), p->iSize);
-
- //CLog::Log(LOGDEBUG, "DTS: %0.4f, PTS:%0.4f, ID: %u SZ: %d", p->dts, p->pts, p->iStreamId, p->iSize);
-
- sr->ReadSample();
- return p;
- }
- return NULL;
-}
-
-bool CDVDDemuxMPD::SeekTime(int time, bool backwards, double* startpts)
-{
- if (!m_MPDsession)
- return false;
-
- return m_MPDsession->SeekTime(static_cast(time)*0.001f, 0, !backwards);
-}
-
-void CDVDDemuxMPD::SetSpeed(int speed)
-{
-}
-
-int CDVDDemuxMPD::GetNrOfStreams()
-{
- int n = 0;
- if (m_MPDsession)
- n = m_MPDsession->GetStreamCount();
-
- return n;
-}
-
-CDemuxStream* CDVDDemuxMPD::GetStream(int streamid)
-{
- CDASHSession::STREAM *stream(m_MPDsession->GetStream(streamid));
- if (!stream)
- {
- CLog::Log(LOGERROR, "CDVDDemuxMPD::GetStream(%d): error getting stream", streamid);
- return nullptr;
- }
-
- return stream->dmuxstrm;
-}
-
-void CDVDDemuxMPD::EnableStream(int streamid, bool enable)
-{
- CLog::Log(LOGDEBUG, "EnableStream(%d: %s)", streamid, enable?"true":"false");
-
- if (!m_MPDsession)
- return;
-
- CDASHSession::STREAM *stream(m_MPDsession->GetStream(streamid));
- if (!stream)
- return;
-
- if (enable)
- {
- if (stream->enabled)
- return;
-
- stream->enabled = true;
-
- stream->stream_.start_stream(~0, m_MPDsession->GetWidth(), m_MPDsession->GetHeight());
- const dash::DASHTree::Representation *rep(stream->stream_.getRepresentation());
- CLog::Log(LOGDEBUG, "Selecting stream with conditions: w: %u, h: %u, bw: %u",
- stream->stream_.getWidth(), stream->stream_.getHeight(), stream->stream_.getBandwidth());
-
- if (!stream->stream_.select_stream(true, false, stream->dmuxstrm->iPhysicalId >> 16))
- {
- CLog::Log(LOGERROR, "Unable to select stream!");
- return stream->disable();
- }
-
- if(rep != stream->stream_.getRepresentation())
- {
- m_MPDsession->UpdateStream(*stream);
- m_MPDsession->CheckChange(true);
- }
-
- stream->input_ = new CDASHByteStream(&stream->stream_);
- stream->input_file_ = new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance_, true);
- AP4_Movie* movie = stream->input_file_->GetMovie();
- if (movie == NULL)
- {
- CLog::Log(LOGERROR, "No MOOV in stream!");
- return stream->disable();
- }
-
- static const AP4_Track::Type TIDC[dash::DASHTree::STREAM_TYPE_COUNT] =
- { AP4_Track::TYPE_UNKNOWN, AP4_Track::TYPE_VIDEO, AP4_Track::TYPE_AUDIO, AP4_Track::TYPE_TEXT };
-
- AP4_Track *track = movie->GetTrack(TIDC[stream->stream_.get_type()]);
- if (!track)
- {
- CLog::Log(LOGERROR, "No suitable track found in stream");
- return stream->disable();
- }
-
- stream->reader_ = new CDASHFragmentedSampleReader(stream->input_, movie, track, streamid, m_MPDsession->GetSingleSampleDecryptor(), m_MPDsession->GetPresentationTimeOffset());
- stream->reader_->SetObserver(dynamic_cast(m_MPDsession.get()));
-
- if (!stream->dmuxstrm->ExtraSize)
- {
- // ExtraData is now available......
- stream->dmuxstrm->ExtraSize = stream->reader_->GetExtraDataSize();
-
- // Set the session Changed to force new GetStreamInfo call from kodi -> addon
- if (stream->dmuxstrm->ExtraSize)
- {
- stream->dmuxstrm->ExtraData = (uint8_t*)malloc(stream->dmuxstrm->ExtraSize);
- memcpy((void*)stream->dmuxstrm->ExtraData, stream->reader_->GetExtraData(), stream->dmuxstrm->ExtraSize);
- m_MPDsession->CheckChange(true);
- }
- }
- return;
- }
- CLog::Log(LOGDEBUG, ">>>> ERROR");
- return stream->disable();
-}
-
-int CDVDDemuxMPD::GetStreamLength()
-{
- if (!m_MPDsession)
- return 0;
-
- return static_cast(m_MPDsession->GetTotalTime()*1000);
-}
-
-std::string CDVDDemuxMPD::GetFileName()
-{
- if (!m_MPDsession)
- return "";
-
- return m_MPDsession->GetMpdUrl();
-}
-
-void CDVDDemuxMPD::GetStreamCodecName(int iStreamId, std::string& strName)
-{
- strName = "";
-
- CDASHSession::STREAM *stream(m_MPDsession->GetStream(iStreamId));
- if (stream)
- strName = stream->codecName;
-}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
index 40524f5213..cb4fb4f361 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
@@ -30,7 +30,7 @@
#include "DVDDemuxBXA.h"
#include "DVDDemuxCDDA.h"
#include "DVDDemuxPVRClient.h"
-#include "DVDDemuxMPD.h"
+#include "DVDDemuxAdaptive.h"
#include "pvr/PVRManager.h"
#include "pvr/addons/PVRClients.h"
@@ -47,10 +47,12 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool
if (!pInputStream)
return NULL;
- // Try to open the MPD demuxer
- if (pInputStream->GetFileItem().GetMimeType() == "video/vnd.mpeg.dash.mpd" || pInputStream->GetFileItem().IsType(".mpd"))
+ // Try to open the Adaptive demuxer
+ if (pInputStream->GetFileItem().GetMimeType() == "video/vnd.mpeg.dash.mpd" || pInputStream->GetFileItem().IsType(".mpd") //MPD
+ || pInputStream->GetFileItem().GetMimeType() == "application/vnd.ms-sstr+xml" || pInputStream->GetFileItem().IsType(".ismc")
+ )
{
- std::unique_ptr demuxer(new CDVDDemuxMPD());
+ std::unique_ptr demuxer(new CDVDDemuxAdaptive());
#ifdef TARGET_ANDROID
CPointInt maxres = CXBMCApp::GetMaxDisplayResolution();
#else
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
index 8cdf860d89..4d8a3014e3 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
@@ -11,17 +11,19 @@ SRCS += DVDDemuxVobsub.cpp
SRCS += DVDDemuxCC.cpp
SRCS += DVDFactoryDemuxer.cpp
-# MPD
+# Adaptive
SRCS += \
- DVDDemuxMPD.cpp \
- dash/DASHStream.cpp \
- dash/DASHTree.cpp \
- dash/DASHCodecHandler.cpp \
- dash/DASHByteStream.cpp \
- dash/DASHFragmentedSampleReader.cpp \
- dash/DASHSession.cpp \
- dash/helpers.cpp \
- dash/oscompat.cpp
+ DVDDemuxAdaptive.cpp \
+ adaptive/DASHStream.cpp \
+ adaptive/DASHCodecHandler.cpp \
+ adaptive/DASHByteStream.cpp \
+ adaptive/DASHFragmentedSampleReader.cpp \
+ adaptive/DASHSession.cpp \
+ adaptive/helpers.cpp \
+ adaptive/oscompat.cpp \
+ adaptive/common/AdaptiveTree.cpp \
+ adaptive/parsers/DASHTree.cpp \
+ adaptive/parsers/SmoothTree.cpp
LIB = DVDDemuxers.a
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.cpp
similarity index 100%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.cpp
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.h
similarity index 94%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.h
index 2845a9782a..0391b176ca 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHByteStream.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHByteStream.h
@@ -29,7 +29,7 @@ class CDASHByteStream : public AP4_ByteStream
{
public:
// Constructor
- CDASHByteStream(dash::DASHStream *dashStream) :dash_stream_(dashStream) {}
+ CDASHByteStream(dash::DASHStream *dashStream = nullptr) :dash_stream_(dashStream) {}
// AP4_ByteStream methods
AP4_Result ReadPartial(void* buffer, AP4_Size bytesToRead, AP4_Size& bytesRead) override;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.cpp
similarity index 100%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.cpp
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.h
similarity index 98%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.h
index 0ca1356bd3..88a8b62d10 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHCodecHandler.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHCodecHandler.h
@@ -34,6 +34,8 @@ class CDASHCodecHandler
, pictureId(0)
, pictureIdPrev(0)
{}
+ virtual ~CDASHCodecHandler() {}
+
virtual void UpdatePPSId(AP4_DataBuffer const&) {}
virtual bool GetVideoInformation(int &width, int &height) { return false; }
virtual bool GetAudioInformation(int &channels) { return false; }
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentObserver.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentObserver.h
similarity index 100%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentObserver.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentObserver.h
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.cpp
similarity index 65%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.cpp
index 9b36f825c0..512cfaa933 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.cpp
@@ -30,6 +30,7 @@ CDASHFragmentedSampleReader::CDASHFragmentedSampleReader(AP4_ByteStream* input,
, m_eos(false)
, m_started(false)
, m_StreamId(streamId)
+ , m_SampleDescIndex(1)
, m_SingleSampleDecryptor(ssd)
, m_Decrypter(0)
, m_Protected_desc(0)
@@ -37,6 +38,7 @@ CDASHFragmentedSampleReader::CDASHFragmentedSampleReader(AP4_ByteStream* input,
, m_Observer(0)
, m_DefaultKey(0)
, m_presentationTimeOffset(pto)
+ , m_bSampleDescChanged(false)
{
EnableTrack(m_Track->GetId());
@@ -46,25 +48,7 @@ CDASHFragmentedSampleReader::CDASHFragmentedSampleReader(AP4_ByteStream* input,
m_Protected_desc = static_cast(desc);
desc = m_Protected_desc->GetOriginalSampleDescription();
}
- switch (desc->GetFormat())
- {
- case AP4_SAMPLE_FORMAT_AVC1:
- case AP4_SAMPLE_FORMAT_AVC2:
- case AP4_SAMPLE_FORMAT_AVC3:
- case AP4_SAMPLE_FORMAT_AVC4:
- m_codecHandler = new CAVCDASHCodecHandler(desc);
- break;
- case AP4_SAMPLE_FORMAT_HEV1:
- case AP4_SAMPLE_FORMAT_HVC1:
- m_codecHandler = new CHEVCDASHCodecHandler(desc);
- break;
- case AP4_SAMPLE_FORMAT_MP4A:
- m_codecHandler = new CMPEGDASHCodecHandler(desc);
- break;
- default:
- m_codecHandler = new CDASHCodecHandler(desc);
- break;
- }
+ UpdateSampleDescription();
}
CDASHFragmentedSampleReader::~CDASHFragmentedSampleReader()
@@ -126,7 +110,7 @@ AP4_Result CDASHFragmentedSampleReader::SeekSample(AP4_UI32 track_id, AP4_UI64 t
return result;
sample_index = 0;
}
- return SetSampleIndex(track_id, sample_index);
+ return SetSampleIndex(tracker->m_Track->GetId(), sample_index);
}
AP4_Result CDASHFragmentedSampleReader::ReadSample()
@@ -203,6 +187,15 @@ bool CDASHFragmentedSampleReader::TimeSeek(double pts, bool preceeding)
return false;
}
+uint64_t CDASHFragmentedSampleReader::GetFragmentDuration()
+{
+ Tracker* trk = FindTracker(m_Track->GetId());
+ if (!trk->m_SampleTable)
+ return 0;
+
+ return dynamic_cast(trk->m_SampleTable)->GetDuration();
+}
+
AP4_Result CDASHFragmentedSampleReader::ProcessMoof(AP4_ContainerAtom* moof, AP4_Position moof_offset, AP4_Position mdat_payload_offset)
{
AP4_Result result;
@@ -210,38 +203,128 @@ AP4_Result CDASHFragmentedSampleReader::ProcessMoof(AP4_ContainerAtom* moof, AP4
if (m_Observer)
m_Observer->BeginFragment(m_StreamId);
- if (AP4_SUCCEEDED((result = AP4_LinearReader::ProcessMoof(moof, moof_offset, mdat_payload_offset))) && m_Protected_desc)
+ // create a new fragment
+ delete m_Fragment;
+ m_Fragment = new AP4_MovieFragment(moof);
+
+ // update the trackers
+ AP4_Array ids;
+ m_Fragment->GetTrackIds(ids);
+ for (unsigned int i=0; im_SampleTableIsOwned) {
+ delete tracker->m_SampleTable;
+ }
+ tracker->m_SampleTable = NULL;
+ tracker->m_NextSampleIndex = 0;
+ for (unsigned int j=0; jm_Track->GetId()) {
+ AP4_FragmentSampleTable* sample_table = NULL;
+ result = m_Fragment->CreateSampleTable(&m_Movie,
+ ids[j],
+ m_FragmentStream,
+ moof_offset,
+ mdat_payload_offset,
+ tracker->m_NextDts,
+ sample_table);
+ if (AP4_FAILED(result)) break;
+ tracker->m_SampleTable = sample_table;
+ tracker->m_SampleTableIsOwned = true;
+ tracker->m_Eos = false;
+ break;
+ }
+ }
+ }
+
+ if (AP4_SUCCEEDED(result))
{
- //Setup the decryption
- AP4_CencSampleInfoTable *sample_table;
- AP4_UI32 algorithm_id = 0;
-
- delete m_Decrypter;
- m_Decrypter = 0;
+ //Check if the sample table description has changed
AP4_ContainerAtom *traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, 0));
+ AP4_TfhdAtom *tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD, 0));
+ if (tfhd && tfhd->GetSampleDescriptionIndex() != m_SampleDescIndex)
+ {
+ m_SampleDescIndex = tfhd->GetSampleDescriptionIndex();
+ UpdateSampleDescription();
+ }
+ else if (m_SampleDescIndex != 1)
+ {
+ m_SampleDescIndex = 1;
+ UpdateSampleDescription();
+ }
- if (!m_Protected_desc || !traf)
- return AP4_ERROR_INVALID_FORMAT;
+ if (m_Protected_desc)
+ {
+ //Setup the decryption
+ AP4_CencSampleInfoTable *sample_table;
+ AP4_UI32 algorithm_id = 0;
- if (AP4_FAILED(result = AP4_CencSampleInfoTable::Create(m_Protected_desc, traf, algorithm_id, *m_FragmentStream, moof_offset, sample_table)))
- return result;
+ delete m_Decrypter;
+ m_Decrypter = 0;
- AP4_ContainerAtom *schi;
- m_DefaultKey = 0;
- if (m_Protected_desc->GetSchemeInfo() && (schi = m_Protected_desc->GetSchemeInfo()->GetSchiAtom()))
- {
- AP4_TencAtom* tenc(AP4_DYNAMIC_CAST(AP4_TencAtom, schi->GetChild(AP4_ATOM_TYPE_TENC, 0)));
- if (tenc)
- m_DefaultKey = tenc->GetDefaultKid();
- }
+ AP4_ContainerAtom *traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, 0));
+
+ if (!m_Protected_desc || !traf)
+ return AP4_ERROR_INVALID_FORMAT;
+
+ if (AP4_FAILED(result = AP4_CencSampleInfoTable::Create(m_Protected_desc, traf, algorithm_id, *m_FragmentStream, moof_offset, sample_table)))
+ return result;
+
+ AP4_ContainerAtom *schi;
+ m_DefaultKey = 0;
+ if (m_Protected_desc->GetSchemeInfo() && (schi = m_Protected_desc->GetSchemeInfo()->GetSchiAtom()))
+ {
+ AP4_TencAtom* tenc(AP4_DYNAMIC_CAST(AP4_TencAtom, schi->GetChild(AP4_ATOM_TYPE_TENC, 0)));
+ if (tenc)
+ m_DefaultKey = tenc->GetDefaultKid();
+ }
// if (AP4_FAILED(result = AP4_CencSampleDecrypter::Create(sample_table, algorithm_id, 0, 0, 0, m_SingleSampleDecryptor, m_Decrypter)))
// return result;
+ }
}
+
if (m_Observer)
m_Observer->EndFragment(m_StreamId);
return result;
}
+void CDASHFragmentedSampleReader::UpdateSampleDescription()
+{
+ if (m_codecHandler)
+ delete m_codecHandler;
+ m_codecHandler = 0;
+ m_bSampleDescChanged = true;
+
+ AP4_SampleDescription *desc(m_Track->GetSampleDescription(m_SampleDescIndex - 1));
+ if (!desc)
+ return;
+
+ if (desc->GetType() == AP4_SampleDescription::TYPE_PROTECTED)
+ {
+ m_Protected_desc = static_cast(desc);
+ desc = m_Protected_desc->GetOriginalSampleDescription();
+ }
+ switch (desc->GetFormat())
+ {
+ case AP4_SAMPLE_FORMAT_AVC1:
+ case AP4_SAMPLE_FORMAT_AVC2:
+ case AP4_SAMPLE_FORMAT_AVC3:
+ case AP4_SAMPLE_FORMAT_AVC4:
+ m_codecHandler = new CAVCDASHCodecHandler(desc);
+ break;
+ case AP4_SAMPLE_FORMAT_HEV1:
+ case AP4_SAMPLE_FORMAT_HVC1:
+ m_codecHandler = new CHEVCDASHCodecHandler(desc);
+ break;
+ case AP4_SAMPLE_FORMAT_MP4A:
+ m_codecHandler = new CMPEGDASHCodecHandler(desc);
+ break;
+ default:
+ m_codecHandler = new CDASHCodecHandler(desc);
+ break;
+ }
+}
+
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.h
similarity index 90%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.h
index e530b98cfd..db8fb4d0f8 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHFragmentedSampleReader.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHFragmentedSampleReader.h
@@ -51,24 +51,29 @@ class CDASHFragmentedSampleReader : public AP4_LinearReader
const AP4_Byte *GetSampleData() const { return m_sample_data_.GetData(); }
double GetDuration() const { return (double)m_sample_.GetDuration() / (double)m_Track->GetMediaTimeScale(); }
const AP4_UI08 *GetExtraData() { return m_codecHandler->extra_data; }
- AP4_Size GetExtraDataSize() { return m_codecHandler->extra_data_size; }
+ AP4_Size GetExtraDataSize() { return m_codecHandler ? m_codecHandler->extra_data_size : 0; }
bool GetVideoInformation(int &width, int &height) { return m_codecHandler->GetVideoInformation(width, height); }
bool GetAudioInformation(int &channelCount) { return m_codecHandler->GetAudioInformation(channelCount); }
void SetObserver(IDASHFragmentObserver *observer) { m_Observer = observer; }
void SetPTSOffset(uint64_t offset) { FindTracker(m_Track->GetId())->m_NextDts = offset; }
- uint64_t GetFragmentDuration() { return dynamic_cast(FindTracker(m_Track->GetId())->m_SampleTable)->GetDuration(); }
-
+ uint64_t GetFragmentDuration();
+ uint32_t GetTimeScale() { return m_Track->GetMediaTimeScale(); }
+
protected:
virtual AP4_Result ProcessMoof(AP4_ContainerAtom* moof,
AP4_Position moof_offset,
AP4_Position mdat_payload_offset);
+ virtual void UpdateSampleDescription();
private:
AP4_Track *m_Track;
AP4_UI32 m_StreamId;
+ AP4_UI32 m_SampleDescIndex;
+
bool m_eos, m_started;
double m_dts, m_pts;
double m_presentationTimeOffset;
+ bool m_bSampleDescChanged;
AP4_Sample m_sample_;
AP4_DataBuffer m_encrypted, m_sample_data_;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.cpp
similarity index 75%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.cpp
index f8a58248ff..b7792c53bf 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.cpp
@@ -23,18 +23,23 @@
#include "DVDDemuxers/DVDDemux.h"
+#include "parsers/DASHTree.h"
+#include "parsers/SmoothTree.h"
+
#include "system.h"
#include "utils/log.h"
#include "utils/URIUtils.h"
#include "utils/StringUtils.h"
#include "filesystem/File.h"
-CDASHSession::CDASHSession(const std::string& strURL, int width, int height, const char *strLicType, const char* strLicKey, const char* profile_path)
+CDASHSession::CDASHSession(const CDASHSession::MANIFEST_TYPE manifest_type, const std::string& strURL, int width, int height, const char *strLicType, const char* strLicKey, const char* profile_path)
:single_sample_decryptor_(0)
- , mpdFileURL_(strURL)
+ , manifest_type_(manifest_type)
+ , fileURL_(strURL)
, license_type_(strLicType)
, license_key_(strLicKey)
, profile_path_(profile_path)
+ , adaptiveTree_(nullptr)
, width_(width)
, height_(height)
, last_pts_(0)
@@ -43,6 +48,17 @@ CDASHSession::CDASHSession(const std::string& strURL, int width, int height, con
, changed_(false)
, manual_streams_(false)
{
+ switch (manifest_type)
+ {
+ case MANIFEST_TYPE_MPD:
+ adaptiveTree_ = new adaptive::DASHTree;
+ break;
+ case MANIFEST_TYPE_ISM:
+ adaptiveTree_ = new adaptive::SmoothTree;
+ break;
+ default:;
+ };
+
XFILE::CFile f;
std::string fn = URIUtils::AddFileToFolder(profile_path_, "bandwidth.bin");
@@ -50,13 +66,13 @@ CDASHSession::CDASHSession(const std::string& strURL, int width, int height, con
{
double val;
f.Read((void*)&val, sizeof(double));
- dashtree_.bandwidth_ = static_cast(val);
+ adaptiveTree_->bandwidth_ = static_cast(val);
f.Close();
}
else
- dashtree_.bandwidth_ = 4000000;
- dashtree_.set_download_speed(dashtree_.bandwidth_);
- CLog::Log(LOGDEBUG, "CDASHSession - Initial bandwidth: %u ", dashtree_.bandwidth_);
+ adaptiveTree_->bandwidth_ = 4000000;
+ adaptiveTree_->set_download_speed(adaptiveTree_->bandwidth_);
+ CLog::Log(LOGDEBUG, "CDASHSession - Initial bandwidth: %u ", adaptiveTree_->bandwidth_);
manual_streams_ = false;
}
@@ -79,7 +95,7 @@ CDASHSession::~CDASHSession()
std::string fn = URIUtils::AddFileToFolder(profile_path_, "bandwidth.bin");
if (f.OpenForWrite(fn, READ_NO_CACHE))
{
- double val(dashtree_.get_average_download_speed());
+ double val(adaptiveTree_->get_average_download_speed());
f.Write((const void*)&val, sizeof(double));
f.Close();
}
@@ -87,7 +103,7 @@ CDASHSession::~CDASHSession()
CLog::Log(LOGERROR, "CDASHSession - Cannot write bandwidth.bin");
}
-CDASHSession::STREAM::STREAM(dash::DASHTree& t, dash::DASHTree::StreamType s)
+CDASHSession::STREAM::STREAM(adaptive::AdaptiveTree& t, adaptive::AdaptiveTree::StreamType s)
: stream_(t, s)
, enabled(false)
, current_segment_(0)
@@ -184,27 +200,30 @@ bool CDASHSession::initialize()
// Get URN's wich are supported by this addon
// if (!license_type_.empty())
// {
-// GetSupportedDecrypterURN(dashtree_.adp_pssh_);
-// CLog::Log(LOGDEBUG, "Supported URN: %s", dashtree_.adp_pssh_.first.c_str());
+// GetSupportedDecrypterURN(dashtree_->adp_pssh_);
+// CLog::Log(LOGDEBUG, "Supported URN: %s", dashtree_->adp_pssh_.first.c_str());
// }
// Open mpd file
- const char* delim(strrchr(mpdFileURL_.c_str(), '/'));
- if (!delim)
+ size_t paramPos = fileURL_.find('?');
+ adaptiveTree_->base_url_ = (paramPos == std::string::npos) ? fileURL_ : fileURL_.substr(0, paramPos);
+
+ paramPos = adaptiveTree_->base_url_.find_last_of('/', adaptiveTree_->base_url_.length());
+ if (paramPos == std::string::npos)
{
- CLog::Log(LOGERROR, "Invalid mpdURL: / expected (%s)", mpdFileURL_.c_str());
+ CLog::Log(LOGERROR, "Invalid adaptive URL: / expected (%s)", fileURL_.c_str());
return false;
}
- dashtree_.base_url_ = std::string(mpdFileURL_.c_str(), (delim - mpdFileURL_.c_str()) + 1);
+ adaptiveTree_->base_url_.resize(paramPos + 1);
- if (!dashtree_.open(mpdFileURL_.c_str()) || dashtree_.empty())
+ if (!adaptiveTree_->open(fileURL_.c_str()) || adaptiveTree_->empty())
{
- CLog::Log(LOGERROR, "Could not open / parse mpdURL (%s)", mpdFileURL_.c_str());
+ CLog::Log(LOGERROR, "Could not open / parse adaptive URL (%s)", fileURL_.c_str());
return false;
}
- CLog::Log(LOGINFO, "Successfully parsed .mpd file. #Streams: %d Download speed: %0.4f Bytes/s", dashtree_.periods_[0]->adaptationSets_.size(), dashtree_.download_speed_);
+ CLog::Log(LOGINFO, "Successfully parsed adaptive manifest. #Streams: %d Download speed: %0.4f Bytes/s", adaptiveTree_->periods_[0]->adaptationSets_.size(), adaptiveTree_->download_speed_);
- if (dashtree_.encryptionState_ == dash::DASHTree::ENCRYTIONSTATE_ENCRYPTED)
+ if (adaptiveTree_->encryptionState_ == adaptive::AdaptiveTree::ENCRYTIONSTATE_ENCRYPTED)
{
CLog::Log(LOGERROR, "Unable to handle decryption. Unsupported!");
return false;
@@ -220,30 +239,30 @@ bool CDASHSession::initialize()
*/
// create CDASHSession::STREAM objects. One for each AdaptationSet
- const dash::DASHTree::AdaptationSet *adp;
+ const adaptive::AdaptiveTree::AdaptationSet *adp;
for (std::vector::iterator b(streams_.begin()), e(streams_.end()); b != e; ++b)
SAFE_DELETE(*b);
streams_.clear();
- for (unsigned int i=0; adp = dashtree_.GetAdaptationSet(i); ++i)
+ for (unsigned int i=0; (adp = adaptiveTree_->GetAdaptationSet(i)); ++i)
{
size_t repId = manual_streams_ ? adp->repesentations_.size() : 0;
do {
- streams_.push_back(new STREAM(dashtree_, adp->type_));
+ streams_.push_back(new STREAM(*adaptiveTree_, adp->type_));
STREAM &stream(*streams_.back());
stream.stream_.prepare_stream(adp, width_, height_, min_bandwidth, max_bandwidth, repId);
switch (adp->type_)
{
- case dash::DASHTree::VIDEO:
+ case adaptive::AdaptiveTree::VIDEO:
stream.dmuxstrm = new CDemuxStreamVideo();
break;
- case dash::DASHTree::AUDIO:
+ case adaptive::AdaptiveTree::AUDIO:
stream.dmuxstrm = new CDemuxStreamAudio();
break;
- case dash::DASHTree::TEXT:
+ case adaptive::AdaptiveTree::TEXT:
stream.dmuxstrm = new CDemuxStreamTeletext();
break;
default:
@@ -261,19 +280,19 @@ bool CDASHSession::initialize()
}
// // Try to initialize an SingleSampleDecryptor
-// if (dashtree_.encryptionState_)
+// if (dashtree_->encryptionState_)
// {
// AP4_DataBuffer init_data;
-// if (dashtree_.adp_pssh_.second == "FILE")
+// if (dashtree_->adp_pssh_.second == "FILE")
// {
-// std::string strkey(dashtree_.adp_pssh_.first.substr(9));
+// std::string strkey(dashtree_->adp_pssh_.first.substr(9));
// size_t pos;
// while ((pos = strkey.find('-')) != std::string::npos)
// strkey.erase(pos, 1);
// if (strkey.size() != 32)
// {
-// CLog::Log(LOGERROR, "Key system mismatch (%s)!", dashtree_.adp_pssh_.first.c_str());
+// CLog::Log(LOGERROR, "Key system mismatch (%s)!", dashtree_->adp_pssh_.first.c_str());
// return false;
// }
@@ -313,10 +332,17 @@ bool CDASHSession::initialize()
// }
// else
// {
-// init_data.SetBufferSize(1024);
-// unsigned int init_data_size(1024);
-// b64_decode(dashtree_.pssh_.second.data(), dashtree_.pssh_.second.size(), init_data.UseData(), init_data_size);
-// init_data.SetDataSize(init_data_size);
+// if (manifest_type_ == MANIFEST_TYPE_ISM)
+// {
+// create_ism_license(adaptiveTree_->defaultKID_, license_data_, init_data);
+// }
+// else
+// {
+// init_data.SetBufferSize(1024);
+// unsigned int init_data_size(1024);
+// b64_decode(dashtree_->pssh_.second.data(), dashtree_->pssh_.second.size(), init_data.UseData(), init_data_size);
+// init_data.SetDataSize(init_data_size);
+// }
// }
// return (single_sample_decryptor_ = CreateSingleSampleDecrypter(init_data))!=0;
// }
@@ -325,7 +351,7 @@ bool CDASHSession::initialize()
void CDASHSession::UpdateStream(STREAM &stream)
{
- const dash::DASHTree::Representation *rep(stream.stream_.getRepresentation());
+ const adaptive::AdaptiveTree::Representation *rep(stream.stream_.getRepresentation());
// we currently use only the first track!
std::string::size_type pos = rep->codecs_.find(",");
@@ -334,11 +360,11 @@ void CDASHSession::UpdateStream(STREAM &stream)
stream.codecInternalName = rep->codecs_.substr(0, pos);
- if (rep->codecs_.find("mp4a") == 0)
+ if (rep->codecs_.find("mp4a") == 0 || rep->codecs_.find("aacl") == 0)
stream.codecName = "aac";
else if (rep->codecs_.find("ec-3") == 0 || rep->codecs_.find("ac-3") == 0)
stream.codecName = "eac3";
- else if (rep->codecs_.find("avc") == 0)
+ else if (rep->codecs_.find("avc") == 0 || rep->codecs_.find("h264") == 0)
stream.codecName = "h264";
else if (rep->codecs_.find("hevc") == 0)
stream.codecName = "hevc";
@@ -348,6 +374,10 @@ void CDASHSession::UpdateStream(STREAM &stream)
stream.codecName = "opus";
else if (rep->codecs_.find("vorbis") == 0)
stream.codecName = "vorbis";
+ else if (rep->codecs_.find("wvc1") == 0)
+ stream.codecName = "vc1";
+ else if (rep->codecs_.find("wmap") == 0)
+ stream.codecName = "wmapro";
AVCodec *codec = avcodec_find_decoder_by_name(stream.codecName.c_str());
if (codec)
@@ -365,7 +395,7 @@ void CDASHSession::UpdateStream(STREAM &stream)
vstrm->fAspect = rep->aspect_;
vstrm->iFpsRate = rep->fpsRate_;
vstrm->iFpsScale = rep->fpsScale_;
- vstrm->sStreamInfo = StringUtils::Format("MPD Video: %s / %d x %d / %d kbps", stream.codecName.c_str(), rep->width_, rep->height_, rep->bandwidth_ / 1024);
+ vstrm->sStreamInfo = StringUtils::Format("ADP Video: %s / %d x %d / %d kbps", stream.codecName.c_str(), rep->width_, rep->height_, rep->bandwidth_ / 1024);
if (!vstrm->ExtraSize && rep->codec_private_data_.size())
{
@@ -379,7 +409,7 @@ void CDASHSession::UpdateStream(STREAM &stream)
CDemuxStreamAudio* astrm = static_cast(stream.dmuxstrm);
astrm->iSampleRate = rep->samplingRate_;
astrm->iChannels = rep->channelCount_;
- astrm->sStreamInfo = StringUtils::Format("MPD Audio: %s / %d ch / %d Hz / %d kbps", stream.codecName.c_str(), rep->channelCount_, rep->samplingRate_, rep->bandwidth_ / 1024);
+ astrm->sStreamInfo = StringUtils::Format("ADP Audio: %s / %d ch / %d Hz / %d kbps", stream.codecName.c_str(), rep->channelCount_, rep->samplingRate_, rep->bandwidth_ / 1024);
}
}
@@ -448,6 +478,14 @@ bool CDASHSession::SeekTime(double seekTime, unsigned int streamId, bool preceed
return ret;
}
+const AP4_UI08*CDASHSession::GetDefaultKeyId() const
+{
+ static const AP4_UI08 default_key[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ if (adaptiveTree_->defaultKID_.size() == 16)
+ return reinterpret_cast(adaptiveTree_->defaultKID_.data());
+ return default_key;
+}
+
void CDASHSession::BeginFragment(AP4_UI32 streamId)
{
STREAM *s(streams_[streamId]);
@@ -457,7 +495,13 @@ void CDASHSession::BeginFragment(AP4_UI32 streamId)
void CDASHSession::EndFragment(AP4_UI32 streamId)
{
STREAM *s(streams_[streamId]);
- dashtree_.SetFragmentDuration(s->stream_.getAdaptationSet(), s->stream_.getRepresentation(), s->stream_.getSegmentPos(), s->reader_->GetFragmentDuration());
+ adaptiveTree_->SetFragmentDuration(
+ s->stream_.getAdaptationSet(),
+ s->stream_.getRepresentation(),
+ s->stream_.getSegmentPos(),
+ s->reader_->GetFragmentDuration(),
+ s->reader_->GetTimeScale()
+ );
}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.h
similarity index 74%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.h
index abcaf3c51d..8a22fca6de 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHSession.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHSession.h
@@ -27,22 +27,17 @@
#include "DASHFragmentObserver.h"
#include "DASHFragmentedSampleReader.h"
#include "DASHStream.h"
-#include "DASHTree.h"
+#include "common/AdaptiveTree.h"
#include "DVDDemuxers/DVDDemux.h"
class CDASHSession: public IDASHFragmentObserver
{
public:
- CDASHSession(const std::string& strURL, int width, int height, const char *strLicType, const char* strLicKey, const char* profile_path);
- virtual ~CDASHSession();
- bool initialize();
- CDASHFragmentedSampleReader *GetNextSample();
-
class STREAM
{
public:
- STREAM(dash::DASHTree &t, dash::DASHTree::StreamType s);
+ STREAM(adaptive::AdaptiveTree &t, adaptive::AdaptiveTree::StreamType s);
~STREAM();
void disable();
@@ -58,21 +53,35 @@ class CDASHSession: public IDASHFragmentObserver
CDASHFragmentedSampleReader *reader_;
};
+ enum MANIFEST_TYPE
+ {
+ MANIFEST_TYPE_UNKNOWN,
+ MANIFEST_TYPE_MPD,
+ MANIFEST_TYPE_ISM
+ };
+
+ CDASHSession(const CDASHSession::MANIFEST_TYPE manifest_type, const std::string& strURL, int width, int height, const char *strLicType, const char* strLicKey, const char* profile_path);
+ virtual ~CDASHSession();
+ bool initialize();
+ CDASHFragmentedSampleReader *GetNextSample();
+
void UpdateStream(STREAM &stream);
- std::string GetMpdUrl() { return mpdFileURL_; }
+ std::string GetUrl() { return fileURL_; }
STREAM *GetStream(unsigned int sid) const { return (sid < streams_.size() ? streams_[sid] : 0); }
unsigned int GetStreamCount() const { return streams_.size(); }
std::uint16_t GetWidth() const { return width_; }
std::uint16_t GetHeight() const { return height_; }
AP4_CencSingleSampleDecrypter * GetSingleSampleDecryptor() const { return single_sample_decryptor_; }
- double GetPresentationTimeOffset() { return dashtree_.minPresentationOffset < DBL_MAX? dashtree_.minPresentationOffset:0; }
- double GetTotalTime() const { return dashtree_.overallSeconds_; }
+ double GetPresentationTimeOffset() { return adaptiveTree_->minPresentationOffset < DBL_MAX? adaptiveTree_->minPresentationOffset:0; }
+ double GetTotalTime() const { return adaptiveTree_->overallSeconds_; }
double GetPTS() const { return last_pts_; }
bool CheckChange(bool bSet = false);
void SetVideoResolution(unsigned int w, unsigned int h);
bool SeekTime(double seekTime, unsigned int streamId = 0, bool preceeding=true);
- bool IsLive() const { return dashtree_.live_start_ != 0; }
+ bool IsLive() const { return adaptiveTree_->has_timeshift_buffer_; }
+ MANIFEST_TYPE GetManifestType() const { return manifest_type_; }
+ const AP4_UI08 *GetDefaultKeyId() const;
//Observer Section
void BeginFragment(AP4_UI32 streamId) override;
@@ -83,12 +92,13 @@ class CDASHSession: public IDASHFragmentObserver
// AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &streamCodec);
private:
- std::string mpdFileURL_;
+ MANIFEST_TYPE manifest_type_;
+ std::string fileURL_;
std::string license_key_, license_type_;
std::string profile_path_;
void * decrypterModule_;
- dash::DASHTree dashtree_;
+ adaptive::AdaptiveTree* adaptiveTree_;
std::vector streams_;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.cpp
similarity index 70%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.cpp
index e4379a7cd4..dd88544f25 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.cpp
@@ -26,7 +26,7 @@
using namespace dash;
using namespace XFILE;
-DASHStream::DASHStream(DASHTree &tree, DASHTree::StreamType type)
+DASHStream::DASHStream(adaptive::AdaptiveTree &tree, adaptive::AdaptiveTree::StreamType type)
:tree_(tree)
, type_(type)
, observer_(0)
@@ -48,19 +48,26 @@ bool DASHStream::download_segment()
std::string strURL;
char rangebuf[128], *rangeHeader(0);
- if ((current_rep_->flags_ & DASHTree::Representation::SEGMENTBASE))
+ if (current_rep_->flags_ & adaptive::AdaptiveTree::Representation::STARTTIMETPL)
{
strURL = current_rep_->url_;
- sprintf(rangebuf, "bytes=%" PRIu64 "-%" PRIu64, current_seg_->range_begin_, current_seg_->range_end_);
- rangeHeader = rangebuf;
+ sprintf(rangebuf, "%" PRIu64, tree_.base_time_ + current_seg_->range_end_);
+ strURL.replace(strURL.find("{start time}"), 12, rangebuf);
}
- else if ((current_rep_->flags_ & DASHTree::Representation::SEGMENTMEDIA))
+ else if ((current_rep_->flags_ & adaptive::AdaptiveTree::Representation::SEGMENTMEDIA))
{
strURL = current_rep_->url_ + current_seg_->media_;
}
- else if ((current_rep_->flags_ & DASHTree::Representation::TEMPLATE))
+ else if (!(current_rep_->flags_ & adaptive::AdaptiveTree::Representation::SEGMENTBASE))
{
- if (~current_seg_->range_end_) //templated segment
+ if (!(current_rep_->flags_ & adaptive::AdaptiveTree::Representation::TEMPLATE))
+ {
+ strURL = current_rep_->url_;
+ sprintf(rangebuf, "bytes=%" PRIu64 "-%" PRIu64, current_seg_->range_begin_, current_seg_->range_end_);
+ rangeHeader = rangebuf;
+ absolute_position_ = current_seg_->range_begin_;
+ }
+ else if (~current_seg_->range_end_) //templated segment
{
std::string media = current_rep_->segtpl_.media;
std::string::size_type lenReplace(7);
@@ -89,11 +96,11 @@ bool DASHStream::download_segment()
}
else
{
- sprintf(rangebuf, "/range/%" PRIu64 "-%" PRIu64, current_seg_->range_begin_, current_seg_->range_end_);
- strURL = current_rep_->url_ + rangebuf;
- absolute_position_ = current_seg_->range_begin_;
- }
-
+ strURL = current_rep_->url_;
+ sprintf(rangebuf, "bytes=%" PRIu64 "-%" PRIu64, current_seg_->range_begin_, current_seg_->range_end_);
+ rangeHeader = rangebuf;
+ }
+
return download(strURL.c_str(), rangeHeader);
}
@@ -103,12 +110,12 @@ bool DASHStream::write_data(const void *buffer, size_t buffer_size)
return true;
}
-bool DASHStream::prepare_stream(const DASHTree::AdaptationSet *adp,
+bool DASHStream::prepare_stream(const adaptive::AdaptiveTree::AdaptationSet *adp,
const uint32_t width, const uint32_t height,
uint32_t min_bandwidth, uint32_t max_bandwidth, unsigned int repId)
{
- width_ = type_ == DASHTree::VIDEO ? width : 0;
- height_ = type_ == DASHTree::VIDEO ? height : 0;
+ width_ = type_ == adaptive::AdaptiveTree::VIDEO ? width : 0;
+ height_ = type_ == adaptive::AdaptiveTree::VIDEO ? height : 0;
uint32_t avg_bandwidth = tree_.bandwidth_;
@@ -120,7 +127,7 @@ bool DASHStream::prepare_stream(const DASHTree::AdaptationSet *adp,
stopped_ = false;
- bandwidth_ = static_cast(bandwidth_ *(type_ == DASHTree::VIDEO ? 0.9 : 0.1));
+ bandwidth_ = static_cast(bandwidth_ *(type_ == adaptive::AdaptiveTree::VIDEO ? 0.9 : 0.1));
current_adp_ = adp;
@@ -129,7 +136,7 @@ bool DASHStream::prepare_stream(const DASHTree::AdaptationSet *adp,
bool DASHStream::start_stream(const uint32_t seg_offset, uint16_t width, uint16_t height)
{
- if (!~seg_offset && tree_.live_start_ && current_rep_->segments_.data.size()>1)
+ if (!~seg_offset && tree_.available_time_ && current_rep_->segments_.data.size()>1)
{
//go at least 12 secs back
std::int32_t pos(static_cast(current_rep_->segments_.data.size() - 1));
@@ -147,8 +154,8 @@ bool DASHStream::start_stream(const uint32_t seg_offset, uint16_t width, uint16_
}
else
{
- width_ = type_ == DASHTree::VIDEO ? width : 0;
- height_ = type_ == DASHTree::VIDEO ? height : 0;
+ width_ = type_ == adaptive::AdaptiveTree::VIDEO ? width : 0;
+ height_ = type_ == adaptive::AdaptiveTree::VIDEO ? height : 0;
absolute_position_ = current_rep_->get_next_segment(current_seg_)->range_begin_;
stopped_ = false;
@@ -219,7 +226,7 @@ bool DASHStream::seek_time(double seek_seconds, double current_seconds, bool &ne
if (choosen_seg && current_rep_->get_segment(choosen_seg)->startPTS_ > sec_in_ts)
--choosen_seg;
- const DASHTree::Segment* old_seg(current_seg_);
+ const adaptive::AdaptiveTree::Segment* old_seg(current_seg_);
if ((current_seg_ = current_rep_->get_segment(choosen_seg)))
{
needReset = true;
@@ -308,41 +315,84 @@ bool DASHStream::parseIndexRange()
}
byteStream->Seek(0);
- AP4_Atom *atom(NULL);
- if(AP4_FAILED(AP4_DefaultAtomFactory::Instance_.CreateAtomFromStream(*byteStream, atom)) || AP4_DYNAMIC_CAST(AP4_SidxAtom, atom)==0)
+ adaptive::AdaptiveTree::AdaptationSet *adp(const_cast(getAdaptationSet()));
+ adaptive::AdaptiveTree::Representation *rep(const_cast(getRepresentation()));
+
+ if (!getRepresentation()->indexRangeMin_)
{
- CLog::Log(LOGERROR, "Unable to create SIDX from IndexRange bytes");
- byteStream->Release();
- return false;
+ AP4_File f(*byteStream, AP4_DefaultAtomFactory::Instance_, true);
+ AP4_Movie* movie = f.GetMovie();
+ if (movie == NULL)
+ {
+ CLog::Log(LOGERROR, "No MOOV in stream!");
+ byteStream->Release();
+ return false;
+ }
+ rep->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
+ rep->initialization_.range_begin_ = 0;
+ AP4_Position pos;
+ byteStream->Tell(pos);
+ rep->initialization_.range_end_ = pos - 1;
}
- byteStream->Release();
- AP4_SidxAtom *sidx(AP4_DYNAMIC_CAST(AP4_SidxAtom, atom));
-
- dash::DASHTree::AdaptationSet *adp(const_cast(getAdaptationSet()));
- dash::DASHTree::Representation *rep(const_cast(getRepresentation()));
- rep->timescale_ = sidx->GetTimeScale();
-
- const AP4_Array &reps(sidx->GetReferences());
- dash::DASHTree::Segment seg;
- seg.range_end_ = rep->indexRangeMax_;
+ adaptive::AdaptiveTree::Segment seg;
seg.startPTS_ = 0;
+ unsigned int numSIDX(1);
- for (unsigned int i(0); i < reps.ItemCount(); ++i)
+ do
{
- seg.range_begin_ = seg.range_end_ + 1;
- seg.range_end_ = seg.range_begin_ + reps[i].m_ReferencedSize - 1;
- rep->segments_.data.push_back(seg);
- if (adp->segment_durations_.data.size() < rep->segments_.data.size() - 1)
- adp->segment_durations_.data.push_back(reps[i].m_SubsegmentDuration);
- seg.startPTS_ += reps[i].m_SubsegmentDuration;
- }
+ AP4_Atom *atom(NULL);
+ if (AP4_FAILED(AP4_DefaultAtomFactory::Instance_.CreateAtomFromStream(*byteStream, atom)))
+ {
+ CLog::Log(LOGERROR, "Unable to create SIDX from IndexRange bytes");
+ byteStream->Release();
+ return false;
+ }
+
+ if (atom->GetType() == AP4_ATOM_TYPE_MOOF)
+ {
+ delete atom;
+ break;
+ }
+ else if (atom->GetType() != AP4_ATOM_TYPE_SIDX)
+ {
+ delete atom;
+ continue;
+ }
+
+ AP4_SidxAtom *sidx(AP4_DYNAMIC_CAST(AP4_SidxAtom, atom));
+ const AP4_Array &refs(sidx->GetReferences());
+ if (refs[0].m_ReferenceType == 1)
+ {
+ numSIDX = refs.ItemCount();
+ delete atom;
+ continue;
+ }
+ AP4_Position pos;
+ byteStream->Tell(pos);
+ seg.range_end_ = pos + getRepresentation()->indexRangeMin_ + sidx->GetFirstOffset() - 1;
+ rep->timescale_ = sidx->GetTimeScale();
+
+ for (unsigned int i(0); i < refs.ItemCount(); ++i)
+ {
+ seg.range_begin_ = seg.range_end_ + 1;
+ seg.range_end_ = seg.range_begin_ + refs[i].m_ReferencedSize - 1;
+ rep->segments_.data.push_back(seg);
+ if (adp->segment_durations_.data.size() < rep->segments_.data.size() - 1)
+ adp->segment_durations_.data.push_back(refs[i].m_SubsegmentDuration);
+ seg.startPTS_ += refs[i].m_SubsegmentDuration;
+ }
+ delete atom;
+ --numSIDX;
+ } while (numSIDX);
+
+ byteStream->Release();
return true;
}
bool DASHStream::select_stream(bool force, bool justInit, unsigned int repId)
{
- const DASHTree::Representation *new_rep(0), *min_rep(0);
+ const adaptive::AdaptiveTree::Representation *new_rep(0), *min_rep(0);
if (force && absolute_position_ == 0) //already selected
return true;
@@ -351,7 +401,7 @@ bool DASHStream::select_stream(bool force, bool justInit, unsigned int repId)
{
unsigned int bestScore(~0);
- for (std::vector::const_iterator br(current_adp_->repesentations_.begin()), er(current_adp_->repesentations_.end()); br != er; ++br)
+ for (std::vector::const_iterator br(current_adp_->repesentations_.begin()), er(current_adp_->repesentations_.end()); br != er; ++br)
{
unsigned int score;
if ((*br)->bandwidth_ <= bandwidth_
@@ -390,7 +440,7 @@ bool DASHStream::select_stream(bool force, bool justInit, unsigned int repId)
/* If we have indexRangeExact SegmentBase, update SegmentList from SIDX */
if (current_rep_->indexRangeMax_)
{
- DASHTree::Representation *rep(const_cast(current_rep_));
+ adaptive::AdaptiveTree::Representation *rep(const_cast(current_rep_));
if (!parseIndexRange())
return false;
rep->indexRangeMin_ = rep->indexRangeMax_ = 0;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.h
similarity index 77%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.h
index 14408bf4f5..0a539b7724 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHStream.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/DASHStream.h
@@ -11,7 +11,7 @@
#pragma once
-#include "DASHTree.h"
+#include "common/AdaptiveTree.h"
#include
namespace dash
@@ -27,10 +27,10 @@ namespace dash
class DASHStream
{
public:
- DASHStream(DASHTree &tree, DASHTree::StreamType type);
+ DASHStream(adaptive::AdaptiveTree &tree, adaptive::AdaptiveTree::StreamType type);
~DASHStream();
void set_observer(DASHStreamObserver *observer){ observer_ = observer; };
- bool prepare_stream(const DASHTree::AdaptationSet *adp,
+ bool prepare_stream(const adaptive::AdaptiveTree::AdaptationSet *adp,
const uint32_t width, const uint32_t height,
uint32_t min_bandwidth, uint32_t max_bandwidth, unsigned int repId);
bool start_stream(const uint32_t seg_offset, uint16_t width, uint16_t height);
@@ -49,8 +49,8 @@ namespace dash
uint64_t tell(){ read(0, 0); return absolute_position_; };
bool seek(uint64_t const pos);
bool seek_time(double seek_seconds, double current_seconds, bool &needReset);
- DASHTree::AdaptationSet const *getAdaptationSet() { return current_adp_; };
- DASHTree::Representation const *getRepresentation(){ return current_rep_; };
+ adaptive::AdaptiveTree::AdaptationSet const *getAdaptationSet() { return current_adp_; };
+ adaptive::AdaptiveTree::Representation const *getRepresentation(){ return current_rep_; };
double get_download_speed() const { return tree_.get_download_speed(); };
void set_download_speed(double speed) { tree_.set_download_speed(speed); };
size_t getSegmentPos() { return current_rep_->segments_.pos(current_seg_); };
@@ -62,14 +62,14 @@ namespace dash
private:
bool download_segment();
- DASHTree &tree_;
- DASHTree::StreamType type_;
+ adaptive::AdaptiveTree &tree_;
+ adaptive::AdaptiveTree::StreamType type_;
DASHStreamObserver *observer_;
// Active configuration
- const DASHTree::Period *current_period_;
- const DASHTree::AdaptationSet *current_adp_;
- const DASHTree::Representation *current_rep_;
- const DASHTree::Segment *current_seg_;
+ const adaptive::AdaptiveTree::Period *current_period_;
+ const adaptive::AdaptiveTree::AdaptationSet *current_adp_;
+ const adaptive::AdaptiveTree::Representation *current_rep_;
+ const adaptive::AdaptiveTree::Segment *current_seg_;
//We assume that a single segment can build complete frames
std::string segment_buffer_;
std::size_t segment_read_pos_;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.cpp
new file mode 100644
index 0000000000..e8d91487cb
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.cpp
@@ -0,0 +1,145 @@
+/*
+* Copyright (C) 2016-2016 peak3d
+* http://www.peak3d.de
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* .
+*
+*/
+
+#include "AdaptiveTree.h"
+#include
+
+#include "URL.h"
+#include "utils/URIUtils.h"
+#include "filesystem/File.h"
+
+namespace adaptive
+{
+ void AdaptiveTree::Segment::SetRange(const char *range)
+ {
+ const char *delim(strchr(range, '-'));
+ if (delim)
+ {
+ range_begin_ = strtoull(range, 0, 10);
+ range_end_ = strtoull(delim + 1, 0, 10);
+ }
+ else
+ range_begin_ = range_end_ = 0;
+ }
+
+ AdaptiveTree::AdaptiveTree()
+ : current_period_(0)
+ , parser_(0)
+ , currentNode_(0)
+ , segcount_(0)
+ , overallSeconds_(0.0)
+ , stream_start_(0)
+ , available_time_(0)
+ , publish_time_(0)
+ , base_time_(0)
+ , minPresentationOffset(0.0)
+ , has_timeshift_buffer_(false)
+ , download_speed_(0.0)
+ , average_download_speed_(0.0f)
+ , encryptionState_(ENCRYTIONSTATE_UNENCRYPTED)
+ {
+ }
+
+ bool AdaptiveTree::has_type(StreamType t)
+ {
+ if (periods_.empty())
+ return false;
+
+ for (std::vector::const_iterator b(periods_[0]->adaptationSets_.begin()), e(periods_[0]->adaptationSets_.end()); b != e; ++b)
+ if ((*b)->type_ == t)
+ return true;
+ return false;
+ }
+
+ uint32_t AdaptiveTree::estimate_segcount(uint32_t duration, uint32_t timescale)
+ {
+ double tmp(duration);
+ duration /= timescale;
+ return static_cast((overallSeconds_ / duration)*1.01);
+ }
+
+ void AdaptiveTree::set_download_speed(double speed)
+ {
+ download_speed_ = speed;
+ if (!average_download_speed_)
+ average_download_speed_ = download_speed_;
+ else
+ average_download_speed_ = average_download_speed_*0.9 + download_speed_*0.1;
+ };
+
+ void AdaptiveTree::SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint32_t fragmentDuration, uint32_t movie_timescale)
+ {
+ if (!has_timeshift_buffer_)
+ return;
+
+ //Get a modifiable adaptationset
+ AdaptationSet *adpm(static_cast((void*)adp));
+
+ // Check if its the last frame we watch
+ if (adp->segment_durations_.data.size())
+ {
+ if (pos == adp->segment_durations_.data.size() - 1)
+ {
+ adpm->segment_durations_.insert(static_cast(fragmentDuration)*adp->timescale_ / movie_timescale);
+ }
+ else
+ return;
+ }
+ else if (pos != rep->segments_.data.size() - 1)
+ return;
+
+ fragmentDuration = static_cast(static_cast(fragmentDuration)*rep->timescale_ / movie_timescale);
+
+ Segment seg(*(rep->segments_[pos]));
+ if(~seg.range_begin_)
+ seg.range_begin_ += fragmentDuration;
+ seg.range_end_ += (rep->flags_ & (Representation::STARTTIMETPL | Representation::TIMETEMPLATE)) ? fragmentDuration : 1;
+ seg.startPTS_ += fragmentDuration;
+
+ for (std::vector::iterator b(adpm->repesentations_.begin()), e(adpm->repesentations_.end()); b != e; ++b)
+ (*b)->segments_.insert(seg);
+ }
+
+ bool AdaptiveTree::download(const char* url)
+ {
+ // open the file
+ CURL uUrl(url);
+ if (URIUtils::IsInternetStream(uUrl))
+ {
+ uUrl.SetProtocolOption("seekable", "0");
+ uUrl.SetProtocolOption("acceptencoding", "gzip");
+ }
+
+ XFILE::CFile* file = new XFILE::CFile();
+ if (!file->Open(uUrl, READ_CHUNKED | READ_NO_CACHE))
+ return false;
+
+ // read the file
+ static const unsigned int CHUNKSIZE = 16384;
+ char buf[CHUNKSIZE];
+ size_t nbRead;
+ while ((nbRead = file->Read(buf, CHUNKSIZE)) > 0 && ~nbRead && write_data(buf, nbRead));
+
+ //download_speed_ = xbmc->GetFileDownloadSpeed(file);
+
+ file->Close();
+ delete file;
+
+ return nbRead == 0;
+ }
+}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.h
old mode 100644
new mode 100755
similarity index 75%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.h
index f08fc76e3e..d5f6be3378
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/common/AdaptiveTree.h
@@ -1,13 +1,20 @@
/*
-* DASHTree.h
-*****************************************************************************
-* Copyright (C) 2015, liberty_developer
+* Copyright (C) 2016-2016 peak3d
+* http://www.peak3d.de
*
-* Email: liberty.developer@xmail.net
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
*
-* This source code and its use and distribution, is subject to the terms
-* and conditions of the applicable license agreement.
-*****************************************************************************/
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* .
+*
+*/
#pragma once
@@ -17,7 +24,7 @@
#include
#include "expat.h"
-namespace dash
+namespace adaptive
{
template
struct SPINCACHE
@@ -61,7 +68,7 @@ namespace dash
std::vector data;
};
- class DASHTree
+ class AdaptiveTree
{
public:
enum StreamType
@@ -95,8 +102,8 @@ namespace dash
struct Representation
{
- Representation() :timescale_(0), duration_(0), bandwidth_(0), samplingRate_(0), width_(0), height_(0),
- aspect_(1.0f), fpsRate_(0), fpsScale_(1), channelCount_(0), flags_(0), indexRangeMin_(0), indexRangeMax_(0){};
+ Representation() :bandwidth_(0), samplingRate_(0), width_(0), height_(0), fpsRate_(0), fpsScale_(1), aspect_(1.0f),
+ flags_(0), indexRangeMin_(0), indexRangeMax_(0), channelCount_(0), duration_(0), timescale_(0){};
std::string url_;
std::string id;
std::string codecs_;
@@ -114,11 +121,13 @@ namespace dash
static const unsigned int INITIALIZATION = 8;
static const unsigned int TIMETEMPLATE = 16;
static const unsigned int SEGMENTBASE = 32;
- static const unsigned int SEGMENTMEDIA = 64;
+ static const unsigned int SEGMENTMEDIA = 64;
+ static const unsigned int STARTTIMETPL = 128;
+
uint32_t flags_;
uint32_t indexRangeMin_, indexRangeMax_;
- uint8_t channelCount_;
+ uint8_t channelCount_, nalLengthSize_;
SegmentTemplate segtpl_;
//SegmentList
uint32_t duration_, timescale_;
@@ -146,7 +155,7 @@ namespace dash
struct AdaptationSet
{
- AdaptationSet() :type_(NOTYPE), timescale_(0), startPTS_(0){ language_ = "unk"; };
+ AdaptationSet() :type_(NOTYPE), timescale_(0), startPTS_(0), encrypted(false){ language_ = "unk"; };
~AdaptationSet(){ for (std::vector::const_iterator b(repesentations_.begin()), e(repesentations_.end()); b != e; ++b) delete *b; };
StreamType type_;
uint32_t timescale_;
@@ -162,6 +171,7 @@ namespace dash
return *segment_durations_[pos];
};
SegmentTemplate segtpl_;
+ bool encrypted;
}*current_adaptationset_;
struct Period
@@ -180,14 +190,16 @@ namespace dash
uint32_t currentNode_;
uint32_t segcount_;
double overallSeconds_;
- uint64_t stream_start_, live_start_, publish_time_, base_time_;
+ uint64_t stream_start_, available_time_, publish_time_, base_time_;
double minPresentationOffset;
+ bool has_timeshift_buffer_;
uint32_t bandwidth_;
double download_speed_, average_download_speed_;
-
+
std::pair pssh_, adp_pssh_;
+ std::string defaultKID_;
enum
{
@@ -197,41 +209,26 @@ namespace dash
};
unsigned int encryptionState_;
uint8_t adpChannelCount_;
+ uint16_t adpwidth_, adpheight_;
+ uint32_t adpfpsRate_;
- enum
- {
- MPDNODE_MPD = 1 << 0,
- MPDNODE_PERIOD = 1 << 1,
- MPDNODE_ADAPTIONSET = 1 << 2,
- MPDNODE_CONTENTPROTECTION = 1 << 3,
- MPDNODE_REPRESENTATION = 1 << 4,
- MPDNODE_BASEURL = 1 << 5,
- MPDNODE_SEGMENTLIST = 1 << 6,
- MPDNODE_INITIALIZATION = 1 << 7,
- MPDNODE_SEGMENTURL = 1 << 8,
- MPDNODE_SEGMENTDURATIONS = 1 << 9,
- MPDNODE_S = 1 << 11,
- MPDNODE_PSSH = 1 << 12,
- MPDNODE_SEGMENTTEMPLATE = 1 << 13,
- MPDNODE_SEGMENTTIMELINE = 1 << 14
- };
std::string strXMLText_;
- DASHTree();
- ~DASHTree();
- bool open(const char *url);
+ AdaptiveTree();
bool has_type(StreamType t);
uint32_t estimate_segcount(uint32_t duration, uint32_t timescale);
double get_download_speed() const { return download_speed_; };
double get_average_download_speed() const { return average_download_speed_; };
void set_download_speed(double speed);
- void SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint32_t fragmentDuration);
+ void SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint32_t fragmentDuration, uint32_t movie_timescale);
- bool empty();
+ bool empty(){ return !current_period_ || current_period_->adaptationSets_.empty(); };
const AdaptationSet *GetAdaptationSet(unsigned int pos) const { return current_period_ && pos < current_period_->adaptationSets_.size() ? current_period_->adaptationSets_[pos] : 0; };
-protected:
- virtual bool download(const char* url);
- bool write_data(void *buffer, size_t buffer_size);
+
+ virtual bool open(const char *url) = 0;
+ protected:
+ virtual bool download(const char* url);
+ virtual bool write_data(void *buffer, size_t buffer_size) = 0;
};
}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.cpp
similarity index 78%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.cpp
index 7a44835e1e..84aecb944e 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.cpp
@@ -20,6 +20,7 @@
#include
#include "oscompat.h"
#include
+#include "ap4/Ap4DataBuffer.h"
#ifndef BYTE
typedef unsigned char BYTE;
@@ -253,3 +254,69 @@ std::string annexb_to_avc(const char *b16_data)
return result;
}
+
+void prkid2wvkid(const char *input, char *output)
+{
+ static const uint8_t remap[16] = { 3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15 };
+ for (unsigned int i(0); i < 16; ++i)
+ output[i] = input[remap[i]];
+}
+
+bool create_ism_license(std::string key, std::string license_data, AP4_DataBuffer &init_data)
+{
+ if (key.size() != 16 || license_data.empty())
+ {
+ init_data.SetDataSize(0);
+ return false;
+ }
+
+ uint8_t ld[1024];
+ unsigned int ld_size(1024);
+ b64_decode(license_data.c_str(), license_data.size(), ld, ld_size);
+
+ const uint8_t *uuid((uint8_t*)strstr((const char*)ld, "{UUID}"));
+ unsigned int license_size = uuid ? ld_size + 36 - 6 : ld_size;
+
+ //Build up proto header
+ init_data.Reserve(512);
+ uint8_t *protoptr(init_data.UseData());
+ *protoptr++ = 18; //id=16>>3=2, type=2(flexlen)
+ *protoptr++ = 16; //length of key
+ memcpy(protoptr, key.data(), 16);
+ protoptr += 16;
+ //-----------
+ *protoptr++ = 34;//id=32>>3=4, type=2(flexlen)
+ do {
+ *protoptr++ = static_cast(license_size & 127);
+ license_size >>= 7;
+ if (license_size)
+ *(protoptr - 1) |= 128;
+ else
+ break;
+ } while (1);
+ if (uuid)
+ {
+ static const uint8_t hexmap[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
+ memcpy(protoptr, ld, uuid - ld);
+ protoptr += uuid - ld;
+
+ for (unsigned int i(0); i < 16; ++i)
+ {
+ if(i == 4 || i == 6 || i == 8 || i == 10)
+ *protoptr++ = '-';
+ *protoptr++ = hexmap[(uint8_t)(key.data()[i]) >> 4];
+ *protoptr++ = hexmap[(uint8_t)(key.data()[i]) & 15];
+ }
+ unsigned int sizeleft = ld_size - ((uuid - ld) + 6);
+ memcpy(protoptr, uuid + 6, sizeleft);
+ protoptr += sizeleft;
+ }
+ else
+ {
+ memcpy(protoptr, ld, ld_size);
+ protoptr += ld_size;
+ }
+ init_data.SetDataSize(protoptr - init_data.UseData());
+
+ return true;
+}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.h
similarity index 85%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.h
index c28400a4a3..7052cc6ff6 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/helpers.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/helpers.h
@@ -22,6 +22,9 @@
#include
#include
+
+class AP4_DataBuffer;
+
bool b64_decode(const char *in, unsigned int in_len, uint8_t *out, unsigned int &out_len);
std::string b64_encode(unsigned char const* in, unsigned int in_len, bool urlEncode);
@@ -33,3 +36,6 @@ std::string &trim(std::string &src);
std::string url_decode(std::string text);
std::string annexb_to_avc(const char *b16_data);
+
+void prkid2wvkid(const char *input, char *output);
+bool create_ism_license(std::string key, std::string license_data, AP4_DataBuffer &init_data);
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.cpp
similarity index 100%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.cpp
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.h
similarity index 100%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/oscompat.h
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/oscompat.h
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.cpp
similarity index 84%
rename from xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.cpp
rename to xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.cpp
index b0b520f293..886b15d163 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/dash/DASHTree.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.cpp
@@ -15,18 +15,14 @@
#include
#include "DASHTree.h"
-#include "oscompat.h"
-#include "helpers.h"
+#include "../oscompat.h"
+#include "../helpers.h"
-#include "URL.h"
-#include "filesystem/File.h"
#include "utils/log.h"
-#include "utils/URIUtils.h"
//#define DEBUG_VERBOSE 1
-using namespace dash;
-using namespace XFILE;
+using namespace adaptive;
const char* TRANSLANG[370] = {
"aa", "aar",
@@ -230,15 +226,6 @@ static const char* ltranslate(const char * in)
}
DASHTree::DASHTree()
- :download_speed_(0.0)
- , average_download_speed_(0.0f)
- , parser_(0)
- , encryptionState_(ENCRYTIONSTATE_UNENCRYPTED)
- , current_period_(0)
- , live_start_(0)
- , stream_start_(0)
- , base_time_(0)
- , publish_time_(0)
{
}
@@ -357,7 +344,7 @@ start(void *data, const char *el, const char **attr)
else if (strcmp((const char*)*attr, "media") == 0)
{
seg.media_ = (const char*)*(attr + 1);
- dash->current_representation_->flags_ |= DASHTree::Representation::SEGMENTMEDIA;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::SEGMENTMEDIA;
}
attr += 2;
}
@@ -372,11 +359,11 @@ start(void *data, const char *el, const char **attr)
else if (strcmp((const char*)*attr, "sourceURL") == 0)
{
seg.media_ = (const char*)*(attr + 1);
- dash->current_representation_->flags_ |= DASHTree::Representation::SEGMENTMEDIA;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::SEGMENTMEDIA;
}
attr += 2;
}
- dash->current_representation_->flags_ |= DASHTree::Representation::INITIALIZATION;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
dash->current_representation_->initialization_ = seg;
}
else
@@ -402,13 +389,13 @@ start(void *data, const char *el, const char **attr)
}
if (d && r)
{
- DASHTree::Segment s;
+ adaptive::AdaptiveTree::Segment s;
if (dash->current_representation_->segments_.data.empty())
{
if (dash->current_representation_->segtpl_.duration && dash->current_representation_->segtpl_.timescale)
dash->current_representation_->segments_.data.reserve((unsigned int)(dash->overallSeconds_ / (((double)dash->current_representation_->segtpl_.duration) / dash->current_representation_->segtpl_.timescale)) + 1);
- if (dash->current_representation_->flags_ & DASHTree::Representation::INITIALIZATION)
+ if (dash->current_representation_->flags_ & adaptive::AdaptiveTree::Representation::INITIALIZATION)
{
s.range_begin_ = s.range_end_ = ~0;
dash->current_representation_->initialization_ = s;
@@ -436,7 +423,7 @@ start(void *data, const char *el, const char **attr)
}
else if (strcmp(el, "SegmentTimeline") == 0)
{
- dash->current_representation_->flags_ |= DASHTree::Representation::TIMELINE;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::TIMELINE;
dash->currentNode_ |= DASHTree::MPDNODE_SEGMENTTIMELINE;
}
}
@@ -475,11 +462,11 @@ start(void *data, const char *el, const char **attr)
if (strcmp((const char*)*attr, "indexRange") == 0)
sscanf((const char*)*(attr + 1), "%u-%u" , &dash->current_representation_->indexRangeMin_, &dash->current_representation_->indexRangeMax_);
else if (strcmp((const char*)*attr, "indexRangeExact") == 0 && strcmp((const char*)*(attr + 1), "true") == 0)
- dash->current_representation_->flags_ |= DASHTree::Representation::INDEXRANGEEXACT;
- dash->current_representation_->flags_ |= DASHTree::Representation::SEGMENTBASE;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::INDEXRANGEEXACT;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::SEGMENTBASE;
attr += 2;
}
- if((dash->current_representation_->flags_ & DASHTree::Representation::INDEXRANGEEXACT) && dash->current_representation_->indexRangeMax_)
+ if((dash->current_representation_->flags_ & adaptive::AdaptiveTree::Representation::INDEXRANGEEXACT) && dash->current_representation_->indexRangeMax_)
dash->currentNode_ |= DASHTree::MPDNODE_SEGMENTLIST;
}
else if (strcmp(el, "SegmentTemplate") == 0)
@@ -487,10 +474,10 @@ start(void *data, const char *el, const char **attr)
dash->current_representation_->segtpl_ = dash->current_adaptationset_->segtpl_;
ParseSegmentTemplate(attr, dash->current_representation_->url_, dash->current_representation_->segtpl_, false);
- dash->current_representation_->flags_ |= DASHTree::Representation::TEMPLATE;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::TEMPLATE;
if (!dash->current_representation_->segtpl_.initialization.empty())
{
- dash->current_representation_->flags_ |= DASHTree::Representation::INITIALIZATION;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
dash->current_representation_->url_ += dash->current_representation_->segtpl_.initialization;
dash->current_representation_->timescale_ = dash->current_representation_->segtpl_.timescale;
}
@@ -544,9 +531,9 @@ start(void *data, const char *el, const char **attr)
if (strcmp((const char*)*attr, "contentType") == 0)
{
dash->current_adaptationset_->type_ =
- stricmp((const char*)*(attr + 1), "video") == 0 ? DASHTree::VIDEO
- : stricmp((const char*)*(attr + 1), "audio") == 0 ? DASHTree::AUDIO
- : DASHTree::NOTYPE;
+ stricmp((const char*)*(attr + 1), "video") == 0 ? adaptive::AdaptiveTree::VIDEO
+ : stricmp((const char*)*(attr + 1), "audio") == 0 ? adaptive::AdaptiveTree::AUDIO
+ : adaptive::AdaptiveTree::NOTYPE;
break;
}
attr += 2;
@@ -563,7 +550,7 @@ start(void *data, const char *el, const char **attr)
}
else if (strcmp(el, "Representation") == 0)
{
- dash->current_representation_ = new DASHTree::Representation();
+ dash->current_representation_ = new adaptive::AdaptiveTree::Representation();
dash->current_representation_->channelCount_ = dash->adpChannelCount_;
dash->current_representation_->codecs_ = dash->current_adaptationset_->codecs_;
dash->current_representation_->url_ = dash->current_adaptationset_->base_url_;
@@ -617,7 +604,7 @@ start(void *data, const char *el, const char **attr)
else if (strcmp(el, "ContentProtection") == 0)
{
dash->strXMLText_.clear();
- dash->encryptionState_ |= DASHTree::ENCRYTIONSTATE_ENCRYPTED;
+ dash->encryptionState_ |= adaptive::AdaptiveTree::ENCRYTIONSTATE_ENCRYPTED;
bool urnFound(false);
for (; *attr;)
{
@@ -631,7 +618,7 @@ start(void *data, const char *el, const char **attr)
if (urnFound)
{
dash->currentNode_ |= DASHTree::MPDNODE_CONTENTPROTECTION;
- dash->encryptionState_ |= DASHTree::ENCRYTIONSTATE_SUPPORTED;
+ dash->encryptionState_ |= adaptive::AdaptiveTree::ENCRYTIONSTATE_SUPPORTED;
}
}
else if (strcmp(el, "AudioChannelConfiguration") == 0)
@@ -647,7 +634,7 @@ start(void *data, const char *el, const char **attr)
else if (strcmp(el, "AdaptationSet") == 0)
{
//
- dash->current_adaptationset_ = new DASHTree::AdaptationSet();
+ dash->current_adaptationset_ = new adaptive::AdaptiveTree::AdaptationSet();
dash->current_period_->adaptationSets_.push_back(dash->current_adaptationset_);
dash->current_adaptationset_->base_url_ = dash->current_period_->base_url_;
dash->adp_pssh_.second.clear();
@@ -657,9 +644,9 @@ start(void *data, const char *el, const char **attr)
{
if (strcmp((const char*)*attr, "contentType") == 0)
dash->current_adaptationset_->type_ =
- stricmp((const char*)*(attr + 1), "video") == 0 ? DASHTree::VIDEO
- : stricmp((const char*)*(attr + 1), "audio") == 0 ? DASHTree::AUDIO
- : DASHTree::NOTYPE;
+ stricmp((const char*)*(attr + 1), "video") == 0 ? adaptive::AdaptiveTree::VIDEO
+ : stricmp((const char*)*(attr + 1), "audio") == 0 ? adaptive::AdaptiveTree::AUDIO
+ : adaptive::AdaptiveTree::NOTYPE;
else if (strcmp((const char*)*attr, "lang") == 0)
dash->current_adaptationset_->language_ = ltranslate((const char*)*(attr + 1));
else if (strcmp((const char*)*attr, "mimeType") == 0)
@@ -681,7 +668,7 @@ start(void *data, const char *el, const char **attr)
}
else if (strcmp(el, "Period") == 0)
{
- dash->current_period_ = new DASHTree::Period();
+ dash->current_period_ = new adaptive::AdaptiveTree::Period();
dash->current_period_->base_url_ = dash->base_url_;
dash->periods_.push_back(dash->current_period_);
dash->currentNode_ |= DASHTree::MPDNODE_PERIOD;
@@ -697,9 +684,16 @@ start(void *data, const char *el, const char **attr)
if (strcmp((const char*)*attr, "mediaPresentationDuration") == 0)
mpt = (const char*)*(attr + 1);
else if (strcmp((const char*)*attr, "timeShiftBufferDepth") == 0)
+ {
tsbd = (const char*)*(attr + 1);
+ dash->has_timeshift_buffer_ = true;
+ }
else if (strcmp((const char*)*attr, "availabilityStartTime") == 0)
- dash->live_start_ = getTime((const char*)*(attr + 1));
+ {
+ dash->available_time_ = getTime((const char*)*(attr + 1));
+ if (!dash->available_time_)
+ dash->available_time_ = ~0ULL;
+ }
else if (strcmp((const char*)*attr, "publishTime") == 0)
dash->publish_time_ = getTime((const char*)*(attr + 1));
attr += 2;
@@ -724,8 +718,8 @@ start(void *data, const char *el, const char **attr)
if (next)
dash->overallSeconds_ += atof(mpt);
}
- if (dash->publish_time_ && dash->live_start_ && dash->publish_time_ - dash->live_start_ > dash->overallSeconds_)
- dash->base_time_ = dash->publish_time_ - dash->live_start_ - dash->overallSeconds_;
+ if (dash->publish_time_ && dash->available_time_ && dash->publish_time_ - dash->available_time_ > dash->overallSeconds_)
+ dash->base_time_ = dash->publish_time_ - dash->available_time_ - dash->overallSeconds_;
dash->minPresentationOffset = DBL_MAX;
dash->currentNode_ |= DASHTree::MPDNODE_MPD;
@@ -824,7 +818,7 @@ end(void *data, const char *el)
if (dash->current_representation_->segments_.data.empty())
{
bool isSegmentTpl(!dash->current_representation_->segtpl_.media.empty());
- DASHTree::SegmentTemplate &tpl(isSegmentTpl ? dash->current_representation_->segtpl_ : dash->current_adaptationset_->segtpl_);
+ adaptive::AdaptiveTree::SegmentTemplate &tpl(isSegmentTpl ? dash->current_representation_->segtpl_ : dash->current_adaptationset_->segtpl_);
if (!tpl.media.empty() && dash->overallSeconds_ > 0
&& tpl.timescale > 0 && (tpl.duration > 0 || dash->current_adaptationset_->segment_durations_.data.size()))
@@ -834,10 +828,10 @@ end(void *data, const char *el)
if (countSegs < 65536)
{
- DASHTree::Segment seg;
+ adaptive::AdaptiveTree::Segment seg;
seg.range_begin_ = ~0;
- dash->current_representation_->flags_ |= DASHTree::Representation::TEMPLATE;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::TEMPLATE;
dash->current_representation_->segments_.data.reserve(countSegs);
if (!tpl.initialization.empty())
@@ -852,20 +846,20 @@ end(void *data, const char *el)
}
dash->current_representation_->initialization_ = seg;
- dash->current_representation_->flags_ |= DASHTree::Representation::INITIALIZATION;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::INITIALIZATION;
}
std::vector::const_iterator sdb(dash->current_adaptationset_->segment_durations_.data.begin()),
sde(dash->current_adaptationset_->segment_durations_.data.end());
bool timeBased = sdb!=sde && tpl.media.find("$Time") != std::string::npos;
if(timeBased)
- dash->current_representation_->flags_ |= DASHTree::Representation::TIMETEMPLATE;
+ dash->current_representation_->flags_ |= adaptive::AdaptiveTree::Representation::TIMETEMPLATE;
seg.range_end_ = timeBased ? dash->current_adaptationset_->startPTS_ : tpl.startNumber;
seg.startPTS_ = dash->current_adaptationset_->startPTS_;
- if (!timeBased && dash->live_start_ /*&& !dash->publish_time_*/ && dash->stream_start_ - dash->live_start_ > dash->overallSeconds_) //we need to adjust the start-segment
- seg.range_end_ += ((dash->stream_start_ - dash->live_start_ - dash->overallSeconds_)*tpl.timescale) / tpl.duration;
+ if (!timeBased && dash->available_time_ /*&& !dash->publish_time_*/ && dash->stream_start_ - dash->available_time_ > dash->overallSeconds_) //we need to adjust the start-segment
+ seg.range_end_ += ((dash->stream_start_ - dash->available_time_ - dash->overallSeconds_)*tpl.timescale) / tpl.duration;
for (;countSegs;--countSegs)
{
@@ -876,7 +870,7 @@ end(void *data, const char *el)
return;
}
}
- else if (dash->current_representation_->flags_ & DASHTree::Representation::SEGMENTMEDIA)
+ else if (dash->current_representation_->flags_ & adaptive::AdaptiveTree::Representation::SEGMENTMEDIA)
{
if (dash->current_representation_->segments_.data.size() != dash->current_adaptationset_->segment_durations_.data.size())
{
@@ -890,7 +884,7 @@ end(void *data, const char *el)
t += dash->current_adaptationset_->segment_durations_.data[i];
}
}
- else if (dash->current_representation_->flags_ & DASHTree::Representation::SEGMENTBASE)
+ else if (dash->current_representation_->flags_ & adaptive::AdaptiveTree::Representation::SEGMENTBASE)
{}
else
{
@@ -947,8 +941,8 @@ end(void *data, const char *el)
else if (strcmp(el, "AdaptationSet") == 0)
{
dash->currentNode_ &= ~DASHTree::MPDNODE_ADAPTIONSET;
- if (dash->current_adaptationset_->type_ == DASHTree::NOTYPE
- || ((dash->encryptionState_ & DASHTree::ENCRYTIONSTATE_ENCRYPTED) && dash->adp_pssh_.second.empty())
+ if (dash->current_adaptationset_->type_ == adaptive::AdaptiveTree::NOTYPE
+ || ((dash->encryptionState_ & adaptive::AdaptiveTree::ENCRYTIONSTATE_ENCRYPTED) && dash->adp_pssh_.second.empty())
|| dash->current_adaptationset_->repesentations_.empty())
{
delete dash->current_adaptationset_;
@@ -961,7 +955,7 @@ end(void *data, const char *el)
if (dash->current_adaptationset_->segment_durations_.data.empty()
&& !dash->current_adaptationset_->segtpl_.media.empty())
{
- for (std::vector::iterator
+ for (std::vector::iterator
b(dash->current_adaptationset_->repesentations_.begin()),
e(dash->current_adaptationset_->repesentations_.end()); b != e; ++b)
{
@@ -975,16 +969,16 @@ end(void *data, const char *el)
else if (!dash->current_adaptationset_->segment_durations_.data.empty())
//If representation are not timelined, we have to adjust startPTS_ in rep::segments
{
- for (std::vector::iterator
+ for (std::vector::iterator
b(dash->current_adaptationset_->repesentations_.begin()),
e(dash->current_adaptationset_->repesentations_.end()); b != e; ++b)
{
- if ((*b)->flags_ & DASHTree::Representation::TIMELINE)
+ if ((*b)->flags_ & adaptive::AdaptiveTree::Representation::TIMELINE)
continue;
std::vector::const_iterator sdb(dash->current_adaptationset_->segment_durations_.data.begin()),
sde(dash->current_adaptationset_->segment_durations_.data.end());
uint64_t spts(0);
- for (std::vector::iterator sb((*b)->segments_.data.begin()), se((*b)->segments_.data.end()); sb != se && sdb != sde; ++sb, ++sdb)
+ for (std::vector::iterator sb((*b)->segments_.data.begin()), se((*b)->segments_.data.end()); sb != se && sdb != sde; ++sb, ++sdb)
{
sb->startPTS_ = spts;
spts += *sdb;
@@ -1010,18 +1004,6 @@ end(void *data, const char *el)
| DASHTree
+---------------------------------------------------------------------*/
-void DASHTree::Segment::SetRange(const char *range)
-{
- const char *delim(strchr(range, '-'));
- if (delim)
- {
- range_begin_ = strtoull(range, 0, 10);
- range_end_ = strtoull(delim + 1, 0, 10);
- }
- else
- range_begin_ = range_end_ = 0;
-}
-
bool DASHTree::open(const char *url)
{
parser_ = XML_ParserCreate(NULL);
@@ -1054,92 +1036,3 @@ bool DASHTree::write_data(void *buffer, size_t buffer_size)
}
return true;
}
-
-bool DASHTree::has_type(StreamType t)
-{
- if (periods_.empty())
- return false;
-
- for (std::vector::const_iterator b(periods_[0]->adaptationSets_.begin()), e(periods_[0]->adaptationSets_.end()); b != e; ++b)
- if ((*b)->type_ == t)
- return true;
- return false;
-}
-
-uint32_t DASHTree::estimate_segcount(uint32_t duration, uint32_t timescale)
-{
- duration /= timescale;
- return static_cast((overallSeconds_ / duration)*1.01);
-}
-
-void DASHTree::set_download_speed(double speed)
-{
- download_speed_ = speed;
- if (!average_download_speed_)
- average_download_speed_ = download_speed_;
- else
- average_download_speed_ = average_download_speed_*0.9 + download_speed_*0.1;
-};
-
-void DASHTree::SetFragmentDuration(const AdaptationSet* adp, const Representation* rep, size_t pos, uint32_t fragmentDuration)
-{
- if (!live_start_ /*|| !(rep->flags_ & DASHTree::Representation::TIMELINE)*/)
- return;
-
- //Get a modifiable adaptationset
- AdaptationSet *adpm(static_cast((void*)adp));
-
- // Check if its the last frame we watch
- if (adp->segment_durations_.data.size())
- {
- if (pos == adp->segment_durations_.data.size() - 1)
- {
- adpm->segment_durations_.insert(fragmentDuration);
- }
- else
- return;
- }
- else if (pos != rep->segments_.data.size() - 1)
- return;
-
- Segment seg(*(rep->segments_[pos]));
- seg.range_begin_ += fragmentDuration;
- seg.range_end_ += (rep->flags_ & DASHTree::Representation::TIMETEMPLATE)?fragmentDuration:1;
- seg.startPTS_ += fragmentDuration;
-
- for (std::vector::iterator b(adpm->repesentations_.begin()), e(adpm->repesentations_.end()); b != e; ++b)
- (*b)->segments_.insert(seg);
-}
-
-bool DASHTree::empty()
-{
- return (!current_period_ || current_period_->adaptationSets_.empty());
-}
-
-bool DASHTree::download(const char* url)
-{
- // open the file
- CURL uUrl(url);
- if (URIUtils::IsInternetStream(uUrl))
- {
- uUrl.SetProtocolOption("seekable", "0");
- uUrl.SetProtocolOption("acceptencoding", "gzip");
- }
-
- CFile* file = new CFile();
- if (!file->Open(uUrl, READ_CHUNKED | READ_NO_CACHE))
- return false;
-
- // read the file
- static const unsigned int CHUNKSIZE = 16384;
- char buf[CHUNKSIZE];
- size_t nbRead;
- while ((nbRead = file->Read(buf, CHUNKSIZE)) > 0 && ~nbRead && write_data(buf, nbRead));
-
- //download_speed_ = xbmc->GetFileDownloadSpeed(file);
-
- file->Close();
- delete file;
-
- return nbRead == 0;
-}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.h
new file mode 100644
index 0000000000..8544796434
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/DASHTree.h
@@ -0,0 +1,53 @@
+/*
+* DASHTree.h
+*****************************************************************************
+* Copyright (C) 2015, liberty_developer
+*
+* Email: liberty.developer@xmail.net
+*
+* This source code and its use and distribution, is subject to the terms
+* and conditions of the applicable license agreement.
+*****************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "expat.h"
+
+#include "../common/AdaptiveTree.h"
+
+namespace adaptive
+{
+
+ class DASHTree : public AdaptiveTree
+ {
+ public:
+ enum
+ {
+ MPDNODE_MPD = 1 << 0,
+ MPDNODE_PERIOD = 1 << 1,
+ MPDNODE_ADAPTIONSET = 1 << 2,
+ MPDNODE_CONTENTPROTECTION = 1 << 3,
+ MPDNODE_REPRESENTATION = 1 << 4,
+ MPDNODE_BASEURL = 1 << 5,
+ MPDNODE_SEGMENTLIST = 1 << 6,
+ MPDNODE_INITIALIZATION = 1 << 7,
+ MPDNODE_SEGMENTURL = 1 << 8,
+ MPDNODE_SEGMENTDURATIONS = 1 << 9,
+ MPDNODE_S = 1 << 11,
+ MPDNODE_PSSH = 1 << 12,
+ MPDNODE_SEGMENTTEMPLATE = 1 << 13,
+ MPDNODE_SEGMENTTIMELINE = 1 << 14
+ };
+
+ DASHTree();
+ virtual ~DASHTree();
+
+ virtual bool open(const char *url) override;
+ virtual bool write_data(void *buffer, size_t buffer_size) override;
+};
+
+}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.cpp
new file mode 100755
index 0000000000..b29959d8a6
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.cpp
@@ -0,0 +1,402 @@
+/*
+* Copyright (C) 2016-2016 peak3d
+* http://www.peak3d.de
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* .
+*
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "SmoothTree.h"
+#include "../oscompat.h"
+#include "../helpers.h"
+
+using namespace adaptive;
+
+uint32_t gTimeScale = 10000000;
+
+SmoothTree::SmoothTree()
+{
+ current_period_ = new AdaptiveTree::Period;
+ periods_.push_back(current_period_);
+}
+
+/*----------------------------------------------------------------------
+| expat start
++---------------------------------------------------------------------*/
+static void XMLCALL
+start(void *data, const char *el, const char **attr)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+
+ if (dash->currentNode_ & SmoothTree::SSMNODE_SSM)
+ {
+ if (dash->currentNode_ & SmoothTree::SSMNODE_PROTECTION)
+ {
+ if (strcmp(el, "ProtectionHeader") == 0)
+ {
+ for (; *attr;)
+ {
+ if (strcmp((const char*)*attr, "SystemID") == 0)
+ {
+ if (strstr((const char*)*(attr + 1), "9A04F079-9840-4286-AB92-E65BE0885F95")
+ || strstr((const char*)*(attr + 1), "9a04f079-9840-4286-ab92-e65be0885f95"))
+ {
+ dash->strXMLText_.clear();
+ dash->currentNode_ |= SmoothTree::SSMNODE_PROTECTIONHEADER| SmoothTree::SSMNODE_PROTECTIONTEXT;
+ }
+ break;
+ }
+ attr += 2;
+ }
+ }
+ }
+ else if (dash->currentNode_ & SmoothTree::SSMNODE_STREAMINDEX)
+ {
+ if (strcmp(el, "QualityLevel") == 0)
+ {
+ //
+ //
+
+ std::string::size_type pos = dash->current_adaptationset_->base_url_.find("{bitrate}");
+ if (pos == std::string::npos)
+ return;
+
+ dash->current_representation_ = new SmoothTree::Representation();
+ dash->current_representation_->url_ = dash->current_adaptationset_->base_url_;
+ dash->current_representation_->timescale_ = dash->current_adaptationset_->timescale_;
+ dash->current_representation_->flags_ |= SmoothTree::Representation::STARTTIMETPL;
+
+ const char *bw = "0";
+
+ for (; *attr;)
+ {
+ if (strcmp((const char*)*attr, "Bitrate") == 0)
+ bw = (const char*)*(attr + 1);
+ else if (strcmp((const char*)*attr, "FourCC") == 0)
+ {
+ dash->current_representation_->codecs_ = (const char*)*(attr + 1);
+ std::transform(dash->current_representation_->codecs_.begin(), dash->current_representation_->codecs_.end(), dash->current_representation_->codecs_.begin(), ::tolower);
+ }
+ else if (strcmp((const char*)*attr, "MaxWidth") == 0)
+ dash->current_representation_->width_ = static_cast(atoi((const char*)*(attr + 1)));
+ else if (strcmp((const char*)*attr, "MaxHeight") == 0)
+ dash->current_representation_->height_ = static_cast(atoi((const char*)*(attr + 1)));
+ else if (strcmp((const char*)*attr, "SamplingRate") == 0)
+ dash->current_representation_->samplingRate_ = static_cast(atoi((const char*)*(attr + 1)));
+ else if (strcmp((const char*)*attr, "Channels") == 0)
+ dash->current_representation_->channelCount_ = static_cast(atoi((const char*)*(attr + 1)));
+ else if (strcmp((const char*)*attr, "Index") == 0)
+ dash->current_representation_->id = (const char*)*(attr + 1);
+ else if (strcmp((const char*)*attr, "CodecPrivateData") == 0)
+ dash->current_representation_->codec_private_data_ = annexb_to_avc((const char*)*(attr + 1));
+ else if (strcmp((const char*)*attr, "NALUnitLengthField") == 0)
+ dash->current_representation_->nalLengthSize_ = static_cast(atoi((const char*)*(attr + 1)));
+ attr += 2;
+ }
+ dash->current_representation_->url_.replace(pos, 9, bw);
+ dash->current_representation_->bandwidth_ = atoi(bw);
+ dash->current_adaptationset_->repesentations_.push_back(dash->current_representation_);
+ }
+ else if (strcmp(el, "c") == 0)
+ {
+ //
+ uint32_t push_duration(~0);
+
+ for (; *attr;)
+ {
+ if (*(const char*)*attr == 't')
+ {
+ uint64_t lt(atoll((const char*)*(attr + 1)));
+ if (!dash->current_adaptationset_->segment_durations_.data.empty())
+ dash->current_adaptationset_->segment_durations_.data.back() = static_cast(lt - dash->pts_helper_);
+ else
+ dash->current_adaptationset_->startPTS_ = lt;
+ dash->pts_helper_ = lt;
+ push_duration = 0;
+ }
+ else if (*(const char*)*attr == 'd')
+ {
+ push_duration = atoi((const char*)*(attr + 1));
+ break;
+ }
+ attr += 2;
+ }
+ if (~push_duration)
+ dash->current_adaptationset_->segment_durations_.data.push_back(push_duration);
+ }
+ }
+ else if (strcmp(el, "StreamIndex") == 0)
+ {
+ //
+ dash->current_adaptationset_ = new SmoothTree::AdaptationSet();
+ dash->current_period_->adaptationSets_.push_back(dash->current_adaptationset_);
+ dash->current_adaptationset_->encrypted = dash->encryptionState_ == SmoothTree::ENCRYTIONSTATE_SUPPORTED;
+ dash->current_adaptationset_->timescale_ = gTimeScale;
+
+ for (; *attr;)
+ {
+ if (strcmp((const char*)*attr, "Type") == 0)
+ dash->current_adaptationset_->type_ =
+ stricmp((const char*)*(attr + 1), "video") == 0 ? SmoothTree::VIDEO
+ : stricmp((const char*)*(attr + 1), "audio") == 0 ? SmoothTree::AUDIO
+ : SmoothTree::NOTYPE;
+ else if (strcmp((const char*)*attr, "Language") == 0)
+ dash->current_adaptationset_->language_ = (const char*)*(attr + 1);
+ else if (strcmp((const char*)*attr, "TimeScale") == 0)
+ dash->current_adaptationset_->timescale_ = atoi((const char*)*(attr + 1));
+ else if (strcmp((const char*)*attr, "Chunks") == 0)
+ dash->current_adaptationset_->segment_durations_.data.reserve(atoi((const char*)*(attr + 1)));
+ else if (strcmp((const char*)*attr, "Url") == 0)
+ dash->current_adaptationset_->base_url_ = dash->base_url_ + (const char*)*(attr + 1);
+ attr += 2;
+ }
+ dash->segcount_ = 0;
+ dash->currentNode_ |= SmoothTree::SSMNODE_STREAMINDEX;
+ }
+ else if (strcmp(el, "Protection") == 0)
+ {
+ dash->currentNode_ |= SmoothTree::SSMNODE_PROTECTION;
+ dash->encryptionState_ = SmoothTree::ENCRYTIONSTATE_SUPPORTED;
+ }
+ }
+ else if (strcmp(el, "SmoothStreamingMedia") == 0)
+ {
+ uint64_t duration = 0;
+ dash->overallSeconds_ = 0;
+ for (; *attr;)
+ {
+ if (strcmp((const char*)*attr, "TimeScale") == 0)
+ gTimeScale = atoll((const char*)*(attr + 1));
+ else if (strcmp((const char*)*attr, "Duration") == 0)
+ duration = atoll((const char*)*(attr + 1));
+ else if (strcmp((const char*)*attr, "IsLive") == 0)
+ {
+ dash->has_timeshift_buffer_ = strcmp((const char*)*(attr + 1), "TRUE") == 0;
+ if (dash->has_timeshift_buffer_)
+ {
+ dash->stream_start_ = time(0);
+ dash->available_time_ = dash->stream_start_;
+ }
+ }
+ attr += 2;
+ }
+ dash->overallSeconds_ = (double)duration / gTimeScale;
+ dash->currentNode_ |= SmoothTree::SSMNODE_SSM;
+ dash->minPresentationOffset = DBL_MAX;
+ dash->base_time_ = ~0ULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| expat text
++---------------------------------------------------------------------*/
+static void XMLCALL
+text(void *data, const char *s, int len)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+
+ if (dash->currentNode_ & SmoothTree::SSMNODE_PROTECTIONTEXT)
+ dash->strXMLText_ += std::string(s, len);
+}
+
+/*----------------------------------------------------------------------
+| expat end
++---------------------------------------------------------------------*/
+static void XMLCALL
+end(void *data, const char *el)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+
+ if (dash->currentNode_ & SmoothTree::SSMNODE_SSM)
+ {
+ if (dash->currentNode_ & SmoothTree::SSMNODE_PROTECTION)
+ {
+ if (dash->currentNode_ & SmoothTree::SSMNODE_PROTECTIONHEADER)
+ {
+ if (strcmp(el, "ProtectionHeader") == 0)
+ dash->currentNode_ &= ~SmoothTree::SSMNODE_PROTECTIONHEADER;
+ }
+ else if (strcmp(el, "Protection") == 0)
+ {
+ dash->currentNode_ &= ~(SmoothTree::SSMNODE_PROTECTION| SmoothTree::SSMNODE_PROTECTIONTEXT);
+ dash->parse_protection();
+ }
+ }
+ else if (dash->currentNode_ & SmoothTree::SSMNODE_STREAMINDEX)
+ {
+ if (strcmp(el, "StreamIndex") == 0)
+ {
+ if (dash->current_adaptationset_->repesentations_.empty()
+ || dash->current_adaptationset_->segment_durations_.data.empty())
+ dash->current_period_->adaptationSets_.pop_back();
+ else
+ {
+ if (dash->current_adaptationset_->startPTS_ < dash->base_time_)
+ dash->base_time_ = dash->current_adaptationset_->startPTS_;
+ }
+ dash->currentNode_ &= ~SmoothTree::SSMNODE_STREAMINDEX;
+ }
+ }
+ else if (strcmp(el, "SmoothStreamingMedia") == 0)
+ dash->currentNode_ &= ~SmoothTree::SSMNODE_SSM;
+ }
+}
+
+/*----------------------------------------------------------------------
+| expat protection start
++---------------------------------------------------------------------*/
+static void XMLCALL
+protection_start(void *data, const char *el, const char **attr)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+ dash->strXMLText_.clear();
+}
+
+/*----------------------------------------------------------------------
+| expat protection text
++---------------------------------------------------------------------*/
+static void XMLCALL
+protection_text(void *data, const char *s, int len)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+ dash->strXMLText_ += std::string(s, len);
+}
+
+/*----------------------------------------------------------------------
+| expat protection end
++---------------------------------------------------------------------*/
+static void XMLCALL
+protection_end(void *data, const char *el)
+{
+ SmoothTree *dash(reinterpret_cast(data));
+ if (strcmp(el, "KID") == 0)
+ {
+ uint8_t buffer[32];
+ unsigned int buffer_size(32);
+ b64_decode(dash->strXMLText_.data(), dash->strXMLText_.size(), buffer, buffer_size);
+
+ if (buffer_size == 16)
+ {
+ dash->defaultKID_.resize(16);
+ prkid2wvkid(reinterpret_cast(buffer), &dash->defaultKID_[0]);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| SmoothTree
++---------------------------------------------------------------------*/
+
+bool SmoothTree::open(const char *url)
+{
+ parser_ = XML_ParserCreate(NULL);
+ if (!parser_)
+ return false;
+ XML_SetUserData(parser_, (void*)this);
+ XML_SetElementHandler(parser_, start, end);
+ XML_SetCharacterDataHandler(parser_, text);
+ currentNode_ = 0;
+ strXMLText_.clear();
+
+ bool ret = download(url);
+
+ XML_ParserFree(parser_);
+ parser_ = 0;
+
+ if (!ret)
+ return false;
+
+ for (std::vector::iterator ba(current_period_->adaptationSets_.begin()), ea(current_period_->adaptationSets_.end()); ba != ea; ++ba)
+ {
+ for (std::vector::iterator b((*ba)->repesentations_.begin()), e((*ba)->repesentations_.end()); b != e; ++b)
+ {
+ (*b)->segments_.data.resize((*ba)->segment_durations_.data.size());
+ std::vector::iterator bsd((*ba)->segment_durations_.data.begin());
+ uint64_t cummulated = (*ba)->startPTS_ - base_time_;
+ for (std::vector::iterator bs((*b)->segments_.data.begin()), es((*b)->segments_.data.end()); bs != es; ++bsd, ++bs)
+ {
+ bs->range_begin_ = ~0;
+ bs->range_end_ = bs->startPTS_ = cummulated;
+ cummulated += *bsd;
+ }
+ }
+ }
+ return true;
+}
+
+bool SmoothTree::write_data(void *buffer, size_t buffer_size)
+{
+ bool done(false);
+ XML_Status retval = XML_Parse(parser_, (const char*)buffer, buffer_size, done);
+
+ if (retval == XML_STATUS_ERROR)
+ {
+ unsigned int byteNumber = XML_GetErrorByteIndex(parser_);
+ return false;
+ }
+ return true;
+}
+
+void SmoothTree::parse_protection()
+{
+ if (strXMLText_.empty())
+ return;
+
+ //(p)repair the content
+ std::string::size_type pos = 0;
+ while ((pos = strXMLText_.find('\n', 0)) != std::string::npos)
+ strXMLText_.erase(pos, 1);
+
+ while (strXMLText_.size() & 3)
+ strXMLText_ += "=";
+
+ unsigned int xml_size = strXMLText_.size();
+ uint8_t *buffer = (uint8_t*)malloc(xml_size), *xml_start(buffer);
+
+ if (!b64_decode(strXMLText_.c_str(), xml_size, buffer, xml_size))
+ {
+ free(buffer);
+ return;
+ }
+
+ while (xml_size && *xml_start != '<')
+ {
+ xml_start++;
+ xml_size--;
+ }
+
+ XML_Parser pp = XML_ParserCreate("UTF-16");
+ if (!pp)
+ {
+ free(buffer);
+ return;
+ }
+
+ XML_SetUserData(pp, (void*)this);
+ XML_SetElementHandler(pp, protection_start, protection_end);
+ XML_SetCharacterDataHandler(pp, protection_text);
+
+ bool done(false);
+ XML_Parse(pp, (const char*)(xml_start), xml_size, done);
+
+ XML_ParserFree(pp);
+ free(buffer);
+
+ strXMLText_.clear();
+}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.h b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.h
new file mode 100644
index 0000000000..6b32daa6c3
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/adaptive/parsers/SmoothTree.h
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2016-2016 peak3d
+* http://www.peak3d.de
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* .
+*
+*/
+
+#pragma once
+
+#include "../common/AdaptiveTree.h"
+
+namespace adaptive
+{
+
+ class SmoothTree : public AdaptiveTree
+ {
+ public:
+ SmoothTree();
+ virtual bool open(const char *url) override;
+ virtual bool write_data(void *buffer, size_t buffer_size) override;
+
+ void parse_protection();
+
+ enum
+ {
+ SSMNODE_SSM = 1 << 0,
+ SSMNODE_PROTECTION = 1 << 1,
+ SSMNODE_STREAMINDEX = 1 << 2,
+ SSMNODE_PROTECTIONHEADER = 1 << 3,
+ SSMNODE_PROTECTIONTEXT = 1 << 4
+ };
+
+ uint64_t pts_helper_;
+ };
+
+}
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 9574ff01a7..af01d8888c 100755
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -419,7 +419,7 @@ void CAdvancedSettings::Initialize()
m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2|.rss";
m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf";
- m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.mpd|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.mk3d|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv|.ssif";
+ m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.mpd|.ism|.ismc|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.mk3d|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv|.ssif";
m_subtitlesExtensions = ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.text|.ssa|.aqt|.jss|.ass|.idx|.ifo|.rar|.zip";
m_discStubExtensions = ".disc";
// internal music extensions