10#include <openssl/aes.h>
11#include <openssl/evp.h>
14#include <QMutexLocker>
18#ifdef HLS_USE_MYTHDOWNLOADMANAGER
22#define LOC QString("HLSRecstream[%1]: ").arg(m_inputId)
28 m_m3u8Url(
std::move(m3u8_url)),
29 m_segmentBaseUrl(
std::move(segment_base_url))
31 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"ctor");
36 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"dtor");
38 AESKeyMap::iterator Iaes;
40 for (Iaes = m_aesKeys.begin(); Iaes != m_aesKeys.end(); ++Iaes)
47 return QString(
"%1 bitrate %2").arg(
Id()).arg(
Bitrate());
56#ifdef HLS_USE_MYTHDOWNLOADMANAGER
57 bool ret = HLSReader::DownloadURL(keypath, &key);
66 LOG(VB_RECORD, LOG_ERR,
LOC +
67 QString(
"The AES key loaded doesn't have the right size (%1)")
72 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to download AES key: " +
79 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Downloaded AES key");
87int HLSRecStream::Decrypt(
unsigned char *ciphertext,
int ciphertext_len,
unsigned char *key,
88 unsigned char *iv,
unsigned char *plaintext)
const
92 int plaintext_len = 0;
95 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
98 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to create and initialize cipher context");
109 if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
111 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to initialize decryption operation");
119 if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
121 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to decrypt");
130 if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
132 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to finalize decryption" +
133 QString(
" len:%1").arg(len) +
134 QString(
" plaintext_len:%1").arg(plaintext_len) );
137 plaintext_len += len;
140 EVP_CIPHER_CTX_free(ctx);
142 return plaintext_len;
146 const QByteArray& IV,
const QString& keypath,
147 QByteArray& data, int64_t sequence)
149 LOG(VB_RECORD, LOG_INFO,
LOC +
"DecodeData:" +
150 QString(
" IV.size():%1").arg(IV.size()) +
151 QString(
" keypath:%1..%2").arg(keypath.left(20),keypath.right(20)) +
152 QString(
" sequence:%1").arg(sequence));
154 AESKeyMap::iterator Ikey = m_aesKeys.find(keypath);
155 if (Ikey == m_aesKeys.end())
158 DownloadKey(downloader, keypath, key);
159 Ikey = m_aesKeys.insert(keypath, key);
160 if (Ikey == m_aesKeys.end())
162 LOG(VB_RECORD, LOG_ERR,
LOC +
163 "DecodeData: Unable to add AES key to map");
169 std::array<uint8_t,AES_BLOCK_SIZE> iv {};
170 auto *decrypted_data =
new uint8_t[data.size()];
181 iv[15] = sequence & 0xff;
182 iv[14] = (sequence >> 8) & 0xff;
183 iv[13] = (sequence >> 16) & 0xff;
184 iv[12] = (sequence >> 24) & 0xff;
188 std::copy(IV.cbegin(), IV.cend(), iv.data());
191 int aeslen = data.size() & ~0xf;
192 if (aeslen != data.size())
194 LOG(VB_RECORD, LOG_WARNING,
LOC +
195 QString(
"Data size %1 not multiple of 16 bytes, rounding to %2")
196 .arg(data.size()).arg(aeslen));
199 int plaintext_len = Decrypt((
unsigned char*)data.constData(), aeslen, (*Ikey)->key.data(),
200 iv.data(), decrypted_data);
202 LOG(VB_RECORD, LOG_INFO,
LOC +
203 QString(
"Segment data.size()):%1 plaintext_len:%2")
204 .arg(data.size()).arg(plaintext_len));
206 data = QByteArray(
reinterpret_cast<char*
>(decrypted_data), plaintext_len);
207 delete[] decrypted_data;
225 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