Skip to content

Commit

Permalink
Begin refactor of wvdecrypter, sample-aes-cbc support
Browse files Browse the repository at this point in the history
  • Loading branch information
glennguy committed Jan 25, 2022
1 parent e484fb4 commit 9c1e139
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 84 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(ADP_HEADERS
src/main.h
src/oscompat.h
src/SSD_dll.h
src/common/AdaptiveDecrypter.h
src/common/AdaptiveStream.h
src/common/AdaptiveTree.h
src/common/RepresentationChooser.h
Expand Down
25 changes: 17 additions & 8 deletions src/SSD_dll.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

//Functionality wich is supported by the Decrypter
class AP4_CencSingleSampleDecrypter;
class Adaptive_CencSingleSampleDecrypter;
class AP4_DataBuffer;

namespace SSD
Expand Down Expand Up @@ -182,15 +182,24 @@ namespace SSD
// Return supported URN if type matches to capabilities, otherwise null
virtual const char *SelectKeySytem(const char* keySystem) = 0;
virtual bool OpenDRMSystem(const char *licenseURL, const AP4_DataBuffer &serverCertificate, const uint8_t config) = 0;
virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t *defaultkeyid, bool skipSessionMessage) = 0;
virtual void DestroySingleSampleDecrypter(AP4_CencSingleSampleDecrypter* decrypter) = 0;

virtual void GetCapabilities(AP4_CencSingleSampleDecrypter* decrypter, const uint8_t *keyid, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps) = 0;
virtual bool HasLicenseKey(AP4_CencSingleSampleDecrypter* decrypter, const uint8_t *keyid) = 0;
virtual Adaptive_CencSingleSampleDecrypter* CreateSingleSampleDecrypter(
AP4_DataBuffer& pssh,
const char* optionalKeyParameter,
const uint8_t* defaultkeyid,
bool skipSessionMessage) = 0;
virtual void DestroySingleSampleDecrypter(Adaptive_CencSingleSampleDecrypter* decrypter) = 0;

virtual void GetCapabilities(Adaptive_CencSingleSampleDecrypter* decrypter,
const uint8_t* keyid,
uint32_t media,
SSD_DECRYPTER::SSD_CAPS& caps) = 0;
virtual bool HasLicenseKey(Adaptive_CencSingleSampleDecrypter* decrypter,
const uint8_t* keyid) = 0;
virtual bool HasCdmSession() = 0;
virtual std::string GetChallengeB64Data(AP4_CencSingleSampleDecrypter* decrypter) = 0;
virtual std::string GetChallengeB64Data(Adaptive_CencSingleSampleDecrypter* decrypter) = 0;

virtual bool OpenVideoDecoder(AP4_CencSingleSampleDecrypter* decrypter, const SSD_VIDEOINITDATA *initData) = 0;
virtual bool OpenVideoDecoder(Adaptive_CencSingleSampleDecrypter* decrypter,
const SSD_VIDEOINITDATA* initData) = 0;
virtual SSD_DECODE_RETVAL DecodeVideo(void* instance, SSD_SAMPLE *sample, SSD_PICTURE *picture) = 0;
virtual void ResetVideo() = 0;
};
Expand Down
24 changes: 24 additions & 0 deletions src/common/AdaptiveDecrypter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <bento4/Ap4.h>

enum class ENCRYPTION_SCHEME
{
NONE,
CENC,
CBCS
};

class Adaptive_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
{
public:

Adaptive_CencSingleSampleDecrypter() : AP4_CencSingleSampleDecrypter(0) {};

void SetCrypto(AP4_UI08 cryptBlocks, AP4_UI08 skipBlocks)
{
m_CryptBlocks = cryptBlocks;
m_SkipBlocks = skipBlocks;
};
virtual void SetEncryptionScheme(ENCRYPTION_SCHEME encryptionScheme){};
AP4_UI08 m_CryptBlocks = 0;
AP4_UI08 m_SkipBlocks = 0;
};
129 changes: 82 additions & 47 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,7 @@ class ATTR_DLL_LOCAL FragmentedSampleReader : public SampleReader, public AP4_Li
AP4_Movie* movie,
AP4_Track* track,
AP4_UI32 streamId,
AP4_CencSingleSampleDecrypter* ssd,
Adaptive_CencSingleSampleDecrypter* ssd,
const SSD::SSD_DECRYPTER::SSD_CAPS& dcaps)
: AP4_LinearReader(*movie, input),
m_track(track),
Expand Down Expand Up @@ -1492,6 +1492,19 @@ class ATTR_DLL_LOCAL FragmentedSampleReader : public SampleReader, public AP4_Li
AP4_CencSampleDecrypter::Create(sample_table, algorithm_id, 0, 0, 0, reset_iv,
m_singleSampleDecryptor, m_decrypter)))
return result;

