Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backport][DashTree] Improved clearkey defaultkid workaround #1650

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ CSession::CSession(const std::string& manifestUrl) : m_manifestUrl(manifestUrl)
CSession::~CSession()
{
LOG::Log(LOGDEBUG, "CSession::~CSession()");
m_streams.clear();
DeleteStreams();
DisposeDecrypter();

if (m_adaptiveTree)
Expand All @@ -79,6 +79,12 @@ CSession::~CSession()
m_reprChooser = nullptr;
}

void SESSION::CSession::DeleteStreams()
{
LOG::Log(LOGDEBUG, "CSession::DeleteStreams()");
m_streams.clear();
}

void CSession::SetSupportedDecrypterURN(std::vector<std::string_view>& keySystems)
{
std::string decrypterPath = CSrvBroker::GetSettings().GetDecrypterPath();
Expand Down
2 changes: 2 additions & 0 deletions src/Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
CSession(const std::string& manifestUrl);
virtual ~CSession();

void DeleteStreams();

/*! \brief Initialize the session
* \return True if has success, false otherwise
*/
Expand Down
21 changes: 21 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,27 @@ bool CInputStreamAdaptive::GetStream(int streamid, kodi::addon::InputstreamInfo&

if (stream)
{
// If the stream is encrypted, verify if the decrypter has been initialized
// this is important for HLS because the DRM it is initialized at later time
// so on the OpenStream, instead of CSession::Initialize->InitializePeriod->InitializeDRM
// Since kodi initialize one single stream at time, can happens that or another stream
// has been opened before this one, or another stream will be opened after this one (e.g. unencrypted)
// so if you dont delete all streams, the kodi demux reader still starts
// and a corrupted playback will starts.
// NOTE: GetStream is called by Kodi twice times, before and after OpenStream, on HLS
// the first time all streams are unencrypted because child manifest has not been downloaded
const uint16_t psshSetPos = stream->m_adStream.getRepresentation()->m_psshSetPos;
if (psshSetPos != PSSHSET_POS_DEFAULT ||
stream->m_adStream.getPeriod()->GetEncryptionState() == EncryptionState::NOT_SUPPORTED)
{
if (!m_session->GetSingleSampleDecryptor(psshSetPos))
{
LOG::Log(LOGERROR, "GetStream(%d): Decrypter for the stream not found");
m_session->DeleteStreams();
return false;
}
}

info = stream->m_info;
return true;
}
Expand Down
41 changes: 28 additions & 13 deletions src/parser/DASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1343,26 +1343,41 @@ bool adaptive::CDashTree::GetProtectionData(
//! @todo: this should not be a task of parser, moreover missing an appropriate KID extraction from mp4 box
auto& kodiProps = CSrvBroker::GetKodiProps();
ProtectionScheme ckProtScheme;
if (!protSelected && !protCommon && kodiProps.GetLicenseType() == DRM::KS_CLEARKEY)
if (kodiProps.GetLicenseType() == DRM::KS_CLEARKEY)
{
for (const ProtectionScheme& protScheme : reprProtSchemes)
std::string_view defaultKid;
if (protSelected)
defaultKid = protSelected->kid;
if (defaultKid.empty() && protCommon)
defaultKid = protCommon->kid;

if (defaultKid.empty())
{
if (!protScheme.kid.empty())
for (const ProtectionScheme& protScheme : reprProtSchemes)
{
ckProtScheme.kid = protScheme.kid;
break;
if (!protScheme.kid.empty())
{
defaultKid = protScheme.kid;
break;
}
}
}
if (ckProtScheme.kid.empty())
{
for (const ProtectionScheme& protScheme : adpProtSchemes)
if (defaultKid.empty())
{
ckProtScheme.kid = protScheme.kid;
break;
for (const ProtectionScheme& protScheme : adpProtSchemes)
{
if (!protScheme.kid.empty())
{
defaultKid = protScheme.kid;
break;
}
}
}
}
if (!ckProtScheme.kid.empty())
if (protCommon)
ckProtScheme = *protCommon;

ckProtScheme.kid = defaultKid;
protCommon = &ckProtScheme;
}
}

bool isEncrypted{false};
Expand Down