9#include <openssl/aes.h>
10#include <openssl/evp.h>
17#define LOC QString("HLSRecstream[%1]: ").arg(m_inputId)
23 m_m3u8Url(
std::move(m3u8_url)),
24 m_segmentBaseUrl(
std::move(segment_base_url))
26 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"ctor");
31 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"dtor");
33 AESKeyMap::iterator Iaes;
35 for (Iaes = m_aesKeys.begin(); Iaes != m_aesKeys.end(); ++Iaes)
42 return QString(
"%1 bitrate %2").arg(
Id()).arg(
Bitrate());
51#ifdef HLS_USE_MYTHDOWNLOADMANAGER
52 bool ret = HLSReader::DownloadURL(keypath, &key);
61 LOG(VB_RECORD, LOG_ERR,
LOC +
62 QString(
"The AES key loaded doesn't have the right size (%1)")
67 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to download AES key: " +
74 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Downloaded AES key");
82int HLSRecStream::Decrypt(
unsigned char *ciphertext,
int ciphertext_len,
unsigned char *key,
83 unsigned char *iv,
unsigned char *plaintext)
const
87 int plaintext_len = 0;
90 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
93 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to create and initialize cipher context");
104 if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
106 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to initialize decryption operation");
114 if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
116 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to decrypt");
125 if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
127 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to finalize decryption" +
128 QString(
" len:%1").arg(len) +
129 QString(
" plaintext_len:%1").arg(plaintext_len) );
132 plaintext_len += len;
135 EVP_CIPHER_CTX_free(ctx);
137 return plaintext_len;
141 const QByteArray& IV,
const QString& keypath,
142 QByteArray& data, int64_t sequence)
144 LOG(VB_RECORD, LOG_INFO,
LOC +
"DecodeData:" +
145 QString(
" IV.size():%1").arg(IV.size()) +
146 QString(
" keypath:%1..%2").arg(keypath.left(20),keypath.right(20)) +
147 QString(
" sequence:%1").arg(sequence));
149 AESKeyMap::iterator Ikey = m_aesKeys.find(keypath);
150 if (Ikey == m_aesKeys.end())
153 DownloadKey(downloader, keypath, key);
154 Ikey = m_aesKeys.insert(keypath, key);
155 if (Ikey == m_aesKeys.end())
157 LOG(VB_RECORD, LOG_ERR,
LOC +
158 "DecodeData: Unable to add AES key to map");
164 std::array<uint8_t,AES_BLOCK_SIZE> iv {};
165 auto *decrypted_data =
new uint8_t[data.size()];
176 iv[15] = sequence & 0xff;
177 iv[14] = (sequence >> 8) & 0xff;
178 iv[13] = (sequence >> 16) & 0xff;
179 iv[12] = (sequence >> 24) & 0xff;
183 std::copy(IV.cbegin(), IV.cend(), iv.data());
186 int aeslen = data.size() & ~0xf;
187 if (aeslen != data.size())
189 LOG(VB_RECORD, LOG_WARNING,
LOC +
190 QString(
"Data size %1 not multiple of 16 bytes, rounding to %2")
191 .arg(data.size()).arg(aeslen));
194 int plaintext_len = Decrypt((
unsigned char*)data.constData(), aeslen, (*Ikey)->key.data(),
195 iv.data(), decrypted_data);
197 LOG(VB_RECORD, LOG_INFO,
LOC +
198 QString(
"Segment data.size()):%1 plaintext_len:%2")
199 .arg(data.size()).arg(plaintext_len));
201 data = QByteArray(
reinterpret_cast<char*
>(decrypted_data), plaintext_len);
202 delete[] decrypted_data;
220 QMutexLocker lock(&
m_lock);
static constexpr uint8_t AES128_KEY_SIZE
hls_aes_key_st HLS_AES_KEY
std::chrono::seconds Duration(void) const
bool operator>(const HLSRecStream &b) const
std::chrono::seconds m_duration
QString toString(void) const
uint64_t Bitrate(void) const
HLSRecStream(int inputId, int seq, uint64_t bitrate, QString m3u8_url, QString segment_base_url)
bool operator<(const HLSRecStream &b) const
QQueue< int64_t > m_bandwidthSegs
uint64_t AverageBandwidth(void) const
QString ErrorString(void) const
bool DownloadURL(const QUrl &url, QByteArray *buffer, std::chrono::seconds timeout=30s, uint redirs=0, qint64 maxsize=0, QString *final_url=nullptr)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
std::array< uint8_t, AES128_KEY_SIZE > key