// Inform decrypter of pattern decryption (CBCS)
if (m_protectedDesc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CENC)
{
m_singleSampleDecryptor->SetEncryptionScheme(ENCRYPTION_SCHEME::CENC);
m_singleSampleDecryptor->SetCrypto(0, 0);
}
else if (m_protectedDesc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_CBCS)
{
m_singleSampleDecryptor->SetEncryptionScheme(ENCRYPTION_SCHEME::CBCS);
m_singleSampleDecryptor->SetCrypto(sample_table->GetCryptByteBlock(),
sample_table->GetSkipByteBlock());
}
}
}
SUCCESS:
Expand Down Expand Up @@ -1575,7 +1588,7 @@ class ATTR_DLL_LOCAL FragmentedSampleReader : public SampleReader, public AP4_Li
const AP4_UI08* m_defaultKey;

AP4_ProtectedSampleDescription* m_protectedDesc;
AP4_CencSingleSampleDecrypter* m_singleSampleDecryptor;
Adaptive_CencSingleSampleDecrypter* m_singleSampleDecryptor;
AP4_CencSampleDecrypter* m_decrypter;
uint64_t m_nextDuration, m_nextTimestamp;
};
Expand Down Expand Up @@ -2558,21 +2571,43 @@ bool Session::InitializeDRM()

unsigned char key_system[16];
AP4_ParseHex(strkey.c_str(), key_system, 16);
uint32_t currentSessionTypes = 0;

for (size_t ses(1); ses < cdm_sessions_.size(); ++ses)
{
AP4_DataBuffer init_data;
const char* optionalKeyParameter(nullptr);
adaptive::AdaptiveTree::Period::PSSH sessionPsshset =
adaptiveTree_->current_period_->psshSets_[ses];
uint32_t sessionType = 0;

if (sessionPsshset.media_ > 0)
{
sessionType = sessionPsshset.media_;
}
else
{
switch (sessionPsshset.adaptation_set_->type_)
{
case adaptive::AdaptiveTree::VIDEO:
sessionType = adaptive::AdaptiveTree::Period::PSSH::MEDIA_VIDEO;
break;
case adaptive::AdaptiveTree::AUDIO:
sessionType = adaptive::AdaptiveTree::Period::PSSH::MEDIA_AUDIO;
break;
default:
break;
}
}

if (adaptiveTree_->current_period_->psshSets_[ses].pssh_ == "FILE")
if (sessionPsshset.pssh_ == "FILE")
{
kodi::Log(ADDON_LOG_DEBUG, "Searching PSSH data in FILE");

if (license_data_.empty())
{
Session::STREAM stream(*adaptiveTree_,
adaptiveTree_->current_period_->psshSets_[ses].adaptation_set_,
media_headers_, representationChooser_, play_timeshift_buffer_, 0, false);
Session::STREAM stream(*adaptiveTree_, sessionPsshset.adaptation_set_, media_headers_,
representationChooser_, play_timeshift_buffer_, 0, false);

stream.enabled = true;
stream.stream_.start_stream();
Expand All @@ -2593,11 +2628,13 @@ bool Session::InitializeDRM()
if (memcmp(pssh[i].GetSystemId(), key_system, 16) == 0)
{
init_data.AppendData(pssh[i].GetData().GetData(), pssh[i].GetData().GetDataSize());
if (adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.empty())
if (sessionPsshset.defaultKID_.empty())
{
if (pssh[i].GetKid(0))
adaptiveTree_->current_period_->psshSets_[ses].defaultKID_ =
std::string((const char*)pssh[i].GetKid(0), 16);
{
sessionPsshset.defaultKID_ =
std::string(reinterpret_cast<const char*>(pssh[i].GetKid(0)), 16);
}
else if (AP4_Track* track = movie->GetTrack(TIDC[stream.stream_.get_type()]))
{
AP4_ProtectedSampleDescription* m_protectedDesc =
Expand All @@ -2609,16 +2646,20 @@ bool Session::InitializeDRM()
AP4_TencAtom* tenc(
AP4_DYNAMIC_CAST(AP4_TencAtom, schi->GetChild(AP4_ATOM_TYPE_TENC, 0)));
if (tenc)
adaptiveTree_->current_period_->psshSets_[ses].defaultKID_ =
std::string((const char*)tenc->GetDefaultKid(), 16);
{
sessionPsshset.defaultKID_ =
std::string(reinterpret_cast<const char*>(tenc->GetDefaultKid()), 16);
}
else
{
AP4_PiffTrackEncryptionAtom* piff(
AP4_DYNAMIC_CAST(AP4_PiffTrackEncryptionAtom,
schi->GetChild(AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 0)));
if (piff)
adaptiveTree_->current_period_->psshSets_[ses].defaultKID_ =
std::string((const char*)piff->GetDefaultKid(), 16);
{
sessionPsshset.defaultKID_ =
std::string(reinterpret_cast<const char*>(piff->GetDefaultKid()), 16);
}
}
}
}
Expand All @@ -2635,10 +2676,9 @@ bool Session::InitializeDRM()
}
stream.disable();
}
else if (!adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.empty())
else if (!sessionPsshset.defaultKID_.empty())
{
init_data.SetData(
(AP4_Byte*)adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.data(), 16);
init_data.SetData(reinterpret_cast<AP4_Byte*>(sessionPsshset.defaultKID_.data()), 16);

uint8_t ld[1024];
unsigned int ld_size(1014);
Expand Down Expand Up @@ -2666,71 +2706,66 @@ bool Session::InitializeDRM()
if (license_data_.empty())
license_data_ = "e0tJRH0="; // {KID}
std::vector<uint8_t> init_data_v;
create_ism_license(adaptiveTree_->current_period_->psshSets_[ses].defaultKID_,
license_data_, init_data_v);
create_ism_license(sessionPsshset.defaultKID_, license_data_, init_data_v);
init_data.SetData(init_data_v.data(), init_data_v.size());
}
else
{
init_data.SetData(reinterpret_cast<const uint8_t*>(
adaptiveTree_->current_period_->psshSets_[ses].pssh_.data()),
adaptiveTree_->current_period_->psshSets_[ses].pssh_.size());
init_data.SetData(reinterpret_cast<const uint8_t*>(sessionPsshset.pssh_.data()),
sessionPsshset.pssh_.size());
optionalKeyParameter = license_data_.empty() ? nullptr : license_data_.c_str();
}
}
else
{
init_data.SetBufferSize(1024);
unsigned int init_data_size(1024);
b64_decode(adaptiveTree_->current_period_->psshSets_[ses].pssh_.data(),
adaptiveTree_->current_period_->psshSets_[ses].pssh_.size(),
init_data.UseData(), init_data_size);
b64_decode(sessionPsshset.pssh_.data(), sessionPsshset.pssh_.size(), init_data.UseData(),
init_data_size);
init_data.SetDataSize(init_data_size);
}
}

CDMSESSION& session(cdm_sessions_[ses]);
const char* defkid = adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.empty()
? nullptr
: adaptiveTree_->current_period_->psshSets_[ses].defaultKID_.data();
const char* defkid =
sessionPsshset.defaultKID_.empty() ? nullptr : sessionPsshset.defaultKID_.data();

if (decrypter_ && defkid)
{
char hexkid[36];
AP4_FormatHex(reinterpret_cast<const AP4_UI08*>(defkid), 16, hexkid), hexkid[32] = 0;
kodi::Log(ADDON_LOG_DEBUG, "Initializing stream with KID: %s", hexkid);

for (unsigned int i(1); i < ses; ++i)
if (decrypter_->HasLicenseKey(cdm_sessions_[i].single_sample_decryptor_,
(const uint8_t*)defkid))
// use shared ssd session if we already have 1 of the same stream type
if (currentSessionTypes & sessionType)
{
for (unsigned int i(1); i < ses; ++i)
{
session.single_sample_decryptor_ = cdm_sessions_[i].single_sample_decryptor_;
session.shared_single_sample_decryptor_ = true;
break;
if (decrypter_->HasLicenseKey(cdm_sessions_[i].single_sample_decryptor_,
reinterpret_cast<const uint8_t*>(defkid)))
{
session.single_sample_decryptor_ = cdm_sessions_[i].single_sample_decryptor_;
session.shared_single_sample_decryptor_ = true;
break;
}
}
}
}
else if (!defkid)
else if (!defkid && !session.single_sample_decryptor_)
{
for (unsigned int i(1); i < ses; ++i)
if (adaptiveTree_->current_period_->psshSets_[ses].pssh_ ==
adaptiveTree_->current_period_->psshSets_[i].pssh_)
{
session.single_sample_decryptor_ = cdm_sessions_[i].single_sample_decryptor_;
session.shared_single_sample_decryptor_ = true;
break;
}
if (!session.single_sample_decryptor_)
kodi::Log(ADDON_LOG_WARNING, "Initializing stream with unknown KID!");
}

currentSessionTypes |= sessionType;

if (decrypter_ && init_data.GetDataSize() >= 4 &&
(session.single_sample_decryptor_ ||
(session.single_sample_decryptor_ = decrypter_->CreateSingleSampleDecrypter(
init_data, optionalKeyParameter, (const uint8_t*)defkid, false)) != 0))
{

decrypter_->GetCapabilities(session.single_sample_decryptor_, (const uint8_t*)defkid,
adaptiveTree_->current_period_->psshSets_[ses].media_,
decrypter_->GetCapabilities(session.single_sample_decryptor_,
reinterpret_cast<const uint8_t*>(defkid), sessionPsshset.media_,
session.decrypter_caps_);

if (session.decrypter_caps_.flags & SSD::SSD_DECRYPTER::SSD_CAPS::SSD_INVALID)
Expand Down Expand Up @@ -3296,7 +3331,7 @@ const AP4_UI08* Session::GetDefaultKeyId(const uint16_t index) const
return default_key;
}

AP4_CencSingleSampleDecrypter* Session::GetSingleSampleDecrypter(std::string sessionId)
Adaptive_CencSingleSampleDecrypter* Session::GetSingleSampleDecrypter(std::string sessionId)
{
for (std::vector<CDMSESSION>::iterator b(cdm_sessions_.begin() + 1), e(cdm_sessions_.end());
b != e; ++b)
Expand Down Expand Up @@ -4151,7 +4186,7 @@ bool CVideoCodecAdaptive::Open(const kodi::addon::VideoCodecInitdata& initData)
m_name += ".decoder";

std::string sessionId(initData.GetCryptoSession().GetSessionId());
AP4_CencSingleSampleDecrypter* ssd(m_session->GetSingleSampleDecrypter(sessionId));
Adaptive_CencSingleSampleDecrypter* ssd(m_session->GetSingleSampleDecrypter(sessionId));

return m_session->GetDecrypter()->OpenVideoDecoder(
ssd, reinterpret_cast<const SSD::SSD_VIDEOINITDATA*>(initData.GetCStructure()));
Expand Down
10 changes: 7 additions & 3 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <kodi/addon-instance/Inputstream.h>
#include <kodi/tools/DllHelper.h>

#include "common/AdaptiveDecrypter.h"
#include "common/AdaptiveTree.h"
#include "common/AdaptiveStream.h"
#include "common/RepresentationChooser.h"
Expand Down Expand Up @@ -164,9 +165,12 @@ class ATTR_DLL_LOCAL Session : public adaptive::AdaptiveStreamObserver
unsigned int GetStreamCount() const { return streams_.size(); };
const char *GetCDMSession(int nSet) { return cdm_sessions_[nSet].cdm_session_str_; };;
uint8_t GetMediaTypeMask() const { return media_type_mask_; };
AP4_CencSingleSampleDecrypter * GetSingleSampleDecryptor(unsigned int nIndex)const{ return cdm_sessions_[nIndex].single_sample_decryptor_; };
Adaptive_CencSingleSampleDecrypter* GetSingleSampleDecryptor(unsigned int nIndex) const
{
return cdm_sessions_[nIndex].single_sample_decryptor_;
};
SSD::SSD_DECRYPTER *GetDecrypter() { return decrypter_; };
AP4_CencSingleSampleDecrypter *GetSingleSampleDecrypter(std::string sessionId);
Adaptive_CencSingleSampleDecrypter* GetSingleSampleDecrypter(std::string sessionId);
const SSD::SSD_DECRYPTER::SSD_CAPS &GetDecrypterCaps(unsigned int nIndex) const{ return cdm_sessions_[nIndex].decrypter_caps_; };
uint64_t GetTotalTimeMs()const { return adaptiveTree_->overallSeconds_ * 1000; };
uint64_t GetElapsedTimeMs()const { return elapsed_time_ / 1000; };
Expand Down Expand Up @@ -219,7 +223,7 @@ class ATTR_DLL_LOCAL Session : public adaptive::AdaptiveStreamObserver
struct CDMSESSION
{
SSD::SSD_DECRYPTER::SSD_CAPS decrypter_caps_;
AP4_CencSingleSampleDecrypter *single_sample_decryptor_;
Adaptive_CencSingleSampleDecrypter* single_sample_decryptor_;
const char* cdm_session_str_ = nullptr;
bool shared_single_sample_decryptor_ = false;
};
Expand Down
Loading

0 comments on commit 9c1e139

Please sign in to comment.